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 types from the eav_entity_type table consist of the following:
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.
The updateAttribute()
method can take up to 5 arguments. Usually when wanting to update an attribute, 4 arguments are used.
entity_type_id
or entity_type_code
from the eav_entity_type
table.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.
Note: This article is based on Magento Community/Open Source version 1.9.