Add category attribute programmatically in Magento 2

Despite the good amount of attributes offered in Magento by default, there is often a need to add some new ones to the system for a particular EAV entity. Today I’m going to show you how to programmatically add a new category attribute.

In order to do any of the following steps you need to set up a module. If you are not familiar with how to create a module in Magento 2 follow this article by Hrvoje Ivančić.

First thing to do in order to add an attribute is to create either install or upgrade script inside a Setup folder in the root of your module. Which script to create depends on whether your module is already installed or not. If a module is installing for the first time then install script needs to be used, like this:

<?php
 
namespace InchooAttributeSetup;
 
use MagentoEavSetupEavSetupFactory;
use MagentoFrameworkSetupModuleContextInterface;
use MagentoFrameworkSetupModuleDataSetupInterface;
use MagentoFrameworkSetupInstallDataInterface;
 
class InstallData implements InstallDataInterface
{
    private $eavSetupFactory;
 
    public function __construct(EavSetupFactory $eavSetupFactory)
    {
        $this->eavSetupFactory = $eavSetupFactory;
    }
 
    public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {
        $setup->startSetup();
 
	// PLACEHOLDER: add attribute code goes here
 
        $setup->endSetup();
    }
}

If a module is being upgraded, i.e. we are raising module version, then upgrade script needs to be used. Lets say we are upgrading our module from version 1.0.0 to version 1.0.1. In that case our upgrade script would look similar to this:

<?php
 
namespace InchooAttributeSetup;
 
use MagentoEavSetupEavSetupFactory;
use MagentoFrameworkSetupModuleContextInterface;
use MagentoFrameworkSetupModuleDataSetupInterface;
use MagentoFrameworkSetupUpgradeDataInterface;
 
class UpgradeData implements UpgradeDataInterface
{
    private $eavSetupFactory;
 
    public function __construct(EavSetupFactory $eavSetupFactory)
    {
        $this->eavSetupFactory = $eavSetupFactory;
    }
 
    public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {
        $setup->startSetup();
 
        if ($context->getVersion() && version_compare($context->getVersion(), '1.0.1') < 0) {
 
            // PLACEHOLDER: add attribute code goes here
        }
 
        $setup->endSetup();
    }
}

To learn more about install/upgrade scripts read this article by Ivan Weiler.

Part of the install/upgrade script which actually adds a new category attribute looks like this:

$eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);
 
$eavSetup->addAttribute(
    MagentoCatalogModelCategory::ENTITY,
    'inchoo_short_description',
    [
        'type' => 'text',
        'label' => 'Short Description',
        'input' => 'textarea',
        'required' => false,
        'sort_order' => 4,
        'global' => MagentoEavModelEntityAttributeScopedAttributeInterface::SCOPE_STORE,
        'wysiwyg_enabled' => true,
        'is_html_allowed_on_front' => true,
        'group' => 'General Information',
    ]
);

We need to pass the type id of the entity to which we want to add a new attribute to (in our case catalog_category), and an array of properties for the given attribute. Place the above code in the placeholder defined in the install/upgrade script above and lets try to execute it.

In order to execute install or upgrade script we can’t simply refresh the page like we did with Magento 1. Instead, in order for Magento 2 to pick up our script we need to execute this command:

php bin/magento setup:upgrade

After running it you should end up with the new category attribute added to the system. How are we going to check if it actually worked? Well, we can go to our database and check setup_module table to see if versions for our module match up:

setup_module

And/or we can check eav_attribute table for an attribute with the attribute code defined in our install/upgrade script. You should see something like this:

attribute

If all that looks ok, go to your Magento admin, open up a category and you should see your newly added attribute. If you don’t see it that means you are running Magento 2.1 or above. Versions prior to 2.1 run on old forms/tabs interface which would automatically pick up your newly added attribute. From version 2.1. category edit page uses accordion style UI form component to display the actual form. All fields and field sets are defined in the XML file for the UI component which is located here:

MagentoCatalogviewadminhtmlui_componentcategory_form.xml

In order to add the new attribute to the category edit form we need to create xml file in our module on the same path with the same name. So in your module, inside Vendor_Name/Module_Name/view/adminhtml/ui_component folder create a file called category_form.xml and populate it with the xml similar to this:

<?xml version="1.0" encoding="UTF-8"?>
<form xmlns_xsi="http://www.w3.org/2001/XMLSchema-instance" xsi_noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
    <fieldset name="content">
         <field name="inchoo_short_description">
            <argument name="data" xsi_type="array">
                <item name="config" xsi_type="array">
                    <item name="class" xsi_type="string">MagentoCatalogUiComponentCategoryFormElementWysiwyg</item>
                    <item name="formElement" xsi_type="string">wysiwyg</item>
	            <item name="label" xsi_type="string" translate="true">Short Description</item>
                    <item name="wysiwygConfigData" xsi_type="array">
                        <item name="settings" xsi_type="array">
                            <item name="theme_advanced_buttons1" xsi_type="string">bold,italic,|,justifyleft,justifycenter,justifyright,|,fontselect,fontsizeselect,|,forecolor,backcolor,|,link,unlink,image,|,bullist,numlist,|,code</item>
                            <item name="theme_advanced_buttons2" xsi_type="boolean">false</item>
                            <item name="theme_advanced_buttons3" xsi_type="boolean">false</item>
                            <item name="theme_advanced_buttons4" xsi_type="boolean">false</item>
                            <item name="theme_advanced_statusbar_location" xsi_type="boolean">false</item>
                        </item>
                        <item name="files_browser_window_url" xsi_type="boolean">false</item>
                        <item name="height" xsi_type="string">100px</item>
                        <item name="toggle_button" xsi_type="boolean">false</item>
                        <item name="add_variables" xsi_type="boolean">false</item>
                        <item name="add_widgets" xsi_type="boolean">false</item>
                        <item name="add_images" xsi_type="boolean">false</item>
                    </item>
                    <item name="template" xsi_type="string">ui/form/field</item>
                    <item name="source" xsi_type="string">category</item>
                    <item name="wysiwyg" xsi_type="boolean">true</item>
                    <item name="dataScope" xsi_type="string">inchoo_short_description</item>
                    <item name="sortOrder" xsi_type="number">50</item>
                    <item name="rows" xsi_type="number">8</item>
                </item>
            </argument>
        </field>
    </fieldset>
</form>

Structure of xml for your custom field depends on the type of attribute you are adding. Here we’ve added another description attribute so we can reuse the xml of the default category description attribute and change a few things. Most important thing to change is field name which has to match the code of the attribute you are trying to add to the form, in our case it is inchoo_short_description. For any other parameters just look at the way it is already implemented in Magento and you should be good to go. Files to look for are mostly located in /view/adminhtml/ui_component/ folder of the modules.

After this you should see your custom attribute in category edit page and be able to edit it. Don’t forget to clear the cache if you have it enabled.

And that’s how you can programmatically add new category attribute in Magento 2. If you need to add an attribute for some other EAV attribute, for example product or customer, procedure is the same. In your install/upgrade just replace entity type id with the type id of the entity you are adding the new attribute to and adjust the attribute properties as you need it.

Hope you find this article useful.

Happy coding!