Magento layouts: the limit of reference syntax

If you ever tried to update the Magento page content, you probably used the reference node: this instruction tells that every node under the reference node is applied to the block having the name used in the reference. Here’s an example:

<reference name="head">
<action method="addJs"><script>prototype/prototype.js</script></action>
</reference>

The example above will perform the addJs action on the block with the attribute name head.

This syntax is very useful when, in your custom layouts files, you want to refer to another page content block without updating the layout file which contains the referenced block. This instruction is very useful when you create your own modules and want to only customize Magento page

But sometimes, it does not work.

Why the Magento reference node’s content is sometimes not interpreted?

To understand when this case happens, take a look at the following two modules

Test_FirstModule and Test_SecondModule; Each of these modules embeds its own layout update. The layout of the second module defines a block in the content node called test_secondmodule_content

<?xml version="1.0" encoding="UTF-8">
<layout version="1.0">
    <default>
        <reference name="content">
            <block type="test_secondmodule/content" name="test_secondmodule_content" template="test/secondmodule/content.phtml" />
        </reference>
    </default>
</layout>

The first module refers to this block to provide a child block

<?xml version="1.0" encoding="UTF-8">
<layout version="1.0">
    <default>
        <reference name="test_secondmodule_content">
            <block type="test_firstmodule/content_child" name="test_secondmodule_content_child" template="test/firstmodule/content.phtml" />
        </reference>
    </default>
</layout>

In this case block “test_secondmodule_content_child” will never be available: when Magento builds the blocks list composing the page content, it iterates all defined nodes in the appropriate handles within the Mage_Core_Model_Layout::generateBlock method. But merged layout are parsed in the order they have been added in the configuration, so by default by their name. So in our case, firstmodule.xml will be handled before secondmodule.xml. And this is the problem: Reference expects that referenced block already exists. In our example, it won’t be the case because it will be processed after; so the child block won’t make any render

If you call a reference prior the block, all the references content won’t be processed

The only way to use reference is when they have already be defined

Possible solutions to bypass the reference layout limitation

Play with names of your modules and your database layout updates

You can try to manage order by updating the name of your modules and name of the layout files, but this solution depends on the installed modules: there’s still a risk that your layout will be handled before the expected one.

Use the Magento database layout updates

The database layout updates are always managed after the file’s ones: so if you define your references in database layout updates, they should always refer to a valid defined block. But it’s a more complicated way to develop your module.

Remove reference instructions from the layout

This is a cleaner way: before generating blocks, you’ll move all the references nodes content into the appropriate block node: no more references in your layout, no more risk that there is something wrong because they have been loaded in the wrong order.

The Kyp_LayoutFix module

I’ve created a module, Kyp_LayoutFix, that does that very thing: before generating block content, it removes all references instructions from the used layout

This module has been tested on all Community Editions from 1.4.1 to 1.7.0.2 and on the related Enterprises versions and is a sure way to avoid this references problem

This module is provided under the Open Software License

Download the Kyp_LayoutFix module

This module can be downloaded from my pear channel:

pear channel-discover channel.kyp.fr
pear install kyp/kyp_layoutfix

Or you can download it in a tar.gz file here

Let me know if you have any issue with this module.