Adding Layout Handles Programatically (and in order)

Adding custom layout handles in the correct order can sometimes be an awkward process, it can often be tempting to use either the controller_action_predispatch or the controller_action_predispatch_fullActionName, event and then add the layout handle in the corresponding observer code.

The problem with this approach is that these events are fired in the controller’s preDispatch method, meaning loadLayout hasn’t yet been called and there won’t be any other layout handles present at that point. This causes problems because your layout handle may rely on items from other layout handles which haven’t been loaded at that point.

Correcting the handles’ order

One method to fix this issue is to use the controller_action_layout_load_before event which is fired in the loadLayoutUpdates, method (this is called via the loadLayout method). At this point, addActionLayoutHandles has already been executed, which makes relying on other handles a possibility. One problem with this approach is the observer method will be called for every page, which won’t work correctly for code which relies on running for a fullActionName. One fix for this method is to either check the existence of a required layout handle or controller action’s full name in the observer code.

XML

<controller_action_layout_load_before>
    <observers>
        <Demo_Module>
            <class>skin/observer</class>
            <method>updateLayoutHandle</method>
        </Demo_Module>
    </observers>
</controller_action_layout_load_before>

Observer

public function updateLayoutHandle($observer)
{
    $update = $observer->getEvent()->getLayout()->getUpdate();
    $handles = $update->getHandles();

    foreach($handles as $k => $handle){
        if($handle == 'catalog_category_default'){
            $handles[$k] = 'catalog_category_layered';
        }
    }

    $update->resetHandles();
    $update->addHandle($handles);   
}

This allows us to get all layout handles, change them as necessary, and re-add them (an array can be passed to the addHandle method). We could also splice in handles at required points using this method.