Magento – How to add a layout handle before configurable product is loaded

configurable-productevent-observerlayoutlayout-updatemagento-1.8

Synopsis

I need to add a layout handle for a configurable product view, this will allow me to insert necessary javascript into the page for JS based validation. The server-side validation is outside of the scope of this question.

I have created a simple module that observers controller_action_predispatch_catalog_product_view I have implemented logging to see the observers is triggered, and sets a new handle which does nothing.

Although my JS files doesn't exist I would expect to see a 404 error.

Example

config.xml

<?xml version="1.0" encoding="utf-8"?>
<config>
    <modules>
        <Vendor_Example>
            <version>1.0.0</version>
        </Vendor_Example>
    </modules>
    <global>
        <models>
            <vendor_example>
                <class>Vendor_Example_Model</class>
            </vendor_example>
        </models>
        <events>
            <controller_action_predispatch_catalog_product_view>
                <observers>
                    <vendor_example>
                        <class>Vendor_Example_Model_Observer</class>
                        <method>setLayout</method>
                    </vendor_example>
                </observers>
            </controller_action_predispatch_catalog_product_view>
        </events>
    </global>
    <frontend>
        <layout>
            <updates>
                <vendor_example>
                    <file>Vendor_Example.xml</file>
                </vendor_example>
            </updates>
        </layout>
    </frontend>
</config>

Model/Observer.php

<?php

class Vendor_Example_Model_Observer
{
    public function setLayout(Varien_Event_Observer $observer)
    {
        $action = $observer->getEvent()->getControllerAction();

        if ($action instanceof Mage_Catalog_ProductController
            && $action->getRequest()->getActionName() == 'view'
        ) {

            $id          = $action->getRequest()->getParam('id');
            $product     = Mage::getSingleton('catalog/product')->load($id);
            $productType = $product->getTypeInstance(true);

            if ($productType instanceof Mage_Catalog_Model_Product_Type_Configurable) {

                $handle = 'vendor_example_configurable_plate';
                $action->getLayout()->getUpdate()->addHandle($handle);

            }

        }
    }
}

design/frontend/package/theme/layout/vendor_example.xml

<?xml version="1.0" encoding="utf-8"?>
<layout>

    <vendor_example_configurable>
        <reference name="head">
            <action method="addItem"><type>skin_js</type><name>example/test.js</name></action>
        </reference>
    </vendor_example_configurable>

    <vendor_example_configurable_plate>
        <update handle="vendor_example_configurable" />

        <reference name="before_footer_ends">
            <action method="addItem"><type>skin_js</type><name>js/test/ivalid.js</name></action>
        </reference>
    </vendor_example_configurable_plate>

</layout>

Best Answer

if you just want to add a js file for configurable product, you really dont want to do this. Create a local.xml inside your theme layout location and put this code inside

File : app/design/frontend/<package>/<theme>/layout/local.xml

<PRODUCT_TYPE_configurable>
    <reference name="head">
        <action method="addItem">
            <type>skin_js</type>
            <name>js/test.js</name>
        </action>
    </reference>
</PRODUCT_TYPE_configurable>

and put your js file in skin location

File : skin/frontend/<package>/<theme>/js/test.js

PRODUCT_TYPE_configurable is the unique handler that is render by magento, for configurable products only. So you are lucky.. For each product type, there are unique handlers. Magento use this handler in order to put product type specific layout. Take a look on catalog.xml.

EDIT

In that case, you can go for an alternate solution. You can add a template file through this handler and do your insertion of js file there. This would be more reliable method than go for an event observation.

So these are the steps

1. Declare a template for configuration product

<PRODUCT_TYPE_configurable>
    <reference name="content">
        <block type="core/template" name="configurable.js.block" template="configurable/js.phtml" />
    </reference>
</PRODUCT_TYPE_configurable>

2. define a helper for your module and use it to provide js files, according to the need

class Namespace_Module_Helper_Data extends Mage_Core_Helper_Abstract {

     public function getJsForProduct() {

          $product = Mage::registry('current_prouduct');
          $attribute = $product->getData('attribute_code');
          if($attribute == "something"){
               //returns js file here; file location is enough
          }
     } 
}

You need to define your helper class in config. For more RefeR this

3.Define template file

File : app/design/frontend/<package>/<theme>/template/configurable/js.phtml<

<div>
    <?php $js = Mage::helper('your_helper_alias')->getJsForProduct(); ?>
     <script src="<?php echo $js ?>" ></script>
</div>

You can simply get attribute in template file itself. However I showed you a reliable method that you can go with. I didn't test this. But you can make it work.