Solving Magento

Solutions for Magento E-Commerce Platform

by Oleg Ishenko

Magento Configurable Product Type (Part 1)

If the merchandise you sell in your shop has options, which customers can select from before adding products to the shopping cart, then Magento’s configurable product type is an obvious choice. Configurable products are rather common: shoes (sizes), apparel (colors, sizes), jewelry (material, gems), and many others. The configurable type is quite complex and must be approached carefully because it can add a considerable penalty to the shop performance. In this post we will discuss the architecture of the configurable product type and get an insight into its internal mechanics so that you can employ it correctly and efficiently.

Before diving into the technical details, let’s make an overview of the management of configurable products in the back-end as well as follow a customer browsing such a product in the front-end. In this exercise we will use the sample data you can download from the Magento website (here).

Managing configurable products in the back-end

In the administration back-end go to the Catalog => Manage Products. In the product grid’s Type drop-down filter select Configurable and click the Search button. The result is a list of all configurable products in the system.configurable_products_list

Figure 1. Configurable product list

Click one of them, “ECCO Womens Golf Flexor Golf Shoe (Shoes)”. In the product’s details page down in the left navigation column you can spot a tab “Associated Products”. This is an important distinction of configurable product from any other product type (with an exception of grouped products, which we will discuss later). If you open this tab you’ll see the page with three forms. Due to its length I’ve split the screenshot in two. The first one contains two forms, which you can use to add simple products as options to the configurable:

configurable_associated_products_top

Figure 2. Editing associated products, top forms

The next screenshot shows you a form where you can manage already available product options:

configurable_associated_products_bottom

Figure 3. Editing associated products, product grid

What are these configurable options? Well, they are simple products, more precisely products of type Simple, Virtual, or Downloadable (what product types are allowed as associated products is defined in the configuration of configurable type, see Product Type Configuration section in the post about product types). Every configurable product has one or several of its attributes defined as configurable. Its associated products also must have these attributes, and the combination of these attributes’ values for every option must be unique. For example, if a configurable product has one configurable attribute, say size, its every associated product must have a distinct value for size. Adding a new associated product with a size already available in one of the existing associated products will generate a validation error. If a configurable product has two configurable attributes, for example, size and color, then its associated products would be required to have a unique combination of these two attributes. “Red” and “XL”, “Yellow” and “XL” are two such unique combinations despite having the same size. But an attempt to add another “Yellow” and “XL” associated product would fail.

To add associated products to a configurable you can use any of three forms on the product configuration page in the back-end. The first option is to use the Create Simple Associated Product form in the top of the edit page. Clicking on the “Create Empty” opens a pop-up window where you can type in the details of a new product. Note that the configurable attributes are marked as required and you are supposed to provide a unique value combination for them. If you enter a value combination which is not unique for the given configurable product, the simple product will still be created but not linked to the configurable.

Clicking the button “Copy From Configurable” will open the same pop-up window but with attribute values conveniently pre-entered. You only must correct the ones you need and enter those that must me unique: SKU and configurable attribute(s).

You can create a simple product even faster with the next form, Quick simple product creation. You only need to enter just a few values essential for creating a valid product. Of course, the configurable attributes are required.

The previous ways create simple associated products. If you need to link a non-simple allowed associate product type, such as virtual or downloadable, you can use the product grid in the bottom of the page. It lists all products already associated with the configurable. However, if you select Any in the first column filter, you can list every other simple, virtual, or downloadable product in the catalog. In order to be listed in this grid they must have a configurable attribute, in our case Shoe Size. Other required conditions are:

  • Attribute required_options must be set to 0. This applies to all product types, except Configurable and Bundle, which are not allowed to be associated products anyway. Also a Downloadable product may have this attribute set to 1 if its links can be purchased separately.
  • Associated product candidates must have the same attribute set as the configurable. That is if a configurable product is created with a set of attributes “Shoes”, it only can have associated products created with the “Shoes” set as well. Adding a product with a “default” attribute set would not work in this case.

Take a look at the associated products grid of “ECCO Womens Golf Flexor Golf Shoe (Shoes)”. Note that some of the entries in the grid are deactivated. These products have Shoe Size equal to the value, which is already present among the configurable options. Try to remove the check next to the product with SKU “ecco_3” – every other product with Shoe Size 3 become active and you can any one of them into the selection.

simple_product_options_grid

Figure 4. Selecting associated products in the grid

Configurable product’s presentation in the front-end

The specifics of the display of configurable products are laid out in the catalog.xml file, which is responsible for layouts of catalog pages. Unless you have set up a custom theme, the base/default theme’s configuration is applied, and the file can be found in the app/design/frontend/base/default/layout folder. The layout configurations specific to a product type are recognizable by the PRODUCT_TYPE_ prefix to their nodes. So, scroll down to the PRODUCT_TYPE_configurable node:

<PRODUCT_TYPE_configurable translate="label" module="catalog">
    <label>Catalog Product View (Configurable)</label>
    <reference name="product.info">
        <block type="catalog/product_view_type_configurable"
                            name="product.info.configurable" as="product_type_data"
                            template="catalog/product/view/type/default.phtml">
            <block type="core/text_list" name="product.info.configurable.extra"
                                    as="product_type_data_extra" translate="label">
                <label>Product Extra Info</label>
            </block>
        </block>
    </reference>
    <reference name="product.info.options.wrapper">
        <block type="catalog/product_view_type_configurable"
                            name="product.info.options.configurable" as="options_configurable" before="-"
                            template="catalog/product/view/type/options/configurable.phtml"/>
    </reference>
</PRODUCT_TYPE_configurable>

Listing 1. Layout configuration of the configurable product type, /app/design/frontend/base/default/layout/catalog.xml, line 275.

This node defines, which blocks are inserted into the details page of a configurable product. Look at the reference node product.info.options.wrapper, The layout injects a child block into it. This block is of type catalog/product_view_type_configurable and is responsible for outputting UI elements for configurable options to the product details page. This block has a template assigned to it, catalog/product/view/type/options/configurable.phtml. This template calls all configurable attributes of the product and outputs them as <select> HTML elements. The select elements are a default look for configurable options. Often developers customize them to be presented in more user-engaging ways, such as color pickers for color attributes or icons for sizes. The most interesting lines in the template file, however, are these:

<script type="text/javascript">
    var spConfig = new Product.Config(<?php echo $this->getJsonConfig() ?>);
</script>

Listing 2. Initializing the spConfig object, /app/design/frontend/base/default/template/catalog/product/view/type/options/configurable.phtml, line 45.

This is a call to the function Mage_Catalog_Block_Product_View_Type_Configurable::getJsonConfig(). This function generates a JSON-formatted object, which contains configuration of the configurable product’s options to be used by the add-to cart form. The script that uses this object is inserted into the details page by the layout action setting in the catalog.xml file:

<action method="addJs"><script>varien/configurable.js</script></action>

Listing 3. Configurable product type Javascript added to the layout, /app/design/frontend/base/default/layout/catalog.xml, line 183.

For every allowed configurable attribute the JSON-encoded object contains data on option labels, values, and prices. This JSON object is prepared by the block’s‘ getJsonConfig() function and is used to initialize an object of type Product.Config, whose functionality is defined in the js/varien/configurable.js file. This functionality controls the way the select elements behave when a customer makes a choice. For instance, if a customer chooses an option that changes the final price, the other options in the drop-down list are displayed in such a way that the customer can see, how the price would change is he selects a different option. Or, in case of a configurable product having multiple configurable attributes, the script defines how selecting a value for one attribute would affect options available for another.

To demonstrate this effect I’ve set option prices for product “ECCO Womens Golf Flexor Golf Shoe”:

options_prices_ecco

Figure 5. Option-specific price settings in the back-end

Now, if a customer opens the product’s details page then he can see the base price of $159.99 and the option prices in the drop-down list:

ecco_frontend_special_price_with_option_prices_1

Figure 6. Options of a configurable product with option-specific prices

ecco_frontend_special_price_with_option_prices_changed

Figure 7. Option-specific prices after choosing one of the options

JSON Configuration Object

Before being converted into a JSON string the product options array for this example looks like this:

Array
(
        [attributes] => Array
                (
                        [502] => Array
                                (
                                        [id] => 502
                                         => shoe_size
                                        [label] => Shoe Size
                                        [options] => Array
                                                (
                                                        [0] => Array
                                                                (
                                                                        [id] => 46
                                                                        [label] => 3
                                                                        [price] => 80
                                                                        [oldPrice] => 80
                                                                        [products] => Array
                                                                                (
                                                                                        [0] => 33
                                                                                )

                                                                )

                                                        [1] => Array
                                                                (
                                                                        [id] => 45
                                                                        [label] => 4
                                                                        [price] => 88
                                                                        [oldPrice] => 88
                                                                        [products] => Array
                                                                                (
                                                                                        [0] => 113
                                                                                )

                                                                )

                                                        [2] => Array
                                                                (
                                                                        [id] => 44
                                                                        [label] => 5
                                                                        [price] => 96
                                                                        [oldPrice] => 96
                                                                        [products] => Array
                                                                                (
                                                                                        [0] => 114
                                                                                )

                                                                )

                                                        [3] => Array
                                                                (
                                                                        [id] => 43
                                                                        [label] => 6
                                                                        [price] => 104
                                                                        [oldPrice] => 104
                                                                        [products] => Array
                                                                                (
                                                                                        [0] => 115
                                                                                )

                                                                )

                                                )

                                )

                )

        [template] => $#{price}
        [basePrice] => 159.99
        [oldPrice] => 159.99
        [productId] => 112
        [chooseText] => Choose an Option...
        [taxConfig] => Array
                (
                        [includeTax] => true
                        [showIncludeTax] => false
                        [showBothPrices] => true
                        [defaultTax] => 8.25
                        [currentTax] => 8.25
                        [inclTaxTitle] => Incl. Tax
                )

)

The element under key “attributes” contains options information for each configurable attribute of the product. In our case there is only one such attribute, “Shoe Size”, whose ID is 502 and attribute code is “shoe_size”. The attribute array’s element “options” lists all attribute values available to the current product. There are 4 of them. The first one corresponds to size 3 (“label” => 3). The “id” element refers to the “option_id” value of attribute “shoe_size” in database tables eav_attribute_option and eav_attribute_option_value, and it’s value 46 points to size “3”. The “price” element displays the option price set up in the back-end ($80). This price can be influenced by a catalog price rule, and if there were a rule applying to this product, the value in “price” would have been different. The “old_price” element, however, always shows the option price without any rule adjustment. If the product didn’t have any option-specific prices, both these elements would have had 0 as values. The last element, “products”, lists IDs of all associated products that have this value for attribute “shoe_size”. In our example, only one associated product has value 46, and this is product 33, SKU “ecco_3”.

The other elements of the configuration array are:

  • template is used to output currency value and symbol, and is locale aware.
  • basePrice and oldPrice – contain configurable product’s prices. The value in basePrice can be influenced by an active catalog price rule. The value in oldPrice is always the one set in the back-end. If these prices are different, oldPrice is outputted with a strike-through over it.
  • productId is the Id of the configurable product.
  • chooseText contains a string to be displayed in the top of the options in the drop-down list.
  • taxConfig sets the way taxes are included into the displayed prices.
    • includeTax means that the prices entered in the back-end include tax.
    • showIncludeTax states that prices must be displayed including tax. If the price values do not include tax, the tax part is calculated using the currentTax value.
    • showBothPrices mandates the display of 2 prices: including and excluding tax. The tax display settings can be set in the back-end under Tax => Price Display Settings.
    • defaultTax is calculated by Magento from the tax rule set in the back-end for a default customer. Taxes are location-sensitive and you can set them up in back-end by providing information on country, state or province, and postal code (or a postal code range). To calculate a value for the defaultTax Magento uses the address data of the store’s origin.
    • currentTax is calculated using the data of the customer browsing the page. If the user is not logged in, the system will use address data set up in the back-end under Tax => Default Tax Destination Calculation. In our example I use the USA as the default country and CA as the default state. For these settings my installation has a tax rule with rate of 8.25%, same as for the origin address and the defaultTax.
    • inclTaxTitle is a label to be displayed next to prices including tax.

The taxConfig elements and values are used by the Product.Config class defined in /js/varien/configurable.js in function getOptionLabel():

getOptionLabel: function(option, price){
    var price = parseFloat(price);
    if (this.taxConfig.includeTax) {
        var tax = price / (100 + this.taxConfig.defaultTax) * this.taxConfig.defaultTax;
        var excl = price - tax;
        var incl = excl*(1+(this.taxConfig.currentTax/100));
    } else {
        var tax = price * (this.taxConfig.currentTax / 100);
        var excl = price;
        var incl = excl + tax;
    }

    if (this.taxConfig.showIncludeTax || this.taxConfig.showBothPrices) {
        price = incl;
    } else {
        price = excl;
    }

    var str = option.label;
    if(price){
        if (this.taxConfig.showBothPrices) {
            str+= ' ' + this.formatPrice(excl, true) + ' (' + this.formatPrice(price, true) 
                + ' ' + this.taxConfig.inclTaxTitle + ')';
        } else {
            str+= ' ' + this.formatPrice(price, true);
        }
    }
    return str;
},

Listing 4. Tax settings and price output, /js/varien/configurable.js, line 206

Here the tax display settings are used to generate option labels. This is how they look like if we set Display Product Prices In Catalog to “Including and excluding tax” and our tax is 8.25%:

options_prices_tax

Figure 8. Selecting associated products in the grid

In the next part we will discuss the specifics of the Mage_Catalog_Model_Product_Type_Configurable class. See Magento Configurable Product Type (Part 2).

9 thoughts on “Magento Configurable Product Type (Part 1)

  1. Pingback: Product Type Logic Implementation in Magento | Solving Magento

  2. Pingback: Magento Configurable Product Type Tutorial | Solving Magento

  3. I am working on a local computer right now so website is outdated. I am a novice so am struggling a bit. I have several products that are configured on size. I have the prices fixed and that works fine. What I dislike is having to have a price displayed on the purchase page. In my case $0.00. It looks silly. Is there any way of eliminating having to enter a price in the configured product form? Thank you

  4. Pingback: Creating a Custom Product Type in Magento | Solving Magento

  5. Pingback: Productos configurables con Magento. Intro

  6. Hello,
    final price = base price + each option price
    is ok when you have one option.

    With two or more configurable option, this method cannot handle this simple fact: the manufacturer gives you final price of each variation (main color,size,lighting,a second color,…) of the object he sells.

    The evident (but not implemented ..?) solution is to choose the price in the simple product record pointed by the options choices.

    How/where would you change that in the Magento code ?
    I see something like (‘fixed’,’percent’,’product record’)

    Franck

  7. Олег, добрый день! А как возможно вывести Configurable product’s в список продуктов (файл list.phtml) ?

Leave a Reply

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

Theme: Esquire by Matthew Buchanan.