Magento programmatically creating attribute sets and attributes

What are attribute sets exactly?

One of the best features Magento holds, is the definition of attribute sets for products as an extension of the EAV database architecture.

As I've written previously the EAV models are based on entity-attribute-value relationships, thus making an entity dynamically scalable, without adding changes to the database structure, and maintaining integrity, without adding too much information for known types.

With attribute sets, Magento goes one step forward and provides the ability to define the same entity, in this case products, in a way that permits them to load only the necessary attributes without the requirements to go forward and add a new entity for each product type.

For example, if you have a fashion online store you might find yourself in the need to separate accessories and clothes into different types with a different sets of attributes. A dress might need a size and color, but a necklace that will complete the look will need to have defined materials, like gold, silver and stone, like diamonds, emerald and so on.

In this case study you will create two attribute sets and although all attributes are linked to a product entity, your products will make use only of the attributes that they need size and color for the dress, materials and stone for the necklace.

From a technical point of view it also helps, as it saves storage space and decreases the joins count and select sizes for the product collections.

Magento also has in each sets attribute groups, but they are only from an estetic point of view and are used to separate the attributes in the set in nice tabs, making it easier for the admin to focus when adding or updating products.

Now that you know what they are use for you might find yourself in the hard work of putting them at work and migrating a large product collection into the store. If you have technical knowledge or a developer at your side, there is no point to insert them by hand, and you might want to build a bulk importer that takes into account your data format and your defined product types.

attribute-sets

How do you create an attribute set programmatically?

Here is a code sample which takes into account either being loaded through a module or being loaded using the Mage::app(); auto-loader.

$entityTypeId = Mage::getModel('catalog/product')->getResource()->getTypeId();
$cloneSetId = 4; // Default Attribute set

//make sure an attribute set with the same name doesn't already exist

$model =Mage::getModel('eav/entity_attribute_set')
		->getCollection()
		->setEntityTypeFilter($entityTypeId)
		->addFieldToFilter('attribute_set_name',$data['set-name'])
		->getFirstItem();
if(!is_object($model)){
	$model = Mage::getModel('eav/entity_attribute_set');
}
if(!is_numeric($model->getAttributeSetId())){
	$new = true;
}
$model->setEntityTypeId($entityTypeId);
						
$model->setAttributeSetName($data['set-name']);
$model->validate();
$model->save();
						
//if the set is new use the Magento Default Attributeset as a skeleton template for the default attributes						
if($new){
	$model->initFromSkeleton($cloneSetId)->save();
}

You will most likely have your own attributes as well, so you will prefer to add them to your own administration tab and make them easier to handle. For this you will have to create an attribute group:

//in $model you have your attribute set already loaded

$modelGroup = Mage::getModel('eav/entity_attribute_group');
$modelGroup->setAttributeGroupName('My attributes');
$modelGroup->setAttributeSetId($model->getAttributeSetId());
$model->setGroups(array($modelGroup));
$model->save();

And last, but not least, you need to load/create your new attributes and add them to your newly created set:

//load your attribute if it exists, by your attributecode (alphanumeric and underscores only)

$attributeCode = 'material';
$attributeModel = Mage::getModel('eav/entity_attribute')->loadByCode(Mage::getModel('eav/entity')->setType('catalog_product')->getTypeId(), $attributeCode);

if(!is_object($attributeModel)||is_null($attributeModel->getAttributeCode())){
  $data = array(
		'is_global'                     => '0', // this can be global or store view dependent
		'frontend_input'                => 'select', // this can be text, textarea, select, date, boolean, multiselect,price,media_image,wee
		'default_value_text'            => '', // the default value depending on the input type
		'default_value_yesno'           => '0', // the default value depending on the input type
		'default_value_date'            => '', // the default value depending on the input type
		'default_value_textarea'        => '', // the default value depending on the input type
		'is_unique'                     => '0', //boolean 0 or 1
		'is_required'                   => '0',//boolean 0 or 1
		'frontend_class'                => '',
		'is_searchable'                 => '1', //boolean 0 or 1
		'is_visible_in_advanced_search' => '1', //boolean 0 or 1
		'is_comparable'                 => '1', //boolean 0 or 1
		'is_used_for_promo_rules'       => '0', //boolean 0 or 1
		'is_html_allowed_on_front'      => '1', //boolean 0 or 1
		'is_visible_on_front'           => '0', //boolean 0 or 1 - if this should load in the product detail view
		'used_in_product_listing'       => '0', //boolean 0 or 1 - if this should be loaded in the category or search listing
		'used_for_sort_by'              => '0', //boolean 0 or 1
		'is_configurable'               => '0', //boolean 0 or 1 - if this will be used as a super-attribute for configurable products
		'is_filterable'                 => '1', //boolean 0 or 1 - if this should be used in the filtered navigation
		'is_filterable_in_search'       => '1', //boolean 0 or 1
		'backend_type'                  => 'int', // the available values are int, varchar, boolean, text
		'default_value'                 => '',
	);
    $labelText = 'Material';
    $data['apply_to'] = array('simple','configurable'); // the product type this attribute should apply
    $data['attribute_code'] = $attributeCode;

    // the label for each of your store views
    $data['frontend_label'] = array(  
		0 => $labelText,
		1 => '',
		3 => '',
		2 => '',
		4 => '',
	);
    $data['option']['values'] = array('silver','gold');
    $attmodel = Mage::getModel('catalog/resource_eav_attribute');
    $attmodel->addData($data);
	
    // the atttribute set is loaded in $model and attribute group in $modelGroup
								
    $attmodel->setAttributeSetId($model->getAttributeSetId());
    $attmodel->setAttributeGroupId($modelGroup->getAttributeGroupId());
									
$attmodel->setEntityTypeId(Mage::getModel('eav/entity')->setType('catalog_product')->getTypeId());
	$attmodel->setIsUserDefined(1);
									
	$attmodel->save();
	$setup = new Mage_Eav_Model_Entity_Setup('core_setup');
	
    // here is a re-occurence of the attribute values in case they did not get properly in the first time as no attribute id was available.
								
	$attributeModel = Mage::getModel('eav/entity_attribute')->loadByCode(Mage::getModel('eav/entity')->setType('catalog_product')->getTypeId(), $attributeCode);
	foreach($data['option']['values'] as &$dt)
	{
			$arr['attribute_id'] = $attributeModel->getId();
			$arr['value']['option_name'][0] = $dt;
			$setup->addAttributeOption($arr);
	}
									
	$smodel=Mage::getModel('eav/entity_setup','core_setup');
	$attributeGroupId=$smodel->getAttributeGroup('catalog_product',$model->getAttributeSetId(),'ECL_IMPORT');
	$smodel->addAttributeToSet('catalog_product',$model->getAttributeSetId(),$attributeGroupId['attribute_group_id'],$attributeModel->getId());

}else{
    $data['option']['values'] = array('lether');
	foreach($data['option']['values'] as &$dt){
			$dt = trim($dt);
	}
	$setup = new Mage_Eav_Model_Entity_Setup('core_setup');

         foreach($data['option']['values'] as &$dt){
		$arr['attribute_id'] = $attributeModel->getId();
		$options = $attributeModel->getSource()->getAllOptions(false);
		foreach($options as $option){
			$existing_options[] = $option['label'];
		}
		if(!in_array($dt,$existing_options)){
			$arr['value']['option_name'][0] = $dt;
			$setup->addAttributeOption($arr);
		}
	}
									
	$smodel=Mage::getModel('eav/entity_setup','core_setup');			
	$attributeGroupId=$smodel->getAttributeGroup('catalog_product',$model->getAttributeSetId(),'ECL_IMPORT');
	$smodel->addAttributeToSet('catalog_product',$model->getAttributeSetId(),$attributeGroupId['attribute_group_id'],$attributeModel->getId());
}

Please feel free to try it yourself and comment if you have any questions or any updates.

2 thoughts on “Magento programmatically creating attribute sets and attributes

Leave a Reply

Your email address will not be published. Required fields are marked *

*