7

I've recently started using the local.xml as my playground for layouts. Before I had my doubts using it because of...reasons.
I got to see it's advantages, but I hit a brick wall now.
In the default catalog.xml layout file there is a certain block (name not important). Using the layout.xml I added a generic child block to it where I want to place other blocks.

<reference name="not.important">
    <block type="core/text_list" name="extra.left.menu" as="extra" />
</reference>

So far so good.
But now, I have one extension that should add child block to the one declared above.
If I add this new block using local.xml it works nicely.

<block type="core/text_list" name="extra.left.menu" as="extra">
    <block type="myextension/some_block" template="some/template.phtml" as="some_name" name="some_name" />
</block>

But I don't want to do it via local.xml because this new extension might be disabled in the future. If I do it via local.xml and disable the extension it will flood my log files because the block does not exist anymore.
So in my extension layout file I add this:

<reference name="extra.left.menu">
    <block type="myextension/some_block" template="some/template.phtml" as="some_name" name="some_name" />
</reference>

But This way it does not work. I feel this happens because the local.xml file is loaded last, and I cannot add a module dependency so my extension layout file would be loaded after layout.xml.
How should I tackle this? Did I get something wrong?
Or if I want it like this I have to use the "good old way" of cloning catalog.xml in my theme and adding this new block in the catalog.xml of my theme?

  • I assume an ifconfig on frontend display being disable would not cover your needs – David Manners Oct 28 '14 at 10:06
  • @DavidManners. yes and no. If my module disappears completely and ifconfig might not help. But if someone removes the module it should clean the db also, so it might work. – Marius Oct 28 '14 at 10:16
  • I had a quick look at this and I dont think this would work. You could always add a new node to the block and change the way blocks are generated but that is crazy talk :) – David Manners Oct 29 '14 at 7:35
6

When rendering the layout in Magento a few steps happen:

  1. Handles are defined (default, catalog_product_view, etc.)
  2. All XML files are loaded and merged to a single huge XML file, that file is stored somewhere in the cache.
  3. The contents of all handles are loaded and merged into one page-xml file.
  4. The order where the XML files are loaded are alphabetically and the local.xml is loaded last (there are also database layout updates which are loaded even later. (source https://github.com/OpenMage/magento-mirror/blob/magento-1.9/app/code/core/Mage/Core/Model/Layout/Update.php#L433-L438)
  5. Finally the XML is parsed and the blocks is initiated.

So why isn't your example working? This is because the module XML file is loaded before the local.xml file. What happens is that the system first tries to add a block to a reference (to a block) which doesn't exist yet.

To solve te issue: You can use an update, updates get placed before the handles they are called in.

<default>
    <update handle="awesome_new_container_handle"/>
</default>

<awesome_new_container_handle>
    <reference name="not.important">
        <block type="core/text_list" name="extra.left.menu" as="extra" />
    </reference>
</awesome_new_container_handle>

And in your other module file add the block like your did.

<default>
    <reference name="extra.left.menu">
        <block type="myextension/some_block" template="some/template.phtml" as="some_name" name="some_name" />
    </reference>
</default>
  • Are you 100% sure this solution work ? I have a strong feeling that this would not work because update happends inside default handle via local.xml and you are referencing to default layout handle itself in custom layout xml file. If you are used another layout handle in that file, then it will work. Am I correct? – Rajeev K Tomy Oct 28 '14 at 10:33
  • This did not work exactly. But it gave me an idea and I made it work. I used 2 layout handles. So I added the markup from local.xml in one handle local_xml_handle and the markup from the extension layout file in an other handle extension_layout_handle. Then I used them both in local.xml one after the other. So the layout handle from the extension is applied after the first one <default><update handle="local_xml_handle" /><update handle="extension_layout_handle" /></default>. If I disable my extension there will be no extension_layout_handle so there is nothing to load. Thanks. – Marius Oct 28 '14 at 12:56
  • Oh, and thanks for the nice explanation for the layout files flow. I'm sure future readers will appreciate this also. – Marius Oct 28 '14 at 12:57
1

This is somewhat impossible to do via LAYOUT XML FILES. Because local.xml file will load at last. So a block that is "defined" inside a local.xml file cannot be "referenced" through any other layout file.

Normally I will use any observer to add a block in such situation.

However there is an alternative way does exist, I think. You can define that block in default handle through local.xml file. Now it open a chance to use layout handles that will consider after default layout handle by Magento. Since the block is included via default handle, if you are referencing the block via another layout handle through your own layout xml file, Magento is now know about your block, even if it is added via local.xml file.

local.xml

<default>
    <reference name="not.important">
        <block type="core/text_list" name="extra.left.menu" as="extra" />
    </reference>
</default>

your_layout.xml

<custom_handle> <!-- anything except `default` -->
    <reference name="extra.left.menu">
        <block type="myextension/some_block" template="some/template.phtml" as="some_name" name="some_name" />
    </reference>
</custom_handle>

EDIT

First of all I want to say that, I have enough time to spend for you :-)

I have tested my code by creating a demo. This is what I tried. I added this code in local.xml file

<layout>
    <default>
        <reference name="content">
            <block type="core/text_list" name="extra.left.menu" as="extra" />
        </reference>
    </default>
</layout>

Then I added below code directly inside catalog.xml file.

<catalog_category_layered translate="label">
        ....

        <reference name="content">
            <reference name="extra.left.menu">
                <block type="core/template" template="test.phtml" as="some_name" name="some_name" />
            </reference>
            ......
        </reference>
</catalog_category_layered>

Then I loaded a layered category, I see content of test.phtml there like this. (please not I used core/template block as child block for this test purpose. But in your case it will replace with your own block. But it is not at all a problem. Both cases are somewhat same)

I am here

So my point is, this method definitely work. I am sure about this point because I haves used this trick many time before and my ultimate guru for magento layout is @alanstorm :-)

  • Sorry, this didn't work. But thanks for taking your time. – Marius Oct 28 '14 at 12:52
  • Thanks for try. I have updated my answer. Just to inform you that, my method is not wrong. – Rajeev K Tomy Oct 28 '14 at 13:21
  • If you say it works I believe you. it means I didn't do it right. I will try again. – Marius Oct 28 '14 at 13:21
  • I am waiting for your response. Take your own time to test it :-) – Rajeev K Tomy Oct 28 '14 at 13:24
  • Strange thing. It works if I add the extra.left.menu block directly in the content block. But it doesn't if I add it inside an other block that is a child of content or left. I guess this deserves a +1. Anyway, don't spend any more time on this. I prefer the approach with 2 layout handles. as I explained in one of the comments for this answer: magento.stackexchange.com/a/41624/146. Somehow it seams cleaner for me. – Marius Oct 28 '14 at 13:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.