Why changing the root template doesn't work
Both
Mage_Cms_IndexController::indexAction()
and
Mage_Cms_IndexController::viewAction()
which are responsible for displaying the default homepage and a CMS page respectively call a helper:
Mage::helper('cms/page')->renderPage($this, $pageId)
If you jump into the helper (located at app/code/core/Mage/Cms/Helper/Page.php) and follow renderPage()
to the protected method _renderPage()
you'll see that Magento is checking two times for a root template (Magento CE 1.7.0.2):
if ($page->getRootTemplate()) {
$handle = ($page->getCustomRootTemplate()
&& $page->getCustomRootTemplate() != 'empty'
&& $inRange) ? $page->getCustomRootTemplate() : $page->getRootTemplate();
$action->getLayout()->helper('page/layout')->applyHandle($handle);
}
and
if ($page->getRootTemplate()) {
$action->getLayout()->helper('page/layout')
->applyTemplate($page->getRootTemplate());
}
Both calls happen after layout handles like "cms_page" and the like are processed, so you are out of luck here.
What you can do to change the root template
There is an event cms_page_render
which you can use for adding your own XML layout handle on CMS pages. Create your own extension (I'll spare some details here) and configure the event observer in your config.xml
:
<?xml version="1.0"?>
<config>
<modules>
<Emzee_Cms>
<version>0.0.1</version>
</Emzee_Cms>
</modules>
<global>
<events>
<cms_page_render>
<observers>
<emzee_cms_page_render>
<class>emzee_cms/observer</class>
<method>cms_page_render</method>
</emzee_cms_page_render>
</observers>
</cms_page_render>
</events>
<models>
<emzee_cms>
<class>Emzee_Cms_Model</class>
</emzee_cms>
</models>
</global>
</config>
Add your event observer:
<?php
class Emzee_Cms_Model_Observer
{
public function cms_page_render(Varien_Event_Observer $observer)
{
$action = $observer->getEvent()->getControllerAction();
$actionName = strtolower($action->getFullActionName());
$action->getLayout()->getUpdate()
->addHandle($actionName . '_after');
return $this;
}
}
Finally, add your new layout XML handle (e.g. in your local.xml
):
<?xml version="1.0"?>
<layout version="0.1.0">
<cms_index_index_after>
<reference name="root">
<action method="setTemplate"><template>page/1column.phtml</template></action>
</reference>
</cms_index_index_after>
</layout>
You can use this method as well to add a cms_page_view_after
handle or create page specific handles as cms_page_render
passes the $page
object to your observer.
Why you can't add a block to the 'reference left'
Are you sure that the template you're using has a left column? This question may sound silly but the default "2 columns with right bar" layout for example only offers a 'content' and a 'right' area. I can add blocks to the right column using cms_page
without problems so this could be the problem.
In general, you can only easily add blocks to references and echo them if
- the chosen root template uses the block you're referencing (see
app/design/frontend/base/default/template/page/*.phtml
) and
- the block you're referencing either is of type
core/text_list
, calls $this->getChildhtml()
without arguments or does something else to echo all child blocks.
Without further details, I can't tell you why your blocks are not echo'd in the left or right column.
Best Answer
The XML way
Well an easy way is to create the following file in your module folder:
view/frontend/layout/catalog_category_view.xml
with the following content:It is not more or less elegant than the PHP way and according to what you found it is safer.
The PHP way
Unfortunately in your case, it seems like PHP is the only way to achieve dynamically create handles based on the parameters the category has.
Via plugins
Instead of creating a plugin on the
execute()
method of your action class, you could directly create a plugin on theaddPageLayoutHandles()
method ofMagento\Framework\View\Result\Page
Main problem is that it will be called every time this method is called and you will have to add some conditions in your plugin code to ensure you're on a category view page.
Via preferences
Another way of doing it would be to use preferences for the category view action class:
Then in your custom controller class you simply override the
execute()
method by copying/pasting the original method and add your modifications directly in this method.Main problem is that when you will upgrade your Magento install, if changes are added to the original native Magento action class, it won't reflect in your custom action class.