Skip to content


Configurable Products in Magento

The ecommerce site I’m working on sells some instructional videos, some in different formats (DVD, VHS) and some in mutliple languages (English, Spanish, Portugese, etc). This scenario lends itself to the use of Magento’s Configurable Products. Basically, a configurable product allows the user to choose certain attributes of the product at the time they add the product to their cart. In our scenario, a user would choose the format and the language of the video at the time they add the item to the cart. You can find a good tutorial on setting up Configurable Products through the admin tool at Magento’s Wiki. As described in this wiki entry, you first have to create your custom attributes and then an attribute set that contains the new attributes. I created a Media Format attribute and a Language attribute and then added them to a Videos attribute set. You then create Simple Products based on the attribute set, one for each possbile combination of atttributes, i.e. Video 1 DVD English, Video 1 DVD Spanish, Video 1 VHS English, Video 1 VHS Spanish, etc. Finally you create a configurable product based on the attribute set.

In my case, however, I’m adding products programatically via a php script; not through the admin tool. I traced through the code and the data flow using Firebug on Firefox to determine how configurable products are created. As in the manual process, you first have to create simple products based on the attribute set with all possible combinations of the attributes. Notice that I’m setting the visibility of the simple products to “Nowhere”. This ensures that a user will only see the configurable product.

<?php
define('MAGENTO', realpath('/var/www/magento'));
ini_set('memory_limit', '128M');
 
require_once MAGENTO . '/app/Mage.php';
 
Mage::app();
            //create dvd english product
	    $product = Mage::getModel('catalog/product');
	    $product->setTypeId('simple');
	    $product->setTaxClassId(0); //none
	    $product->setWebsiteIds(array(1));  // store id
	    $product->setAttributeSetId(26); //Videos Attribute Set
	/*	<option value="6">dvd</option>7
		<option value="5">vhs</option> */
	    $product->setMediaFormat(6);  //DVD video
            $product->setLanguage(9); //English
	    $product->setSku(ereg_replace("\n","","videoTest2.1-dvd-english"));
	    $product->setName(ereg_replace("\n","","videoTest2.1"));
	    $product->setDescription("videoTest2");
	    $product->setInDepth("video test");    
	    $product->setPrice("129.95");
	    $product->setShortDescription(ereg_replace("\n","","videoTest2.1"));
	    $product->setWeight(0);
	    $product->setStatus(1); //enabled
	    $product->setVisibility(1); //nowhere
	    $product->setMetaDescription(ereg_replace("\n","","videoTest2.1"));
	    $product->setMetaTitle(ereg_replace("\n","","videotest2"));
	    $product->setMetaKeywords("video test");
	    try{
	    	$product->save();
                $productId = $product->getId();
	    	echo $product->getId() . ", $price, $itemNum added\n";
	    }
	    catch (Exception $e){ 		
	    	echo "$price, $itemNum not added\n";
		echo "exception:$e";
	    } 
 
            //create dvd spanish product
	    $product = Mage::getModel('catalog/product');
	    $product->setTypeId('simple');
	    $product->setTaxClassId(0); //none
	    $product->setWebsiteIds(array(1));  // store id
	    $product->setAttributeSetId(26); //Videos Attribute Set
	/*	<option value="6">dvd</option>7
		<option value="5">vhs</option> */
	    $product->setMediaFormat(6);  //DVD video
            $product->setLanguage(8); //Spanish
	    $product->setSku(ereg_replace("\n","","videoTest2.1-dvd-spanish"));
	    $product->setName(ereg_replace("\n","","videoTest2.1"));
	    $product->setDescription("videoTest2");
	    $product->setInDepth("video test");    
	    $product->setPrice("129.95");
	    $product->setShortDescription(ereg_replace("\n","","videoTest2.1"));
	    $product->setWeight(0);
	    $product->setStatus(1); //enabled
	    $product->setVisibility(1); //nowhere
	    $product->setMetaDescription(ereg_replace("\n","","videoTest2.1"));
	    $product->setMetaTitle(ereg_replace("\n","","videotest2"));
	    $product->setMetaKeywords("video test");
	    try{
	    	$product->save();
                $productId = $product->getId();
	    	echo $product->getId() . ", $price, $itemNum added\n";
	    }
	    catch (Exception $e){ 		
	    	echo "$price, $itemNum not added\n";
		echo "exception:$e";
	    } 
 
            //create vhs english product
	    $product = Mage::getModel('catalog/product');
	    $product->setTypeId('simple');
	    $product->setTaxClassId(0); //none
	    $product->setWebsiteIds(array(1));  // store id
	    $product->setAttributeSetId(26); //Videos Attribute Set
	/*	<option value="6">dvd</option>7
		<option value="5">vhs</option> */
	    $product->setMediaFormat(5);  //VHS video
            $product->setLanguage(9); //English
	    $product->setSku(ereg_replace("\n","","videoTest2.1-vhs-english"));
	    $product->setName(ereg_replace("\n","","videoTest2.1"));
	    $product->setDescription("videoTest2");
	    $product->setInDepth("video test");    
	    $product->setPrice("129.95");
	    $product->setShortDescription(ereg_replace("\n","","videoTest2.1"));
	    $product->setWeight(0);
	    $product->setStatus(1); //enabled
	    $product->setVisibility(1); //nowhere
	    $product->setMetaDescription(ereg_replace("\n","","videoTest2.1"));
	    $product->setMetaTitle(ereg_replace("\n","","videotest2"));
	    $product->setMetaKeywords("video test");
	    try{
	    	$product->save();
                $productId = $product->getId();
	    	echo $product->getId() . ", $price, $itemNum added\n";
	    }
	    catch (Exception $e){ 		
	    	echo "$price, $itemNum not added\n";
		echo "exception:$e";
	    } 
 
            //create vhs spanish product
	    $product = Mage::getModel('catalog/product');
	    $product->setTypeId('simple');
	    $product->setTaxClassId(0); //none
	    $product->setWebsiteIds(array(1));  // store id
	    $product->setAttributeSetId(26); //Videos Attribute Set
	/*	<option value="6">dvd</option>7
		<option value="5">vhs</option> */
	    $product->setMediaFormat(5);  //DVD video
            $product->setLanguage(8); //Spanish
	    $product->setSku(ereg_replace("\n","","videoTest2.1-vhs-spanish"));
	    $product->setName(ereg_replace("\n","","videoTest2.1"));
	    $product->setDescription("videoTest2");
	    $product->setInDepth("video test");    
	    $product->setPrice("129.95");
	    $product->setShortDescription(ereg_replace("\n","","videoTest2.1"));
	    $product->setWeight(0);
	    $product->setStatus(1); //enabled
	    $product->setVisibility(1); //nowhere
	    $product->setMetaDescription(ereg_replace("\n","","videoTest2.1"));
	    $product->setMetaTitle(ereg_replace("\n","","videotest2"));
	    $product->setMetaKeywords("video test");
	    try{
	    	$product->save();
                $productId = $product->getId();
	    	echo $product->getId() . ", $price, $itemNum added\n";
	    }
	    catch (Exception $e){ 		
	    	echo "$price, $itemNum not added\n";
		echo "exception:$e";
	    } 
 
?>

Once you’ve created each of the simple products, you can create the Configurable Product. Configruable Products have two special variables that you must set: Configurable Products Data and Configurable Attributes Data. Configurable Products Data is an array containing the simple products, along with their configurable attribute data and pricing information, that are associated with the configurable product. The JSON “object” that is passed via the admin interface looks like:


{"5792": [{"label": "dvd", "attribute_id": "491", "value_index": "6", "is_percent": 0, "pricing_value"
: ""}, {"label": "Endlish", "attribute_id": "500", "value_index": "9", "is_percent": 0, "pricing_value"
: ""}], "5807": [{"label": "dvd", "attribute_id": "491", "value_index": "6"}, {"label": "Spanish", "attribute_id"
: "500", "value_index": "8", "is_percent": 0, "pricing_value": ""}], "5791": [{"label": "vhs", "attribute_id"
: "491", "value_index": "5", "is_percent": 0, "pricing_value": ""}, {"label": "Endlish", "attribute_id"
: "500", "value_index": "9"}], "5808": [{"label": "vhs", "attribute_id": "491", "value_index": "5"},
{"label": "Spanish", "attribute_id": "500", "value_index": "8"}]}

which translates to this in PHP:

$data = array(
              '5791'=>array('0'=>
                        array('attribute_id'=>'491','label'=>'vhs','value_index'=>'5','is_percent'=>0,'pricing_value'=>''),
                      '1'=>
                        array('attribute_id'=>'500','label'=>'English','value_index'=>'9','is_percent'=>0,'pricing_value'=>'')
                ),
               '5792'=>array('0'=>
                        array('attribute_id'=>'491','label'=>'dvd','value_index'=>'6','is_percent'=>0,'pricing_value'=>''),
                       '1'=>
                         array('attribute_id'=>'500','label'=>'English','value_index'=>'9','is_percent'=>0,'pricing_value'=>'')
                ),
               '5807'=>array('0'=>
                        array('attribute_id'=>'491','label'=>'dvd','value_index'=>'6','is_percent'=>0,'pricing_value'=>''),
                       '1'=>
                         array('attribute_id'=>'500','label'=>'Spanish','value_index'=>'8','is_percent'=>0,'pricing_value'=>'')
                ),
               '5808'=>array('0'=>
                        array('attribute_id'=>'491','label'=>'vhs','value_index'=>'6','is_percent'=>0,'pricing_value'=>''),
                       '1'=>
                         array('attribute_id'=>'500','label'=>'Spanish','value_index'=>'8','is_percent'=>0,'pricing_value'=>'')
                )
);

The is_percent and pricing_value options allow you to set different prices for each customization. So if you wanted the DVD’s to cost $5 more than the default, just set the pricing_value to 5. Or if you prefer to do a percent of the default cost, set the is_percent parameter to 1 and enter a percent (0 to 100) for the pricing_value.

The Configurable Attributes Data is another array that defines which of the product attributes are configurable. It takes this form:

$data = array('0'=>array('id'=>NULL,'label'=>'Media Format','position'=> NULL,
                   'values'=>array('0'=>
                                            array('value_index'=>5,'label'=>'vhs','is_percent'=>0,
                                                    'pricing_value'=>'0','attribute_id'=>'491'),
                                        '1'=>
                                            array('value_index'=>6,'label'=>'dvd',
			                            'is_percent'=>0,'pricing_value'=>'0','attribute_id'=>'491')
		    ),
                    'attribute_id'=>491,'attribute_code'=>'media_format','frontend_label'=>'Media Format',
		    'html_id'=>'config_super_product__attribute_0'),
             '1'=>array('id'=>NULL,'label'=>'Language','position'=> NULL,
                   'values'=>array('0'=>
                                            array('value_index'=>8,'label'=>'Spanish','is_percent'=>0,
                                                    'pricing_value'=>'0','attribute_id'=>'500'),
                                        '1'=>
                                            array('value_index'=>9,'label'=>'English',
			                            'is_percent'=>0,'pricing_value'=>'0','attribute_id'=>'500')
		    ),
                    'attribute_id'=>500,'attribute_code'=>'media_format','frontend_label'=>'Language',
		    'html_id'=>'config_super_product__attribute_1')
        );

Putting it all together:

<?php
define('MAGENTO', realpath('/var/www/magento'));
ini_set('memory_limit', '128M');
 
require_once MAGENTO . '/app/Mage.php';
 
Mage::app();
            //create dvd english product
	    $product = Mage::getModel('catalog/product');
	    $product->setTypeId('configurable');
	    $product->setTaxClassId(0); //none
	    $product->setWebsiteIds(array(1));  // store id
	    $product->setAttributeSetId(26); //Videos Attribute Set
	    $product->setSku(ereg_replace("\n","","videoTest2.2"));
	    $product->setName(ereg_replace("\n","","videoTest2.2"));
	    $product->setDescription("videoTest2.2");
	    $product->setInDepth("video test");    
	    $product->setPrice("129.95");
	    $product->setShortDescription(ereg_replace("\n","","videoTest2.2"));
	    $product->setWeight(0);
	    $product->setStatus(1); //enabled
	    $product->setVisibility(4); //catalog and search
	    $product->setMetaDescription(ereg_replace("\n","","videoTest2.2"));
	    $product->setMetaTitle(ereg_replace("\n","","videotest2.2"));
	    $product->setMetaKeywords("video test");
           $data = array('5791'=>
               array('0'=>
                        array('attribute_id'=>'491','label'=>'vhs','value_index'=>'5','is_percent'=>0,'pricing_value'=>''),
                      '1'=>
                        array('attribute_id'=>'500','label'=>'English','value_index'=>'9','is_percent'=>0,'pricing_value'=>'')
                ),
               '5792'=>array('0'=>
                        array('attribute_id'=>'491','label'=>'dvd','value_index'=>'6','is_percent'=>0,'pricing_value'=>''),
                       '1'=>
                         array('attribute_id'=>'500','label'=>'English','value_index'=>'9','is_percent'=>0,'pricing_value'=>'')
                ),
               '5807'=>array('0'=>
                        array('attribute_id'=>'491','label'=>'dvd','value_index'=>'6','is_percent'=>0,'pricing_value'=>''),
                       '1'=>
                         array('attribute_id'=>'500','label'=>'Spanish','value_index'=>'8','is_percent'=>0,'pricing_value'=>'')
                ),
               '5808'=>array('0'=>
                        array('attribute_id'=>'491','label'=>'vhs','value_index'=>'6','is_percent'=>0,'pricing_value'=>''),
                       '1'=>
                         array('attribute_id'=>'500','label'=>'Spanish','value_index'=>'8','is_percent'=>0,'pricing_value'=>'')
                )
            );
	    $product->setConfigurableProductsData($data);
            $data = array('0'=>array('id'=>NULL,'label'=>'Media Format','position'=> NULL,
                   'values'=>array('0'=>
                                            array('value_index'=>5,'label'=>'vhs','is_percent'=>0,
                                                    'pricing_value'=>'0','attribute_id'=>'491'),
                                        '1'=>
                                            array('value_index'=>6,'label'=>'dvd',
			                            'is_percent'=>0,'pricing_value'=>'0','attribute_id'=>'491')
		    ),
                    'attribute_id'=>491,'attribute_code'=>'media_format','frontend_label'=>'Media Format',
		    'html_id'=>'config_super_product__attribute_0'),
                   '1'=>array('id'=>NULL,'label'=>'Language','position'=> NULL,
                   'values'=>array('0'=>
                                            array('value_index'=>8,'label'=>'Spanish','is_percent'=>0,
                                                    'pricing_value'=>'0','attribute_id'=>'500'),
                                        '1'=>
                                            array('value_index'=>9,'label'=>'English',
			                            'is_percent'=>0,'pricing_value'=>'0','attribute_id'=>'500')
		    ),
                    'attribute_id'=>500,'attribute_code'=>'media_format','frontend_label'=>'Language',
		    'html_id'=>'config_super_product__attribute_1')
           );
	    $product->setConfigurableAttributesData($data);
	    $product->setCanSaveConfigurableAttributes(1);
 
	    try{
	    	$product->save();
                $productId = $product->getId();
	    	echo $product->getId() . ", $price, $itemNum added\n";
	    }
	    catch (Exception $e){ 		
	    	echo "$price, $itemNum not added\n";
		echo "exception:$e";
	    } 
?>

I came up with my attribute_ids, values, etc by viewing the source of the admin interface. I’m sure there’s a way to use the attribute model to get the values but since I manually create the attributes and attribute sets, I haven’t bothered.

Posted in magento.

Tagged with .


13 Responses

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.

  1. Brian says

    awesome! I’ve built simple products but no configurable ones. I haven’t tried your example yet but man thanks.. with the lack of magento documentation for developers this is a huge time saver… can’t thank you enough… sure wish magento would get on the ball for devs

  2. Ron says

    Where is this script supposed to be placed to work properly?

  3. juice says

    I placed my script in my home directory. I run it has a shell script, not as a web script, so you’ll need shell access to the machine where your webserver is running. Make sure to set the Magento variable to where your version of Magento is installed (for me its in /var/www/Magento).

  4. Brian says

    Thanks for this script.
    I am guessing you had to do this because there’s no easy way to do this using Magento’s product API? I was hoping to create configurable products using the API
    Once again, thank you for this script.

  5. juice says

    I had to load 300K+ products. The API was just to slow. I believe I saw posts on the Magento boards about using the API to create configurable products.

  6. Mike says

    juice,
    Have you run into any performance issues using the DB model to create products?

    I came across your post and tried using this method, but unfortunately it ended up being too slow to be feasible (15 minutes for 500 products). I’m wondering if there is perhaps an underlying issue with the Magento DB model as far as efficiency, or something else I missed bogging things down.

  7. juice says

    For simple products, I load ~75 per minute; for configurable products, its about the same rate but seems slower since you have to create multiple simple prodcuts for each configurable product. I believe the perfomance issues are indeed related to Magent’s data model. It allows for a lot of flexibility but that same flexibility undermines performance. There are several posts on the magento boards dealing with using direct sql queries to create products. Doing it that way may be faster but I haven’t tried it yet.

  8. Mike says

    As expected, it is indeed MUCH faster with direct queries, albeit a bit of a headache. The same 500 product import now takes about 8 seconds.

  9. Brian says

    Does 75 per minute include categorization? I’ve noticed that it’s not creation, but categorization that takes a real long time. How did you manage around that?

  10. Mike says

    Brian,
    I did notice the categorization took a bit longer.

    We have moved back to using the API at this point, as there are just too many tables that need to be updated for a configurable product insert. The code was unmaintainable, and the speed increase was becoming negligible.

  11. Thomas says

    Can you use the script for creating bundled products as well?

  12. Gregory says

    This script works for me, almost. It adds the simple and configurable products into Magento, but when I go to edit configurable product, I get this error:

    Fatal error: Call to a member function getId() on a non-object in C:\xampp\htdocs\wmishops\magento\app\code\core\Mage\Catalog\Model\Product\Type\Configurable.php on line 222

    For some reason the protected property ‘_data’ array key ‘product_attribute’ is not being set.

    Any idea on what I am doing wrong?

  13. juice says

    What version of magento are you using? The code was tested with 1.3.2.2 but I have not run it against 1.4rc. I’d double check to make sure all the attribute_ids are correct; the attribute_ids in the sample code are specific to my store.



Some HTML is OK

or, reply to this post via trackback.

Spam Protection by WP-SpamFree