3

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

  • Magento version 2.1.0 – Gaurav Jain Sep 3 '16 at 5:47
13

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;
    }
}
| improve this answer | |
  • What code I need to put in [VendorName][ModuleName]\view\adminhtml\ui_component\category_form.xml – Gaurav Jain Sep 5 '16 at 8:58
  • i will check and get back to you – Amit Bera Sep 5 '16 at 9:03
  • Did you get a solution please? #Amit Bera – Gaurav Jain Sep 7 '16 at 8:55
  • 1
    thanks @amit bera you have helped me a lot thank you so much – Nagaraju K Dec 8 '17 at 12:27
3

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.

| improve this answer | |
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.

| improve this answer | |

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.