4

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

  • 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 at 9:10
  • no.............. – Rk Rathod May 19 at 17:33
  • @User69, you have to name the file system.xml not system.cml – Black Oct 6 at 8:05
  • @Black if other way of multiselect available then it will useful for you? Or you want this multiselect only? – Rohan Hapani Oct 6 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 at 10:22
1

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!

| improve this answer | |
  • I need in magento 2 – Rk Rathod Mar 1 '19 at 11:47
  • OK then in your question file path should be etc/adminhtml/system.xml – VDC Mar 1 '19 at 11:48
  • OK I will update my answer – VDC Mar 1 '19 at 11:48
  • check my updated answer – VDC Mar 1 '19 at 11:55
  • check updated question – Rk Rathod Mar 1 '19 at 12:21
1
+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

| improve this answer | |
  • Thank you, I will try it out tomorrow and report back :) Can you add a screenshot with the result? – Black Oct 6 at 15:42
  • I updated screenshot. Please check it. – Rohan Hapani Oct 7 at 5:14
  • 1
    I added github link. You can download full module now :) – Rohan Hapani Oct 7 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 at 10:25
  • 1
    @Black Happy to help !! Happy Coding :) I will upload solution if i will do same solution. – Rohan Hapani Oct 12 at 10:30
1

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

| improve this answer | |
  • Thanks, but this still not looks like in the screenshot of the question. – Black Oct 9 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 – Rakesh Donga Oct 9 at 13:16
  • @Black this solution is helpful you ? – Rakesh Donga Oct 10 at 4:56
  • it is a start, but it does not fulfill the requirements – Black Oct 12 at 7:54
0

Check this doc.

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

May be help for you.

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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