2

I'm having an issue adding JS and CSS files to the head using a custom handle. Here is a simplified version of my controller action:

public function indexAction() {
    $this->loadLayout();
    $this->_initLayoutMessages('customer/session');
    $this->_initLayoutMessages('catalog/session');

    $this->getLayout()->getUpdate()->addHandle('customer_social_index_tour');

    $this->renderLayout();
}

This handle is being conditionally added on existing customer_social_index pages. The XML for customer_social_index looks like this:

<customer_social_index translate="label">
    <update handle="customer_account"/>

    <!-- Other stuff here that all works great -->
</customer_social_index>

While the custom handle's XML looks like this:

<customer_social_index_tour translate="label">
    <reference name="head">
        <action method="addItem"><type>skin_js</type><name>js/my-js-file.js</name><params/></action>
        <action method="addItem"><type>skin_css</type><name>css/my-css-file.css</name><params/></action>
    </reference>
</customer_social_index_tour>

The problem is that the JS and CSS don't get added. Here are the steps I've taken to debug this:

  1. Move the new handle above $this->loadLayout(); - No effect.
  2. Move <reference name="head"> into <customer_social_index> to make sure that my syntax is right and Magento can find those files. - The files show up correctly.
  3. Dump the list of handles on the page to make sure the handle is being applied correctly using <?php Zend_Debug::dump($this->getLayout()->getUpdate()->getHandles()); ?> - Handle is there as it should be.
  4. Make other layout changes like <remove name="content" /> in <customer_social_index_tour> to make sure that the handle is being effective. - The content was removed.

So from what I can see, the code to add the JS and CSS files is written correctly and works in other handles, and the handle works correctly and can modify the layout. But for some reason I can't add the JS and CSS files from that custom handle.

Thanks for your help!

3

Why didn't your code work ?

Because you added your custom handle customer_social_index_tour after layout get loaded. ie.

$this->loadLayout();
$this->getLayout()->getUpdate()->addHandle('customer_social_index_tour');

What $this->loadLayout()does is, it will generate xml tree based on the available layout handles and then generate all blocks. Since your custom handle get added after all these process, your handle layout update will not have any effects, since layout process are finished just before that :-) Hell... then ..

Why didn't my first Debug technique work ?

In your first debug technique, you have added your custom layout update handle before loading any layouts. ie like this.

$this->getLayout()->getUpdate()->addHandle('customer_social_index_tour');   
$this->loadLayout();

In this case, you are too early. Your custom handle now will be the very first handle that Magento going to process now. This is because action handles are generated inside loadLayout() function. So update handle array will then somwhat look like this.

$handles = array (
    customer_social_index_tour,
    default,
    STORE_{store_id}
    THEME_{area}_{package}_{theme},
    customer_social_index
)

The important thing is your custom handle is placed above default handle. That means default handle processed after customer_social_index_tour processed. Due to this, magento does not understand what is head block that is defined inside your custom handle, since the definition of that block is defined inside head block. OOOOPPSSS..

Why your observer worked

controller_action_layout_load_before is a perfect event for doing custom handle after every action handles. Because this event will get fired after adding default and action handles, but before generating xml and blocks.

So going by this observer is the best solution in my personal opinion. But if you want to do this via controller itself (the only advantage here is, you don't need to declare an observer and then define an observer), then continue reading.

What we need here then ?

Basically this is what you need. You have to add your custom handle after every action handles, but before Magento generates full xml tree and then generate blocks.

It is tricky.. but try this code.

public function indexAction()
{
    $this->loadLayout('', false, false);
    $this->loadLayout('customer_social_index_tour');
    $this->_initLayoutMessages('customer/session');
    $this->_initLayoutMessages('catalog/session');
    $this->renderLayout();
}

Here first loadLayout() call will add all action layout handles (including default handle) but it will not generate xml(second param :false) and blocks((third param :false)). The second loadLayout() will add our custom handle to the layout and then it will generate xml and blocks. Be honest, I didnt try this code. But it should work. If that doesn't work, then you need to manually load your layout. This is what you need to do for that.

public function indexAction()
{
    $this->getLayout()->getUpdate()->addHandle('default');
    $this->addActionLayoutHandles();
    $this->getLayout()->getUpdate()->addHandle('customer_social_index_tour');
    $this->generateLayoutXml();
    $this->generateLayoutBlocks();
    $this->_isLayoutLoaded = true;
    $this->_initLayoutMessages('customer/session');
    $this->_initLayoutMessages('catalog/session');

    $this->renderLayout();
}

Try this and let me know your feedback.

  • Very helpful information. I ended up using an event observer on controller_action_layout_load_before as I think it's cleaner. But I'm glad that I now know why my other method wasn't working. Thanks! – Tyler V. Aug 13 '15 at 2:33
  • oh forgot to add why your observer works. Will add that now. If this is helped, you can accept my answer. thanks – Rajeev K Tomy Aug 13 '15 at 2:37
0

I eventually got this handle working by adding the handle to the layout updates in an event observer, which was observing controller_action_layout_load_before.

What I don't understand is why that is necessary, considering that one of my approaches to this issue was to put the addition of the new handle above $this->loadLayout(); instead of below it. (Edit: See Rajeev's answer.)

Better answers and/or clarifications welcome.

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.