Magento 2 multi-select in system configuration

This article is about Magento 2 multi-select in system configuration . Getting all available categories and display them in a system config multi-select field list can be tricky sometimes. In this tutorial i will try to explain it swiftly and in a simple way that how can you do it in magento 2. There can be various ways of doing it.We will discuss one or two efficient ways of doing so here.

Let’s start our tutorial, here we will discuss different ways of doing it. I hope you are familiar with magento 2 and if yes, you will be able to move along nicely.

First of all modify

QaisarSatti/HelloWorld/etc/adminhtml/system.xml

and paste the following code

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
    <system>
        <section id="module_section" translate="label" type="text"
                 sortOrder="100" showInDefault="1" showInWebsite="1" showInStore="1">
            <label>Module</label>
            <tab>tab_name</tab>
            <resource>QaisarSatti_HelloWorld::config</resource>
            <group id="module_section_page" translate="label" type="text"
                   sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1">
                <label>Module page settings</label>
                <field id="latest_category" translate="label" type="multiselect" sortOrder="12" showInDefault="1" showInWebsite="1" showInStore="1">
                    <label>New Product Category</label>
                    <source_model>QaisarSatti\HelloWorld\Model\Config\Source\Categorylist</source_model>
                </field>
            </group>
        </section>
    </system>
</config>

Now

QaisarSatti/HelloWorld/etc/acl.xml

add Acl

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/acl.xsd">
    <acl>
        <resources>
            <resource id="Magento_Backend::admin">
                <resource id="Magento_Backend::stores">
                    <resource id="Magento_Backend::stores_settings">
                        <resource id="Magento_Config::config">
                            <resource id="QaisarSatti_HelloWorld::config" title="Module Section" />
                        </resource>
                    </resource>
                </resource>
            </resource>
        </resources>
    </acl>
</config>

Now add

QaisarSatti/HelloWorld/Model/Config/Source/Categorylist.php

<?php

namespace QaisarSatti\HelloWorld\Model\Config\Source;

use Magento\Framework\Option\ArrayInterface;

class Categorylist 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;
    }
}

Furthermore, let’s discuss another way of doing so. Here In system.xml file field for multi select of category is like:

<group id="helloworld_setting" translate="label" type="text" delault="1" sortOrder="3" showInDefault="1" showInWebsite="1" showInStore="1">
    <label>Setting</label>
    <field id="cateogry" translate="label" type="multiselect" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
        <label>Select Category</label>
        <source_model>QaisarSatti\HelloWorld\Model\Config\Source\Categorylist</source_model>
    </field>
</group>

Now create a file Categorylist.php in QaisarSatti\HelloWorld\Model\Config\Source

namespace QaisarSatti\HelloWorld\Model\Config\Source;

use Magento\Framework\Option\ArrayInterface;

class Categorylist implements ArrayInterface
{
    protected $_categoryHelper;

    public function __construct(\Magento\Catalog\Helper\Category $catalogCategory)
    {
        $this->_categoryHelper = $catalogCategory;
    }

    /*
     * Return categories helper
     */


    public function getStoreCategories($sorted = false, $asCollection = false, $toLoad = true)
    {
        return $this->_categoryHelper->getStoreCategories($sorted , $asCollection, $toLoad);
    }

    /*  
     * Option getter
     * @return array
     */

    public function toOptionArray()
    {


        $arr = $this->toArray();
        $ret = [];

        foreach ($arr as $key => $value)
        {

            $ret[] = [
                'value' => $key,
                'label' => $value
            ];
        }

        return $ret;
    }

    /*
     * Get options in "key-value" format
     * @return array
     */

    public function toArray()
    {

        $categories = $this->getStoreCategories(true,false,true);

        $catagoryList = array();
        foreach ($categories as $category){

            $catagoryList[$category->getEntityId()] = '__'.($category->getName());
        }

        return $catagoryList;
    }

}

But in this case you’ll get first level only and categories included in menu.

That’s it from this tutorial. I strongly believe there is always room for improvement.So i am open for any suggestion and feed back. Please feel free to leave hat you are thinking in the comments section below. Cheers.

Qaisar Satti

Hi, I'm Qaisar Satti! I've been a developer for over 20 years, and now I love sharing what I've learned through tutorials and guides. Whether you're working with Magento, PrestaShop, or WooCommerce, my goal is to make your development journey a bit easier and more fun. When I'm not coding or writing, you can find me exploring new tech trends and hanging out with the amazing developer community. Thanks for stopping by, and happy coding!

Leave a Reply