Programatically create attribute in Magento, useful for the “on the fly” import system

Sometimes when doing an import in Magento from old shop system you are faced with lot of issues related to attributes. For instance your old shop system might have several product attributes that simply do not fit into the default Magento attributes. In such cases you need to create these attributes manually in the Magento admin, assign them to the appropriate attribute set and then construct a valid CSV file with valid column names for these new attributes.

When you are dealing with large shop systems, with several thousands of products, then actions like these need to be handled programatically. Below is a just a fraction of the code from the full import script I have been working on last few days.

private function createAttribute($code, $label, $attribute_type, $product_type)
{
$_attribute_data = array(
'attribute_code' => 'old_site_attribute_'.(($product_type) ? $product_type : 'joint').'_'.$code,
'is_global' => '1',
'frontend_input' => $attribute_type, //'boolean',
'default_value_text' => '',
'default_value_yesno' => '0',
'default_value_date' => '',
'default_value_textarea' => '',
'is_unique' => '0',
'is_required' => '0',
'apply_to' => array($product_type), //array('grouped')
'is_configurable' => '0',
'is_searchable' => '0',
'is_visible_in_advanced_search' => '0',
'is_comparable' => '0',
'is_used_for_price_rules' => '0',
'is_wysiwyg_enabled' => '0',
'is_html_allowed_on_front' => '1',
'is_visible_on_front' => '0',
'used_in_product_listing' => '0',
'used_for_sort_by' => '0',
'frontend_label' => array('Old Site Attribute '.(($product_type) ? $product_type : 'joint').' '.$label)
);
 
$model = Mage::getModel('catalog/resource_eav_attribute');
 
if (!isset($_attribute_data['is_configurable'])) {
$_attribute_data['is_configurable'] = 0;
}
if (!isset($_attribute_data['is_filterable'])) {
$_attribute_data['is_filterable'] = 0;
}
if (!isset($_attribute_data['is_filterable_in_search'])) {
$_attribute_data['is_filterable_in_search'] = 0;
}
 
if (is_null($model->getIsUserDefined()) || $model->getIsUserDefined() != 0) {
$_attribute_data['backend_type'] = $model->getBackendTypeByInput($_attribute_data['frontend_input']);
}
 
$defaultValueField = $model->getDefaultValueByInput($_attribute_data['frontend_input']);
if ($defaultValueField) {
$_attribute_data['default_value'] = $this->getRequest()->getParam($defaultValueField);
}
 
$model->addData($_attribute_data);
 
$model->setEntityTypeId(Mage::getModel('eav/entity')->setType('catalog_product')->getTypeId());
$model->setIsUserDefined(1);
 
try {
$model->save();
} catch (Exception $e) { echo '<p>Sorry, error occured while trying to save the attribute. Error: '.$e->getMessage().'</p>'; }
}

The import I was running had to deal with grouped and simple products (that go on that grouped products). Besides special attributes that only grouped products had, and some special attributes that only simple products have, system also had some “joint” attributes that both of the product types had. Examples below show how I called the above method to generate such specific or “joint” attributes.

//My "grouped product only" attribute
$this->createAttribute(strtolower("ShirtType"), "ShirtType", "select", "grouped");
 
//My "simple product only" attribute
$this->createAttribute(strtolower("Swatch"), "Swatch", "text", "simple");
 
//My "joint" attribute, the one that I had both on simple and on grouped products
$this->createAttribute(strtolower("InventoryMsg"), "InventoryMsg", "text", "");
$this->createAttribute(strtolower("Complete"), "Complete", "boolean", "");

Hope that above example help someone. Cheers.