8

Magento2 : Create multi select category attribute with custom source. Can anyone give me with example?

1
  • Magento version 2.1.0 Commented Sep 3, 2016 at 5:47

3 Answers 3

21

For a mult select attribute, you can need to add below at your installer:

  • source model: [VendorName]\[ModuleName]\Model\Category\Attribute\Source\Custom.php

  • backend Model [VendorName]\[ModuleName]\Model\Category\Attribute\Backend\Custom.php

  • input_renderer for admin html area [VendorName]\[ModuleName]\Block\Adminhtml\Category\Helper\Custom\Options.php

Install file[app/code/[VendorName]/[ModuleName]/Setup/InstallData.php] an code:

<?php
namespace [VendorName]\[ModuleName]\Setup;

use Magento\Eav\Setup\EavSetup;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\Setup\InstallDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;


class InstallData implements InstallDataInterface
{
    private $eavSetupFactory; 
    /**
     * Init
     *
     * @param EavSetupFactory $eavSetupFactory
     */
    public function __construct(EavSetupFactory $eavSetupFactory)
    {
        $this->eavSetupFactory = $eavSetupFactory;
    }

    /**
     * {@inheritdoc}
     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
     */
    public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {
        /** @var EavSetup $eavSetup */
        $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);
        /**
         * Add attributes to the eav/attribute
         */ 
        $eavSetup->addAttribute(
            \Magento\Catalog\Model\Category::ENTITY,
            'multi_custom_attribute',
                      [
                        'type' => 'text',
                        'label' => 'Custom Attribute Description',
                        'input' => 'multiselect',
                        'required' => false,

                        'source' => '[VendorName]\[ModuleName]\Model\Category\Attribute\Source\Custom',
                        'backend' => '[VendorName]\[ModuleName]\Model\Category\Attribute\Backend\Custom',
                        'input_renderer' => '[VendorName]\[ModuleName]\Block\Adminhtml\Category\Helper\Custom\Options',

                        'sort_order' => 100,
                        'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE,
                        'group' => 'General Information',
                        'is_used_in_grid' => true,
                        'is_visible_in_grid' => false,
                        'is_filterable_in_grid' => true,
            ]
        );


    }
}

Source model:

location: app\code\[VendorName]\[ModuleName]\Model\Category\Attribute\Source\Custom.php

code:

<?php
namespace [VendorName]\[ModuleName]\Model\Category\Attribute\Source;

class Custom extends \Magento\Eav\Model\Entity\Attribute\Source\AbstractSource
{
    /**
     * Catalog config
     *
     * @var \Magento\Catalog\Model\Config
     */
    protected $_catalogConfig;

    /**
     * Construct
     *
     * @param \Magento\Catalog\Model\Config $catalogConfig
     */
    public function __construct(\Magento\Catalog\Model\Config $catalogConfig)
    {
        $this->_catalogConfig = $catalogConfig;
    }

    /**
     * Retrieve Catalog Config Singleton
     *
     * @return \Magento\Catalog\Model\Config
     */
    protected function _getCatalogConfig()
    {
        return $this->_catalogConfig;
    }

    /**
     * {@inheritdoc}
     */
    public function getAllOptions()
    {
        if ($this->_options === null) {
            $this->_options = [
                                ['label' => __('Label1'), 'value' => 'value1'],
                                ['label' => __('Label2'), 'value' => 'value2'],
                                ['label' => __('Label3'), 'value' => 'value3'],
                                ['label' => __('Label4'), 'value' => 'value4']

                                ];

        }
        return $this->_options;
    }
}

backend model:

location: [VendorName]\[ModuleName]\Model\Category\Attribute\Backend\Custom.php

code:

<?php
namespace [VendorName]\[ModuleName]\Model\Category\Attribute\Backend;
class Custom extends \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend
{
    /**
     * Core store config
     *
     * @var \Magento\Framework\App\Config\ScopeConfigInterface
     */
    protected $_scopeConfig;

    /**
     * Construct
     *
     * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
     */
    public function __construct(\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig)
    {
        $this->_scopeConfig = $scopeConfig;
    }

    /**
     * Validate process
     *
     * @param \Magento\Framework\DataObject $object
     * @return bool
     * @throws \Magento\Framework\Exception\LocalizedException
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
     * @SuppressWarnings(PHPMD.NPathComplexity)
     */


    /**
     * Before Attribute Save Process
     *
     * @param \Magento\Framework\DataObject $object
     * @return $this
     */
    public function beforeSave($object)
    {
        $attributeCode = $this->getAttribute()->getName();
        if ($attributeCode == 'multi_custom_attribute') {
            $data = $object->getData($attributeCode);
            if (!is_array($data)) {
                $data = [];
            }
            $object->setData($attributeCode, implode(',', $data) ?: null);
        }
        if (!$object->hasData($attributeCode)) {
            $object->setData($attributeCode, null);
        }
        return $this;
    }

    /**
     * After Load Attribute Process
     *
     * @param \Magento\Framework\DataObject $object
     * @return $this
     */
    public function afterLoad($object)
    {
        $attributeCode = $this->getAttribute()->getName();
        if ($attributeCode == 'multi_custom_attribute') {
            $data = $object->getData($attributeCode);
            if ($data) {
                if (!is_array($data)) {
                    $object->setData($attributeCode, explode(',', $data));
                } else {
                    $object->setData($attributeCode, $data);
                }

            }
        }
        return $this;
    }
}

input_renderer for admin html area:

location: [VendorName]\[ModuleName]\Block\Adminhtml\Category\Helper\Custom\Options.php

code:

<?php
namespace [VendorName]\[ModuleName]\Block\Adminhtml\Category\Helper\Custom;

class Options extends \Magento\Framework\Data\Form\Element\Multiselect
{
    /**
     * Returns js code that is used instead of default toggle code for "Use default config" checkbox
     *
     * @return string
     */
    public function getToggleCode()
    {
        $htmlId = 'use_config_' . $this->getHtmlId();
        return "toggleValueElements(this, this.parentNode.parentNode);" .
            "if (!this.checked) toggleValueElements(\$('{$htmlId}'), \$('{$htmlId}').parentNode);";
    }

    /**
     * Retrieve Element HTML fragment
     *
     * @return string
     */
    public function getElementHtml()
    {
        $elementDisabled = $this->getDisabled() == 'disabled';
        $disabled = false;

        if (!$this->getValue() || $elementDisabled) {
            $this->setData('disabled', 'disabled');
            $disabled = true;
        }

        $html = parent::getElementHtml();
        $htmlId = 'use_config_' . $this->getHtmlId();
        $html .= '<input id="' . $htmlId . '" name="use_config[]" value="' . $this->getId() . '"';
        $html .= $disabled ? ' checked="checked"' : '';

        if ($this->getReadonly() || $elementDisabled) {
            $html .= ' disabled="disabled"';
        }

        $html .= ' onclick="toggleValueElements(this, this.parentNode);" class="checkbox" type="checkbox" />';
        $html .= ' <label for="' . $htmlId . '" class="normal">' . __('Use All Available Attributes') . '</label>';
        $html .= '<script>require(["prototype"], function(){toggleValueElements($(\'' .
            $htmlId .
            '\'), $(\'' .
            $htmlId .
            '\').parentNode);});</script>';

        return $html;
    }
}
5
  • What code I need to put in [VendorName][ModuleName]\view\adminhtml\ui_component\category_form.xml Commented Sep 5, 2016 at 8:58
  • i will check and get back to you
    – Amit Bera
    Commented Sep 5, 2016 at 9:03
  • Did you get a solution please? #Amit Bera Commented Sep 7, 2016 at 8:55
  • 1
    thanks @amit bera you have helped me a lot thank you so much Commented Dec 8, 2017 at 12:27
  • Great. It was helpful Commented Mar 23, 2021 at 10:40
6

This is just an addition to Amits Answer for last step which he has not given.

For admin form you need to create below file.

 [VendorName][ModuleName]\view\adminhtml\ui_component\category_form.xml

<?xml version="1.0"?>
<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
    <fieldset name="general">
        <field name="multi_custom_attribute">
            <argument name="data" xsi:type="array">
                <item name="options" xsi:type="object">app\code\[VendorName]\[ModuleName]\Model\Category\Attribute\Source\Custom</item>
                <item name="config" xsi:type="array">
                    <item name="sortOrder" xsi:type="number">60</item>
                    <item name="dataType" xsi:type="string">string</item>
                    <item name="formElement" xsi:type="string">multiselect</item>
                    <item name="label" xsi:type="string" translate="true">Custom Label</item>
                </item>
            </argument>
        </field>
    </fieldset>
</form>

@Amit you are great. Hope this helps others.

1

I have tried to run the above code. Thanks @Amit for sharing this code and @Ashish for adding missing file but there are three corrections in the paths so as to make the code work. Below are the details of the corrections that I have done after which the module worked.

First:
In Install file [app/code/[VendorName]/[ModuleName]/Setup/InstallData.php] code:
Change:
'backend' => '[VendorName]\[ModuleName]\Model\Category\Attribute\Source\Custom',
To:
'backend' => '[VendorName]\[ModuleName]\Model\Category\Attribute\Backend\Custom',


Second:
backend model file location:
Change:
location: [VendorName]\[ModuleName]\Model\Category\Attribute\Source\Custom.php 
To:
location: [VendorName]\[ModuleName]\Model\Category\Attribute\Backend\Custom.php

Third Correction is in missing file that @Ashish has shared:
Change:
<item name="options" xsi:type="object">app\code\[VendorName]\[ModuleName]\Model\Category\Attribute\Source\Custom</item>
To:
<item name="options" xsi:type="object">[VendorName]\[ModuleName]\Model\Category\Attribute\Source\Custom</item>

Hope it will help to other user's who were facing the same problem. Thanks.

Your Answer

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

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