Magento XML using before/after to place blocks hardly ever works

mike-source picture mike-source · Jan 23, 2013 · Viewed 44.3k times · Source

I'm a front-end Magento dev, have built quite a few of my own themes and I want to understand Magento's XML block positioning better...

I normally use a local.xml file to manipulate everything, I can define a block as follows:

<cms_index_index>
   <reference name="root">
      <block type="core/template" name="example_block" as="exampleBlock" template="page/html/example-block.phtml"/>
   </reference>
</cms_index_index>

This would create a block on the home page (cms_index_index) and since the block is created one level under root, I would normally call the block by adding:

<?php echo $this->getChildHtml('exampleBlock') ?>

...to 1column.phtml (or 2columns-left/right.phtml, 3columns.phtml etc). The block can be placed on any page by substituting cms_index_index for the appropriate page tag.

I see stuff like the following throughout the core XML files, and in tutorials:

<reference name="root">
   <block type="core/template" name="example_block" before="content" template="page/html/example-block.phtml"/>
</reference>

content is a block which is part of magento's general page structure and, from what I understand, before="content" should place it where you'd expect, without needing to use getChildHtml('exampleBlock'), so far so good... however, before/after hardly ever seems to work for me, and I frequently find myself resorting to the getChildHtml method as backup, which isn't always ideal, and means editing more .phtml files than necessary.

I've tried:

<reference name="root">
   <block type="core/template" name="example_block" before="content" template="page/html/example-block.phtml"/>
</reference>

Nothing appears...

<reference name="root">
   <block type="core/template" name="example_block" after="header" template="page/html/example-block.phtml"/>
</reference>

Still nothing.... I'm also aware of using before="-" or after="-" to place something before everything within it's parent block. I occasionally have some luck with that, but generally just get confused and frustrated.

I've googled all over the place for 'magento xml before/after not working' and beginning to wonder if its just me this happens to... can anyone explain when I can and can't use before/after to position blocks? What's wrong with the above examples?

I'm in magento 1.7.0.2 (latest available at time of posting)

The main motivation for this is to reduce the number of core .phtml files I need to edit just to add a getChildHtml(), so if there is another (XML) way to get around this I'd be interested to know...

Answer

Alan Storm picture Alan Storm · Jan 23, 2013

The before and after attributes only work in one of two cases:

  1. When you insert into a core/text_list block
  2. When your template block calls getChildHtml without any parameters

When you say

<reference name="root">
   <block type="core/template" name="example_block" before="content" template="page/html/example-block.phtml"/>
</reference>

you're telling Magento

Hey Magento, put the example_block inside the root block.

When you put a number of different blocks inside a parent, those blocks have an implicit order. For template blocks, this order doesn't matter, since those blocks are being explicitly rendered.

<?php echo $this->getChildHtml('example_block') ?>

However, there's two cases where order matters. First, if you call

<?php echo $this->getChildHtml() ?>

from a template, then Magento will render all the child blocks, in order.

Secondly, there's a special type of block called a "text list" (core/text_list/Mage_Core_Block_Text_List). These blocks render all their children automatically, again in order. The content block is an example of this

<block type="core/text_list" name="content"/>

That's why you can insert blocks into content and they render automatically.

So, in your example above, you're inserting blocks into the root block. The root block is a template block whose phtml template uses getChildHtml calls with explicit parameters. Therefore the before and after attributes don't do what you (and many others, including me) wish they did.