Magento – Custom Options in Product List

custom-options

I am displaying custom options for my products on the product list. The problem is that when you select an option, the price is not updated. This works fine on the individual product page, but not on the product list.

Here's the code I'm using to display the custom options:

Please don't use this code in production. It is messy and incomplete.

<?php $productSku = $_product->getSku();
$product = Mage::getModel('catalog/product');
$productId = $product->getIdBySku( $productSku );

$product = Mage::getModel("catalog/product")->load($productId);

$attVal = $product->getOptions();

$optStr = "";

// loop through the options
foreach($attVal as $optionKey => $optionVal) {

//$optStr .= "<br/>";

//$optStr .= $optionVal->getTitle().": ";

$optStr .= "<select style='display:block; clear:both;' name='options[".$optionVal->getId()."]'>";

foreach($optionVal->getValues() as $valuesKey => $valuesVal) {
$optStr .= "<option value='".$valuesVal->getId()."'>".$valuesVal->getTitle()."</option>";
}

$optStr .= "</select>";

}

echo($optStr );
 ?>

Any ideas on how I can trigger the price change? Thanks.

Best Answer

First, before I get to your question, reloading a model like you are doing is very bad style.

  1. $_product contains the product data, loaded as part of the product collection
  2. You fetch the product's ID using the SKU, this is an additional query, when $_product->getId() would have given you the same.
  3. You then load the product using the ID, even though you already have a loaded product instance. This triggers at least 2 more queries. Per product. Slow. Not good. Do not do that.

Lets assume you have 20 products in the collection, this results in at least 60 additional queries being executed. I'm sorry, but I want to point that out so your code isn't used as a bad example by others.

Now, to get to your actual question: Updating the display of the product price is handled by the JavaScript in js/varien/product.js. To start with, this file isn't included in the product list pages by default. You need to add the following layout XML to change that:

<layout>
    <!-- adjust the handle to whatever page your product list is on -->
    <catalog_category_view>
        <reference name="head">
            <action method="addJs"><script>varien/product.js</script></action>
        </reference>
    </catalog_category_view>
</layout>

The next problem you encounter is that the script assumes there is only a single product on the page. In the single product page template, catalog/product/view.phtml, you can see:

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

This global JavaScript Variable, optionsPrice, is also referred to in the product.js script, in the Product.Config.reloadPrice() method:

    optionsPrice.changePrice('config', {'price': price, 'oldPrice': oldPrice});
    optionsPrice.reload();

So you will need to

  1. Fix the Product.Config class to expect optionsPrice to be an array, indexed by product ID.
  2. Initialize the object for each of the products.

In addition to the JavaScript in the product.js file, you also need to customize the template catalog/product/view/options.phtml.

Again, that script assumes there is only a single products options per page:

var opConfig = new Product.Options(<?php echo $this->getJsonConfig() ?>);

You will need to turn that into an array, indexed by product ID, as well. Also, the global optionsPrice variable is referred to by the code a couple of times. Make sure that they always access the object by the correct product ID.

To summarize:

  • Include the product.js on your product listing page
  • Make sure you use the options.phtml template with the corresponding Mage_Catalog_Block_Product_View_Options block for each of the products to render the options instead of building the HTML yourself
  • Adjust the global JavaScript variables so they work with multiple products per page

Quite a bit of work, but doable. I'm pretty sure there also are a number of extensions that would do what you want.

Related Topic