xmlmagentolayoutpage-layout

How to modify Page Layout with Layout Handles


I'm in the process of creating a custom Page Layout. I've added the necessary XML to my module's config.xml file, created the template and the template is selectable in the Admin Panel.

I don't seem to be able to modify the page layout with layout handles. By modify, I mean add JS to the head, add a body class, etc. In my config.xml I have the following:

<config>
    <frontend>
        ....
        <layout>
            <updates>
                <mymodule_layout>
                   <file>mymodule.xml</file>
                </mymodule_layout>
            </updates>
        </layout>
    </frontend>
    ...
    <global>
        <page>
            <layouts>
                <mymodlue_pagelayout module="page" translate="label">
                    <label>My Module - A Custom Layout</label>
                    <template>page/customlayouttest.phtml</template>
                    <layout_handle>mymodlue_pagelayout</layout_handle>
                </mymodlue_pagelayout>
            </layouts>
        </page>
    ....
    </global>
</config>

Then in mymodule.xml, I have the below XML. None of it works. When I visit the category with the my Page Layout applied absolutely none of the below changes take effect. What am I missing?

<mymodlue_pagelayout translate="label">
    <label>My Module - A Custom Layout</label>
    <reference name="root">
        <action method="setTemplate"><template>page/customlayouttest.phtml</template></action>
        <!-- Mark root page block that template is applied -->
        <action method="setIsHandle"><applied>1</applied></action>
        <action method="addBodyClass"><className>grid-4</className></action>
        <action method="addBodyClass"><className>stl-category</className></action> 
    </reference>

    <reference name="product_list">
        <action method="setTemplate"><template>catalog/product/list-alternate.phtml</template></action>
        <action method="setData"><name>list_golfers</name><value>true</value></action>
    </reference>

    <reference name="product_list_toolbar">
        <action method="setDefaultGridPerPage"><limit>15</limit></action>
        <action method="addPagerLimit"><mode>grid</mode><limit>15</limit></action>
        <action method="addPagerLimit"><mode>grid</mode><limit>all</limit></action>
    </reference>

    <reference name="head">
        <action method="addJs"><script>jquery/jquery-1.7.1-min.js</script></action>
        <action method="addJs"><script>varien/product.js</script></action>
        <action method="addJs"><script>varien/configurable.js</script></action>
        <action method="addJs"><script>amasty/amconf/configurable.js</script></action>
        <action method="addJs"><script>jquery/magiczoom.js</script></action>
        <action method="addJs"><script>prototype/window.js</script></action>
        <action method="addJs"><script>jquery/jquery-magnificPopup.0.9.9.js</script></action>
    </reference>
</mymodlue_pagelayout>

Solution

  • The short answer to this question is that Magento simply does not use the information in the layout handle on category pages, it is literally ignored. Alan Storm provides us with an explanation in a similar SO question: https://stackoverflow.com/a/20257191/2124039.

    While we now know why layout handles aren't working, we still need to a solution -how do we modify Page Layouts with layout handles? I found the simplest solution to be creating an observer that listens for the event controller_action_layout_load_before, determines if the page being viewed is a category page, and then adds the layout handle to the layout object for the layout page we are using (if any).

    Built as a stand alone module, it would be something like this:

    config.xml

    <config>
        <modules>
            <Callmetwan_CategoryLayoutHandler>
                <version>1.0.0.0</version>
            </Callmetwan_CategoryLayoutHandler>
        </modules>
        <frontend>
            <events>
                <controller_action_layout_load_before>
                    <observers>
                        <pm_shopthelook_model_observer>
                            <class>Callmetwan_CategoryLayoutHandler_Model_Observer</class>
                            <method>addCustomHandles</method>
                        </pm_shopthelook_model_observer>
                    </observers>
                </controller_action_layout_load_before>
            </events>
        </frontend>
    </config>
    

    observer.php:

    class Callmetwan_CategoryLayoutHandler_Model_Observer extends Varien_Object
    {
        public function addCustomHandles($observer) {
    
            $pageConfig         = (object) Mage::getModel('page/config');
            $allLayoutHandles   = (array) $pageConfig->getPageLayoutHandles();
    
    
            // Determine if we are in a category
            $category = Mage::registry('current_category');
            $product = Mage::registry('current_product');
    
            if ($category && !$product)
            {
    
                // Get all design settings applied to current category
                $design = (object) Mage::getSingleton('catalog/design')->getDesignSettings($category);
    
                // Get current page layout current category is using
                $pageLayout = (string) $design->getPageLayout();
    
    
                foreach ($allLayoutHandles as $layout => $handle)
                {
                    // Cycle through each layout to find current layout, then add current page's layout handle to the layout object
                    if ($pageLayout === $layout)
                    {
                        $update = (object) Mage::getSingleton('core/layout')->getUpdate();
                        $update->addHandle($handle);
                        break;
                    }
                }
            }
        }
    }
    

    To recap, you'd end up with two separate modules. Your layout pages would be apart of one module (using the example from the question, it would be Mymodule) and it would define a custom mymyodule.xml layout file that contains the all the updates for the layout pages. Then the code above (Callmetwan_CategoryLayoutHandler) would be responsible for adding the layout handler to the layout object.