Adding a Category Attribute in Magento

Magento gives us the ability to add custom attributes into the database, as well as updating existing attributes. This article will demonstrate adding a category attribute in Magento.

For category attributes, there isn’t a nice interface within the admin area like there is for adding product attributes. Usually a developer will have to create a module to add a custom attribute via setup scripts.

So, how can this module be achieved? Firstly, a module declaration file needs to be created.

<?xml version="1.0"?>
<config>
    <modules>
        <Custom_Attribute>
            <codePool>local</codePool>
            <active>true</active>
        </Custom_Attribute>
    </modules>
</config>

Add the setup configuration in the module’s config.xml configuration file.

<?xml version="1.0"?>
<config>
    <modules>
        <Custom_Attribute>
            <version>1.0.0</version>
        </Custom_Attribute>
    </modules>
    <global>
        <resources>
            <custom_attribute_setup>
                <setup>
                    <module>Custom_Attribute</module>
                    <class>Mage_Catalog_Model_Resource_Setup</class>
                </setup>
            </custom_attribute_setup>
        </resources>
    </global>
</config>

Notice the class used here within the pair of class nodes. Mage_Catalog_Model_Resource_Setup is the class used to add an attribute to the catalog_product entity. Other classes that can be used include Mage_Customer_Model_Resource_Setup and Mage_Sales_Model_Resource_Setup.

All of these setup classes extend Magento’s Mage_Eav_Model_Entity_Setup class.

Next, add the installer script.

<?php
$installer = $this;
$installer->startSetup();

$installer->addAttribute('catalog_category', 'custom_attribute',array());

$installer->endSetup();

The addAttribute() method takes three arguments.

  • The entity_type_id or entity_type_code from the eav_entity_type table
  • The attribute code, that will be the code that your new attribute will use
  • An array of attribute data

The entity types from the eav_entity_type table consist of the following:

Magento Adding and Updating an Attribute

Let’s take a look at the addAttribute() method from the Mage_Eav_Model_Entity_Setup class:

public function addAttribute($entityTypeId, $code, array $attr)
    {
        $entityTypeId = $this->getEntityTypeId($entityTypeId);
        $data = array_merge(
            array(
                'entity_type_id' => $entityTypeId,
                'attribute_code' => $code
            ),
            $this->_prepareValues($attr)
         );

        $this->_validateAttributeData($data);

        $sortOrder = isset($attr['sort_order']) ? $attr['sort_order'] : null;
        $attributeId = $this->getAttribute($entityTypeId, $code, 'attribute_id');
        if ($attributeId) {
            $this->updateAttribute($entityTypeId, $attributeId, $data, null, $sortOrder);
        } else {
            $this->_insertAttribute($data);
        }

        if (!empty($attr['group']) || empty($attr['user_defined'])) {
            $select = $this->_conn->select()
                ->from($this->getTable('eav/attribute_set'))
                ->where('entity_type_id = :entity_type_id');
            $sets = $this->_conn->fetchAll($select, array('entity_type_id' => $entityTypeId));
            foreach ($sets as $set) {
                if (!empty($attr['group'])) {
                    $this->addAttributeGroup($entityTypeId, $set['attribute_set_id'],
                        $attr['group']);
                    $this->addAttributeToSet($entityTypeId, $set['attribute_set_id'],
                        $attr['group'], $code, $sortOrder);
                } else {
                    $this->addAttributeToSet($entityTypeId, $set['attribute_set_id'],
                        $this->_generalGroupName, $code, $sortOrder);
                }
            }
        }

        if (isset($attr['option']) && is_array($attr['option'])) {
            $option = $attr['option'];
            $option['attribute_id'] = $this->getAttributeId($entityTypeId, $code);
            $this->addAttributeOption($option);
        }

        return $this;
    }

The first important line to look at is the merging of the three arguments using the array_merge() PHP function.

The _prepareValues() method comes from the Mage_Eav_Model_Entity_Setup class, but this is usually overridden by the Mage_Catalog_Model_Entity_Setup class. We can see the method here in the Mage_Eav_Model_Entity_Setup class.

protected function _prepareValues($attr)
{
    $data = array(
        'backend_model'   => $this->_getValue($attr, 'backend'),
        'backend_type'    => $this->_getValue($attr, 'type', 'varchar'),
        'backend_table'   => $this->_getValue($attr, 'table'),
        'frontend_model'  => $this->_getValue($attr, 'frontend'),
        'frontend_input'  => $this->_getValue($attr, 'input', 'text'),
        'frontend_label'  => $this->_getValue($attr, 'label'),
        'frontend_class'  => $this->_getValue($attr, 'frontend_class'),
        'source_model'    => $this->_getValue($attr, 'source'),
        'is_required'     => $this->_getValue($attr, 'required', 1),
        'is_user_defined' => $this->_getValue($attr, 'user_defined', 0),
        'default_value'   => $this->_getValue($attr, 'default'),
        'is_unique'       => $this->_getValue($attr, 'unique', 0),
        'note'            => $this->_getValue($attr, 'note'),
        'is_global'       => $this->_getValue($attr, 'global', 1),
    );

    return $data;
}

This is data that exists globally for attributes that belong in the eav_attribute table. If we look at the _prepareValues() method in Mage_Catalog_Model_Resource_Setup.

protected function _prepareValues($attr)
{
    $data = parent::_prepareValues($attr);
    $data = array_merge($data, array(
        'frontend_input_renderer'       => $this->_getValue($attr, 'input_renderer'),
        'is_global'                     => $this->_getValue(
            $attr,
            'global',
            Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL
        ),
        'is_visible'                    => $this->_getValue($attr, 'visible', 1),
        'is_searchable'                 => $this->_getValue($attr, 'searchable', 0),
        'is_filterable'                 => $this->_getValue($attr, 'filterable', 0),
        'is_comparable'                 => $this->_getValue($attr, 'comparable', 0),
        'is_visible_on_front'           => $this->_getValue($attr, 'visible_on_front', 0),
        'is_wysiwyg_enabled'            => $this->_getValue($attr, 'wysiwyg_enabled', 0),
        'is_html_allowed_on_front'      => $this->_getValue($attr, 'is_html_allowed_on_front', 0),
        'is_visible_in_advanced_search' => $this->_getValue($attr, 'visible_in_advanced_search', 0),
        'is_filterable_in_search'       => $this->_getValue($attr, 'filterable_in_search', 0),
        'used_in_product_listing'       => $this->_getValue($attr, 'used_in_product_listing', 0),
        'used_for_sort_by'              => $this->_getValue($attr, 'used_for_sort_by', 0),
        'apply_to'                      => $this->_getValue($attr, 'apply_to'),
        'position'                      => $this->_getValue($attr, 'position', 0),
        'is_configurable'               => $this->_getValue($attr, 'is_configurable', 1),
        'is_used_for_promo_rules'       => $this->_getValue($attr, 'used_for_promo_rules', 0)
    ));
    return $data;
}

We can see options that only apply to product attributes. This makes sense as we don’t need the used_in_product_listing option to be present in the Mage_Eav_Model_Entity_Setup class.

So there are quite a few options that we can configure for our attribute. Note the third parameter that gets passed into the _getValue() method on some occasions. This sets the option to the default value if we do not specify it when creating our attribute.

protected function _getValue($array, $key, $default = null)
{
    if (isset($array[$key]) && is_bool($array[$key])) {
        $array[$key] = (int) $array[$key];
    }
    return isset($array[$key]) ? $array[$key] : $default;
}

So back to our example, even though we did not pass in any options as the third parameter, the attribute still gets saved to the system. However, we would like to add some options to our attribute, like an attribute label.

Note that you can delete the custom_attribute_setup row from the core_resource table in the database, as well as the attribute itself from the eav_attribute table should you wish to run the installer again.

We can go back to the installer script and add some options.

<?php
$installer = $this;
$installer->startSetup();

$installer->addAttribute('catalog_category', 'custom_attribute',array(
    'group'        => 'General Information',
    'type'         => 'int',
    'label'        => 'New Category Attribute',
    'input'        => 'select',
    'source'       => 'eav/entity_attribute_source_boolean',
    'global'       => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_STORE,
    'visible'      => true,
    'required'     => false,
    'user_defined' => false,
    'default'      => 0

));

$installer->endSetup();

Refreshing the Manage Categories area in the Magento admin, the new attribute should show.

Adding a Category Attribute in Magento

Update Attribute

The updateAttribute() method can take up to 5 arguments. Usually when wanting to update an attribute, 4 arguments are used.

  • The entity_type_id or entity_type_code from the eav_entity_type table.
  • The attribute ID or attribute code
  • The attribute field to update
  • The value to update the attribute field
  • The fifth parameter is the sort order which may affect the position of the attribute edit field in the admin area.
public function updateAttribute($entityTypeId, $id, $field, $value = null, $sortOrder = null)
{
    $this->_updateAttribute($entityTypeId, $id, $field, $value, $sortOrder);
    $this->_updateAttributeAdditionalData($entityTypeId, $id, $field, $value);
    return $this;
}

There is a slight irritation with the updateAttribute() method with the third parameter. The full column of the field name rather than the alias must be used as the updateAttribute() method does not pass through the _prepareValues() method.

So an example would be in order to update an attribute’s label, we have to use frontend_label as per the name of the column in the database table, and not the alias label.

$installer->updateAttribute(
    'catalog_category', 
    'custom_attribute',
    'frontend_label',
    'Some Label Name'
);

Assuming you know how to add upgrade scripts in Magento, refresh the page and you should notice the customer attribute’s label has changed.

Adding a Category Attribute in Magento

Note: This article is based on Magento Community/Open Source version 1.9.