8

I'm Trying To Create Category Chooser in etc/system.xml

Is That Possible to Create Category Chooser in system.xml ?

enter image description here

Choose Like This

13
  • Hey there have you solved your problem i am doing same thing i have added in system.cml but value is not saving
    – User 69
    May 19, 2020 at 9:10
  • no.............. May 19, 2020 at 17:33
  • @User69, you have to name the file system.xml not system.cml
    – Black
    Oct 6, 2020 at 8:05
  • @Black if other way of multiselect available then it will useful for you? Or you want this multiselect only? Oct 6, 2020 at 10:21
  • @RohanHapani, I want this multiselect from the screenshot only, I already have a normal one thx to the answer of VDC.
    – Black
    Oct 6, 2020 at 10:22

4 Answers 4

6
+50

You can follow this below steps to add multi select dropdown using chosen library :

Add this below code inside your system.xml :

app/code/Vendor/Module/etc/adminhtml/system.xml

<!--
/**
 * Created By : Rohan Hapani
 */
-->
<field id="category_multiselect" translate="label" type="multiselect" showInDefault="1" showInWebsite="1" showInStore="1" sortOrder="10">
    <label>Category Multi Select Dropdown</label>
    <source_model>Vendor\Module\Model\Source\Category</source_model>
    <frontend_model>Vendor\Module\Block\Adminhtml\MultiSelect</frontend_model>
    <can_be_empty>1</can_be_empty>
</field>

Then, create frontend model file MultiSelect.php to display multi select dropdown :

app/code/Vendor/Module/Block/Adminhtml/MultiSelect.php

<?php
/**
 * Created By : Rohan Hapani
 */
namespace Vendor\Module\Block\Adminhtml;

class MultiSelect extends \Magento\Config\Block\System\Config\Form\Field
{

    /**
     * Retrieve Element HTML fragment
     *
     * @param AbstractElement $element
     * @return string
     */
    protected function _getElementHtml(\Magento\Framework\Data\Form\Element\AbstractElement $element)
    {
        $script = " <script>
                require([
                    'jquery',
                    'chosen'
                ], function ($, chosen) {
                    $('#" . $element->getId() . "').chosen({
                        width: '100%',
                        placeholder_text: '" . __('Select Options') . "'
                    });
                    $('#" . $element->getId() . "_inherit').change(function() {

                        $('#" . $element->getId() . "').prop('disabled', $(this).is(':checked'));
                          $('#" . $element->getId() . "').trigger('chosen:updated');
                    });
                })
            </script>";
        return parent::_getElementHtml($element) . $script;
    }
}

Create Category.php source model file

app/code/Vendor/Module/Model/Source/

<?php
/**
 * Created By : Rohan Hapani
 */
namespace Vendor\Module\Model\Source;

use Magento\Framework\Option\ArrayInterface;

class Category implements ArrayInterface
{

    protected $collectionFactory;

    /**
     * @param EavConfig $eavConfig
     */
    public function __construct(
        \Magento\Catalog\Model\ResourceModel\Category\CollectionFactory $collectionFactory
    ) {
        $this->collectionFactory = $collectionFactory;
    }

    public function toOptionArray()
    {
        $optionArray = [];
        $arr = $this->collectionFactory->create()->addAttributeToSelect('*');
        foreach ($arr as $key => $value) {
                $optionArray[] = [
                    'value' => $value->getId(),
                    'label' => $value->getName(),
                ];
        }
        return $optionArray;
    }
}

Create adminhtml_system_config_edit.xml to add CSS

app/code/Vendor/Module/view/adminhtml/layout/adminhtml_system_config_edit.xml

<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
 * Created By : Rohan Hapani
 */
-->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <head>
        <css src="Vendor_Module::css/chosen/chosen.css"/>
    </head>
</page>

Create app/code/Vendor/Module/view/adminhtml/requirejs-config.js file for add js

var config = {
    map: {
        '*': {
            chosen: 'Vendor_Module/js/chosen/chosen.jquery'
        }
    }
};

To Download chosen zip : Click here

Deploy and clean cache.

Output :

enter image description here

Github : Click Here

16
  • Thank you, I will try it out tomorrow and report back :) Can you add a screenshot with the result?
    – Black
    Oct 6, 2020 at 15:42
  • I updated screenshot. Please check it. Oct 7, 2020 at 5:14
  • 2
    I added github link. You can download full module now :) Oct 7, 2020 at 10:21
  • 1
    I give you the award, even though it does not met the requirements, but you gave the most helpful solution. Thx!
    – Black
    Oct 12, 2020 at 10:25
  • 1
    @Black Happy to help !! Happy Coding :) I will upload solution if i will do same solution. Oct 12, 2020 at 10:30
3

You need to update system.xml file with below category filed

<field id="categories" translate="label" type="multiselect" sortOrder="12" showInDefault="1" showInWebsite="1" showInStore="1">
    <label>Category</label>
    <source_model>Namespace\Yourmodule\Model\Config\Source\Category</source_model>
</field>

And now create this file Category.php

Path: app/code/Namespace/Yourmodule/Model/Config/Source/

And add this code

<?php

namespace Namespace\Yourmodule\Model\Config\Source;

use Magento\Framework\Option\ArrayInterface;

class Category implements ArrayInterface
{
    protected $_categoryFactory;
    protected $_categoryCollectionFactory;

    public function __construct(
        \Magento\Catalog\Model\CategoryFactory $categoryFactory,
        \Magento\Catalog\Model\ResourceModel\Category\CollectionFactory $categoryCollectionFactory
    )
    {
        $this->_categoryFactory = $categoryFactory;
        $this->_categoryCollectionFactory = $categoryCollectionFactory;
    }

    public function getCategoryCollection($isActive = true, $level = false, $sortBy = false, $pageSize = false)
    {
        $collection = $this->_categoryCollectionFactory->create();
        $collection->addAttributeToSelect('*');

        // select only active categories
        if ($isActive) {
            $collection->addIsActiveFilter();
        }

        // select categories of certain level
        if ($level) {
            $collection->addLevelFilter($level);
        }

        // sort categories by some value
        if ($sortBy) {
            $collection->addOrderField($sortBy);
        }

        // select certain number of categories
        if ($pageSize) {
            $collection->setPageSize($pageSize);
        }

        return $collection;
    }

    public function toOptionArray()
    {
        $arr = $this->_toArray();
        $ret = [];

        foreach ($arr as $key => $value)
        {
            $ret[] = [
                'value' => $key,
                'label' => $value
            ];
        }

        return $ret;
    }

    private function _toArray()
    {
        $categories = $this->getCategoryCollection(true, false, false, false);

        $catagoryList = array();
        foreach ($categories as $category)
        {
            $catagoryList[$category->getEntityId()] = __($this->_getParentName($category->getPath()) . $category->getName());
        }

        return $catagoryList;
    }

    private function _getParentName($path = '')
    {
        $parentName = '';
        $rootCats = array(1,2);

        $catTree = explode("/", $path);
        // Deleting category itself
        array_pop($catTree);

        if($catTree && (count($catTree) > count($rootCats)))
        {
            foreach ($catTree as $catId)
            {
                if(!in_array($catId, $rootCats))
                {
                    $category = $this->_categoryFactory->create()->load($catId);
                    $categoryName = $category->getName();
                    $parentName .= $categoryName . ' -> ';
                }
            }
        }

        return $parentName;
    }
}

Result:

enter image description here

Hope this will help you!

6
  • I need in magento 2 Mar 1, 2019 at 11:47
  • OK then in your question file path should be etc/adminhtml/system.xml
    – VDC
    Mar 1, 2019 at 11:48
  • OK I will update my answer
    – VDC
    Mar 1, 2019 at 11:48
  • check my updated answer
    – VDC
    Mar 1, 2019 at 11:55
  • check updated question Mar 1, 2019 at 12:21
2

You can try this way ..

First you update below field in system.xml

 <field id="categories" translate="label" type="multiselect" sortOrder="60" showInDefault="1" showInWebsite="1" showInStore="1" >
    <label>Categories</label>
    <source_model>Vendor\Module\Model\Source\Categories</source_model>
</field>

After create file Categories.php

app/code/Vendor/Module/Model/Source/Categories.php

<?php


namespace Vendor\Module\Model\Source;

use Magento\Framework\Option\ArrayInterface;
use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory;


class Categories implements ArrayInterface
{
    const ALL_CATEGORIES = 0;
    const SYSTEM_CATEGORY_ID = 1;
    const ROOT_LEVEL = 1;

    /**
     * @var CollectionFactory
     */
    private $collectionFactory;

    public function __construct(
        CollectionFactory $collectionFactory
    ) {
        $this->collectionFactory = $collectionFactory;
    }

    /**
     * Options getter
     *
     * @return array
     */
    public function toOptionArray()
    {
        $optionArray = [];
        $arr = $this->toArray();
        foreach ($arr as $value => $label) {
            $optionArray[] = [
                'value' => $value,
                'label' => $label
            ];
        }
        return $optionArray;
    }

    /**
     * Get options in "key-value" format
     *
     * @return array
     */
    public function toArray()
    {
        return $this->getChildren(self::SYSTEM_CATEGORY_ID, self::ROOT_LEVEL);
    }

    /**
     * @param $parentCategoryId
     * @param $level
     * @return array
     */
    private function getChildren($parentCategoryId, $level)
    {
        $options[self::ALL_CATEGORIES] = __('All Categories');
        $collection = $this->collectionFactory->create();
        $collection->addAttributeToSelect('name');
        $collection->addAttributeToFilter('level', $level);
        $collection->addAttributeToFilter('parent_id', $parentCategoryId);
        $collection->addAttributeToFilter('is_active', 1);
        $collection->setOrder('position', 'asc');

        foreach ($collection as $category) {
            if ($category->getLevel() > self::ROOT_LEVEL) {
                $options[$category->getId()] =
                    str_repeat(". ", max(0, ($category->getLevel() - 1) * 3)) . $category->getName();
            }
            if ($category->hasChildren()) {
                $options = array_replace($options, $this->getChildren($category->getId(), $category->getLevel() + 1));
            }
        }

        return $options;
    }
}

And Result: enter image description here

4
  • Thanks, but this still not looks like in the screenshot of the question.
    – Black
    Oct 9, 2020 at 13:12
  • @Black yes but working like charm and this type possible in admin menu and my code is standard code, this code is working all magento version Oct 9, 2020 at 13:16
  • @Black this solution is helpful you ? Oct 10, 2020 at 4:56
  • it is a start, but it does not fulfill the requirements
    – Black
    Oct 12, 2020 at 7:54
1

Check this doc.

https://devdocs.magento.com/guides/v2.4/ui_comp_guide/components/ui-secondary-uiselect.html

May be help for you.

1
  • Thx, but I expect a full answer with working code.
    – Black
    Oct 6, 2020 at 13:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.