[Mini Tutorial] Changing the order of layout XML blocks in local.xml

Let’s face it, even though we like to whine and complain about Magento, it is a powerful platform for a reason. Magento has many useful features that sometimes are exactly what we’re looking for, which is great! Because we don’t have to build our own from scratch.

In many occasions though these features are not placed were we want them to be and sometimes we need to change their order, so we need to figure out how they were set up in the first place and where their blocks were defined in order to be able to grab them and move them around. This is when strong Magento layout XML skills come in handy, so I’m writing this tutorial to show you how to re-arrange XML blocks the right way (In local.xml). As I yell right in your ear “Best practices for the win!”

53621351

Related: [Mini Tutorial] Adding Custom Links with local.xml

As you may already know, Magento comes with a few different block types which are the block classes that contain specific functions in each. When it comes to rendering blocks on a page these types can be divided into two different behaviours: one that renders every child block automatically without the need of a getChildHtml() call in the template, and one that only renders blocks whenever and wherever you specify that call in the template. The former behaviour belongs to the one and only core/text_list block type, and the latter behaviour belongs to pretty much every other block type.

In Magento the before="child.block.name" and after="child.block.name" attributes are used to define the order of child blocks in the core/text_list blocks. If those attributes are not specified then the blocks will render in the order that Magento reads them.

Magento’s best practices dictate that you should make ALL of your layout XML edits inside of local.xml in your theme’s layout folder instead of copying over the entire xml file you want to edit from the default or base themes into your theme. The proper use of local.xml allows you to easily keep track of all the changes you have made in the layout and it also makes it future proof when it comes to upgrading to a newer Magento version on the site.

It is very easy to create a new custom block, give it one of those before or after attributes and have Magento render it right where you want it, but what if you want to change the order of predefined Magento blocks. Well, I will show you two ways to solve this issue.

So, let’s dive into it!

Related: [Mini Tutorial] Add Children Categories as Top Navigation

Solution #1 – Unset and Insert

First, you need to declare your page’s handles. If you wanted the change to affect every page on the entire site you can just use the <default></default> handles, but let’s say we only want this change to affect the listing pages. Go ahead and use the appropriate handles for that.

<catalog_category_view> 
    <!-- affects both default and layered -->
</catalog_category_view>


<catalog_category_default> 
    <!-- affects listing pages without layered navigation -->
</catalog_category_default>


<catalog_category_layered> 
    <!-- affects listing pages with layered navigation -->
</catalog_category_layered> 

If you’re still not sure which one to use, just try them each in turn to see which one works. In our case we will be working with the default one. After we have our handles we need to reference the block we’re working in by its name. Blocks like content, left, right, etc are of the core/text_list type. In this tutorial we will be re-ordering Magento child blocks in the right sidebar so the block name we’re looking for is right. We end up with this.

<catalog_category_default>
    <reference name="right">
    </reference>
</catalog_category_default>

In order to change the after or before attributes of a predefined Magento block (like the title suggests) we need to unset it and re-insert it. So, let’s unset the ordered child block.

<catalog_category_default>
    <reference name="right">
        <action method="unsetChild"><name>catalog.compare.sidebar</name></action>
    </reference>
</catalog_category_default>

If the child block has an as="" attribute then you would need to use the <alias></alias> tags instead of the <name></name> ones. The catalog.compare.sidebar is predefined in Magento to render before="cart_sidebar" so let’s tell it to render after instead.

We’ll need to insert it now.

<catalog_category_default>
    <reference name="right">
        <action method="unsetChild"><name>catalog.compare.sidebar</name></action>
        <action method="insert">
            <blockName>catalog.compare.sidebar</blockName>
            <siblingName>cart_sidebar</siblingName>
            <after>1</after>
            <alias>catalogCompareAlias</alias>
        </action>
    </reference>
</catalog_category_default>

<blockName> is the original block’s name attribute.
<siblingName> is the sibling block’s name attribute. This is the one we want our inserted block to render after or before.
<after> is a boolean. If it equals to 1 the inserted block will be added after the sibling. If it equals to 0 it will be added before.
<alias> is used to add an as attribute to your inserted block (not always necessary).

If <siblingName> was left empty, catalog.compare.sidebar would simply render at the bottom or the top of the right sidebar depending on the <after> boolean.

Related: [Mini Tutorial] How to Add Basic Input Fields to Magento Admin Panel

Solution #2 – Remove and Re-declare

You can also simply remove the predefined Magento block entirely and create a custom one to take its place. The only thing that needs to be different is the block’s name since it’s what we use to remove it in the first place and once a name is removed in Magento it can’t be re-created.

<catalog_category_default>
    <reference name="right">
        <remove name="catalog.compare.sidebar"/>
        <block type="catalog/product_compare_sidebar"  
               name="custom.catalog.compare.sidebar" 
               after="cart_sidebar"
               template="catalog/product/compare/sidebar.phtml"
        />
    </reference>
</catalog_category_default>

Again, note the type and template attributes are the same, but the name has changed and the before attribute has been replaced by an after attribute.

Related: Write Better Code: Tips to Keep Your Templates Clean