Product Import in Magento Alongwith Updating the Attribute's Options
As you may know or not ! Magento is the fastest growing eCommerce plateform, nowonder because Magento has a lots of flexibility in it. You can feel that too if you are a just a user and as for me as Programmer I just Love it. One of the salient feature that makes Magento a leader in eCommerce software is its ability to Import and Export data to an from the system.
Magento gives you a default interface to import or export data, but you will need the specific format of your data.It is easy to customize that as well, but today lets be interested in standard import, but with one small (Yet important) modification. The important modification in the standard code is this code will be able to options to the attribute of Select/Multiselect/Radio/Checkbox input type, while the product is being imported.
By default Magento only imports the values of the option, of any attribute, which are already avaliable. But this code can be used to create option at run time if it does not exits and assign to the product, during import. For doing this we need to first set up an Advanced Profile of Export/Import. Go to System–>Import/Export–>Advanced Profile and create new Profile. Then in the Action XML paste this.
[source language=”XML”]
<!–
Path=Path of the file relative to ROOT
filename= File name of the XML(MS EXCEL 2003) where import data is saved in Magento’s Format
format = XML
You can use CSV as well.
–>
<action type="dataflow/convert_adapter_io" method="load">
<var name="type">file</var>
<var name="path">var/import</var>
<var name="filename"><![CDATA[products.xml]]></var>
<var name="format"><![CDATA[xml]]></var>
</action>
<!–
adapter= Your Model path
–>
<action type="dataflow/convert_parser_xml_excel" method="parse">
<var name="single_sheet"><![CDATA[]]></var>
<var name="fieldnames">true</var>
<var name="store"><![CDATA[0]]></var>
<var name="number_of_records">1</var>
<var name="decimal_separator"><![CDATA[.]]></var>
<var name="adapter">yourmodel/import</var>
<var name="method">save</var>
</action>
[/source]
The Model defined in the adapter should be like this. You can create a new module for this.
[source language=”php”]
<?php
class Namespace_Module_Model_Import extends Mage_Catalog_Model_Convert_Adapter_Product {
/**
* Save product (import)
* @param array $importData
* @throws Mage_Core_Exception
* @return bool
*/
public function saveRow(array $importData)
{
$product = $this->getProductModel()
->reset();
if (empty($importData[‘store’])) {
if (!is_null($this->getBatchParams(‘store’))) {
$store = $this->getStoreById($this->getBatchParams(‘store’));
} else {
$message = Mage::helper(‘catalog’)->__(‘Skip import row, required field "%s" not defined’, ‘store’);
Mage::throwException($message);
}
}
else {
$store = $this->getStoreByCode($importData[‘store’]);
}
if ($store === false) {
$message = Mage::helper(‘catalog’)->__(‘Skip import row, store "%s" field not exists’, $importData[‘store’]);
Mage::throwException($message);
}
if (empty($importData[‘sku’])) {
$message = Mage::helper(‘catalog’)->__(‘Skip import row, required field "%s" not defined’, ‘sku’);
Mage::throwException($message);
}
$product->setStoreId($store->getId());
$productId = $product->getIdBySku($importData[‘sku’]);
if ($productId) {
$product->load($productId);
}
else {
$productTypes = $this->getProductTypes();
$productAttributeSets = $this->getProductAttributeSets();
/**
* Check product define type
*/
if (empty($importData[‘type’]) || !isset($productTypes[strtolower($importData[‘type’])])) {
$value = isset($importData[‘type’]) ? $importData[‘type’] : ”;
$message = Mage::helper(‘catalog’)->__(‘Skip import row, is not valid value "%s" for field "%s"’, $value, ‘type’);
Mage::throwException($message);
}
$product->setTypeId($productTypes[strtolower($importData[‘type’])]);
/**
* Check product define attribute set
*/
if (empty($importData[‘attribute_set’]) || !isset($productAttributeSets[$importData[‘attribute_set’]])) {
$value = isset($importData[‘attribute_set’]) ? $importData[‘attribute_set’] : ”;
$message = Mage::helper(‘catalog’)->__(‘Skip import row, is not valid value "%s" for field "%s"’, $value, ‘attribute_set’);
Mage::throwException($message);
}
$product->setAttributeSetId($productAttributeSets[$importData[‘attribute_set’]]);
foreach ($this->_requiredFields as $field) {
$attribute = $this->getAttribute($field);
if (!isset($importData[$field]) &amp;amp;&amp;amp; $attribute &amp;amp;&amp;amp; $attribute->getIsRequired()) {
$message = Mage::helper(‘catalog’)->__(‘Skip import row, required field "%s" for new products not defined’, $field);
Mage::throwException($message);
}
}
}
$this->setProductTypeInstance($product);
if (isset($importData[‘category_ids’])) {
$product->setCategoryIds($importData[‘category_ids’]);
}
foreach ($this->_ignoreFields as $field) {
if (isset($importData[$field])) {
unset($importData[$field]);
}
}
if ($store->getId() != 0) {
$websiteIds = $product->getWebsiteIds();
if (!is_array($websiteIds)) {
$websiteIds = array();
}
if (!in_array($store->getWebsiteId(), $websiteIds)) {
$websiteIds[] = $store->getWebsiteId();
}
$product->setWebsiteIds($websiteIds);
}
if (isset($importData[‘websites’])) {
$websiteIds = $product->getWebsiteIds();
if (!is_array($websiteIds)) {
$websiteIds = array();
}
$websiteCodes = split(‘,’, $importData[‘websites’]);
foreach ($websiteCodes as $websiteCode) {
try {
$website = Mage::app()->getWebsite(trim($websiteCode));
if (!in_array($website->getId(), $websiteIds)) {
$websiteIds[] = $website->getId();
}
}
catch (Exception $e) {}
}
$product->setWebsiteIds($websiteIds);
unset($websiteIds);
}
foreach ($importData as $field => $value) {
if (in_array($field, $this->_inventoryFields)) {
continue;
}
if (in_array($field, $this->_imageFields)) {
continue;
}
$attribute = $this->getAttribute($field);
if (!$attribute) {
continue;
}
$isArray = false;
$setValue = $value;
if ($attribute->getFrontendInput() == ‘multiselect’) {
$value = split(self::MULTI_DELIMITER, $value);
$isArray = true;
$setValue = array();
}
if ($value &amp;amp;&amp;amp; $attribute->getBackendType() == ‘decimal’) {
$setValue = $this->getNumber($value);
}
/**CODE MODIFICATION STARTS HERE*/
$optionLabelArray=array();
if ($attribute->usesSource()) {
$options = $attribute->getSource()->getAllOptions(false);
/**
* Update the Source of the attribute when source has no options.
*/
if(count($options)<1){
if($isArray){
foreach($value as $key=>$subvalue){
if(!in_array($subvalue,$newOptionLabelArray)){
$setValue[]=$this->updateSourceAndReturnId($field,$subvalue);
array_push($newOptionLabelArray,$subvalue);
}
}
}
else{
if(!in_array($value,$newOptionLabelArray)){
$setValue=$this->updateSourceAndReturnId($field,$value);
array_push($newOptionLabelArray,$value);
}
}
}
/**
* Work on the source when it has options
*/
else{
/**
* This is the case of Multi-Select
*/
if ($isArray) {
foreach ($options as $item) {
/** Setting the option’s ID if Label matches with the current value of XML column.*/
if (in_array($item[‘label’], $value)) {
$setValue[] = trim($item[‘value’]);
array_push($optionLabelArray,$item[‘label’]); /**Adding Reference to worked attribute option**/
}
}
/**
* Checking in the current XML column value if all values were used in the above loop or not
* If not used then they are new options value, then new option is created and then assigned.
**/
foreach($value as $key=>$subvalue){
if(!in_array($subvalue,$optionLabelArray)){
$setValue[]=$this->updateSourceAndReturnId($field,$subvalue);
}
}
}
/**This is the case of single select**/
else {
$setValue = null;
$newOptionLabelArray=array();
foreach ($options as $item) {
if ($item[‘label’] == $value) {
$setValue = $item[‘value’];
array_push($optionLabelArray,$item[‘label’]); /**Adding Reference to worked attribute option**/
}
}
/**
* Checking in the current XML column value if all values were used in the above loop or not
* If not used then they are new options value, then new option is created and then assigned.
**/
if(!in_array($value,$optionLabelArray)){
$setValue=$this->updateSourceAndReturnId($field,$value);
}
}
}
}
/**CODE MODIFICATION ENDS HERE*/
$product->setData($field, $setValue);
}
if (!$product->getVisibility()) {
$product->setVisibility(Mage_Catalog_Model_Product_Visibility::VISIBILITY_NOT_VISIBLE);
}
$stockData = array();
$inventoryFields = isset($this->_inventoryFieldsProductTypes[$product->getTypeId()])
? $this->_inventoryFieldsProductTypes[$product->getTypeId()]
: array();
foreach ($inventoryFields as $field) {
if (isset($importData[$field])) {
if (in_array($field, $this->_toNumber)) {
$stockData[$field] = $this->getNumber($importData[$field]);
}
else {
$stockData[$field] = $importData[$field];
}
}
}
$product->setStockData($stockData);
$imageData = array();
foreach ($this->_imageFields as $field) {
if (!empty($importData[$field]) &amp;amp;&amp;amp; $importData[$field] != ‘no_selection’) {
if (!isset($imageData[$importData[$field]])) {
$imageData[$importData[$field]] = array();
}
$imageData[$importData[$field]][] = $field;
}
}
foreach ($imageData as $file => $fields) {
try {
$product->addImageToMediaGallery(Mage::getBaseDir(‘media’) . DS . ‘import’ . $file, $fields);
}
catch (Exception $e) {}
}
$product->setIsMassupdate(true);
$product->setExcludeUrlRewrite(true);
$product->save();
return true;
}
/**
* Updates the source of the attribute by the current new value in the XML column, and returns
* the id of the newly created option.
*
* @param string $attribute_code
* @param string $newOption
* @return int|string New Option Id
*/
public function updateSourceAndReturnId($attribute_code,$newOption){
$attribute_model = Mage::getModel(‘eav/entity_attribute’);
$attribute_options_model= Mage::getModel(‘eav/entity_attribute_source_table’) ;
$attribute_code = $attribute_model->getIdByCode(‘catalog_product’, $attribute_code);
$attribute = $attribute_model->load($attribute_code);
$attribute_table = $attribute_options_model->setAttribute($attribute);
try{
$value[‘option’] = array(trim($newOption),trim($newOption));
$result = array(‘value’ => $value);
$attribute->setData(‘option’,$result);
$attribute->save();
}
catch(Exception $e){}
$options = $attribute_options_model->getAllOptions(false);
foreach($options as $option)
{
if ($option[‘label’] == $newOption)
{
return $option[‘value’];
}
}
return "";
}
}
?>
[/source]
Please note the /**CODE MODIFICATION ENDS HERE*/ block. Most of the description is on the code. I got it working, feel free to ask if you got any problem. I am also working on importing custom option. I’ll soon make a post in it as well.
Download Source[Updated]
Here’s the sample import sheet with request from the reader
Sample Sheet