Adding a custom layout XML handle in Magento via a custom observer
Today I am to show you how you can add a custom layout XML handle to apply layout updates to your Magento store.
This feature may allow you to apply a custom designs or add additional content dependant on, for example, content from your system (such as a category/product data). This is possible by the use of Magento's powerful event mechanism, where you can intercept at certain points of the page request process, using an 'observer', and apply your own logic.
To illustrate this, in the example below I will attempt to create a custom design for category pages that are at the top level (root category level) of our store. The design changes will not be applied to categories who sit under their parent categories. To keep it simple, this example merely outputs an additional html block onto the page, but illustrates how you can add and remove blocks, change the template of a page or in fact anything else possible in Magento layout XML files by default.
So let’s begin…
<?xml version="1.0"?> <config> <modules> <Company_Module> <active>true</active> <codePool>local</codePool> </Company_Module> </modules> </config>
This is the new module declaration file and tells Magento our module exists.
Next we need to declare a few configuration options. Create the file app/code/local/Company/Module/etc/config.xml:
<?xml version="1.0"?> <config> <modules> <Company_Module> <version>0.1.0</version> </Company_Module> </modules> <global> <blocks> <!-- Defines our blocks --> <company_module> <class>Company_Module_Block</class> </company_module> </blocks> <events> <!-- Before layout is loaded --> <controller_action_layout_load_before> <observers> <!-- Add category layer handle --> <category_layer_layout_observer> <type>singleton</type> <class>Company_Module_Model_Observer</class> <method>addCategoryLayerLayoutHandle</method> </category_layer_layout_observer> </observers> </controller_action_layout_load_before> </events> </global> </config>
Here you can see we've defined our modules version number and created our block declaration (so Magento knows where to look when we wish to create one).
The final part of the file tells Magento we wish to call the addCategoryLayerLayoutHandle() method in our Observer file (defined below), on the Magento "controller_action_layout_load_before" system event (this is a system handle that is called just before the layout is loaded, perfect for adding new content). The handle "category_layer_layout_observer" is simply a name for our observer and can be anything you wish.
Now lets create our Observer class, create app/code/local/Company/Module/Model/Observer.php:
<?php class Company_Module_Model_Observer { public function addCategoryLayerLayoutHandle(Varien_Event_Observer $observer) { $category = Mage::registry('current_category'); $product = Mage::registry('current_product'); if ($category && !$product) { if($category->getLevel() == 1) { /* @var $update Mage_Core_Model_Layout_Update */ $update = $observer->getEvent()->getLayout()->getUpdate(); $update->addHandle('catalog_category_level1'); } } } }
Here you can see we are passing into our observer the Varien_Event_Observer object, that allows us to access the current layout, controller action etc. This is passed in by default to any observer method (you can define your own inputs incidentally), so therefore all we need to do is declare it in our method, in order to access its properties.
My function simply checks we are on a category page and not a product page (hence the session check), and then checks whether the category is a level 1 category. If so, we get the updated layout from the passed in event to our function, and add an additional handle "catalog_category_level1".
Next we now define what would like to happen with our updated layout. We will assume your current theme package is = "company" and your design theme = "elegant".
Add to or create to the file app/design/frontend/company/elegant/layout/local.xml:
<?xml version="1.0"?> <layout version="0.1.0"> ...OMITTED OTHER LOCAL.XML CONFIG... <!-- Shop top category --> <catalog_category_level1> <reference name="content"> <block type="company_module/test" name="company.module.test" template="company/module/test.phtml"/> </reference> </catalog_category_level1> ... </layout>
Here we can see the same layout handle defined in our PHP is used, and tells Magento to include our new custom block in the content of the page!
Next we create our block file, app/code/local/Company/Module/Block/Test.php:
<?php class Company_Module_Block_Test extends Mage_Core_Block_Template { public function getHelloWorld() { return "Hello World!"; } }
Here we've just created a simple function, returning a test Hello World text string.
Finally, we need to create our block template file (we defined that in the layout local.xml file) that is associated with the block class we've just created above.
Create app/design/frontend/company/elegant/template/company/module/test.phtml:
<div class="test"> <?php echo $this->getHelloWorld() ?> </div>
Phew! All being well you should now see a friendly message when navigating to a level 1 category in your Magento store.
The possibilities are endless (and this example doesn't even touch the iceberg) with event Observers in Magento (you can even create your own events - post coming soon), and provides a great away of extending functionality custom to you and your store.
I hope this helps, any questions let me know!












