Sometimes there might be a need to start offering products from a new category in your store and you might decide that the category should look completely different than the other ones. The reason might simply be a brand new design. This is where Custom Layout Handle comes in handy.

 What is Custom Layout Handle?

Custom Layout Handle enables us to modify page layout depending on a given handle. In Magento there are many defined handles, for example a page may look different for a logged user (customer_logged_in handle is responsible for this) versus a non-logged one (customer_logged_out).

We can also define a handle for a specific category using its ID. For example, the handle CATEGORY_100 will handle a category with ID 100. However, since the handle will concern only this particular category you may ask yourself what about the subcategories. Should we create a separate handle for each subcategory? The answer is “no – we can use Observer”.

Observer waits for a specific event to execute the code – in this case it will create a custom layout handle.

Let’s imagine a following category tree:

  • Root category
    • Our new category
      • – new category’s child
        • – the child of new category’s child

Now we want Our new category and all it’s children to have a different layout – let’s say e.g. one column. So let’s create a module named Magently_CustomHandle.

//file app/etc/modules/Magently_CustomHandle.xml

<?xml version="1.0"?>
<config>
    <modules>
        <Magently_CustomHandle>
            <active>true</active>
            <codePool>local</codePool>
        </Magently_CustomHandle>
    </modules>
</config>

Now let’s open our module’s configuration file wherein we have to do the following:

  • first, specify the ID of our main category and the name of our handle that we’re going to use in the layout XML files;
  • second, create a helper that will return our categories’ IDs;
  • third, refer to the controller_action_layout_load_before event which, as the name suggests, is executed before the page layout is loaded.
//file app/code/local/Magently/CustomHandle/etc/config.xml

<?xml version="1.0"?>
<config>
    <modules>
        <Magently_CustomHandle>
            <version>1.0.0</version>
        </Magently_CustomHandle>
    </modules>
    <default>
        <custom_category>
            <id>4</id>
            <handle_name>CATALOG_CUSTOM_HANDLE</handle_name>
        </custom_category>
    </default>
    <global>
        <helpers>
            <custom_handle>
                <class>Magently_CustomHandle_Helper</class>
            </custom_handle>
        </helpers>
    </global>
    <frontend>
        <events>
            <controller_action_layout_load_before>
                <observers>
                    <category_handle>
                        <class>Magently_CustomHandle_Model_Observer</class>
                        <method>setHandleForCustomCategory</method>
                    </category_handle>
                </observers>
            </controller_action_layout_load_before>
        </events>
    </frontend>
</config>

Let’s create the helper from which we’ll fetch the category:

//file app/code/local/Magently/CustomHandle/Helper/Data.php

<?php

/**
 * Class Magently_CustomHandle_Helper_Data
 *
 * Methods for our Custom Category
 */
class Magently_CustomHandle_Helper_Data extends Mage_Core_Helper_Abstract 
{
    /**
     * @var int Root category ID
     *
     */
    protected $_rootCategoryId;
    /**
     * @var int Store ID
     */
    protected $_storeId;
    /**
     * @var int Category id
     */
    protected $_categoryId;

    /**
     * Magently_CustomHandle_Helper_Data constructor.
     */
    public function __construct()
    {
        $this->_storeId = Mage::app()->getStore()->getStoreId();
        $this->_rootCategoryId = Mage::app()->getStore($this->_storeId)->getRootCategoryId();
        $this->_categoryId = Mage::getStoreConfig('custom_category/id');
    }

    /**
     * Get id and children ids from our custom category.
    *
     * @return array Array with Custom Categories IDs
     */
    public function getCustomCategoriesIds()
    {
        $customCategory = $this->_getCustomCategory();

        $categoriesIds = array();
        if($customCategory) {
            $subCategories = $customCategory->getAllChildren();

            $categoriesIds = array($customCategory->getId());
            foreach(explode(',', $subCategories) as $id) {
                $categoriesIds[] = $id;
            }
        }

        return $categoriesIds;
    }

    /**
     * Get our custom category.
     *
     * @return Mage_Core_Model_Abstract Custom Category
     */
    protected function _getCustomCategory() 
    {
        $storeCategory = Mage::getResourceModel('catalog/category_collection')
            ->setStoreId($this->_storeId)
            ->addAttributeToFilter('path', array('like' => "1/{$this->_rootCategoryId}/%"))
            ->addFieldToFilter('entity_id', $this->_categoryId);

        if ($storeCategory) {
            return Mage::getModel('catalog/category')->load($storeCategory->getFirstItem()->getEntityId());
        }
    }
}

Next, let’s have a closer look at our helper:

  • in _constructor we determine the store ID, root category ID and the ID of our category that we’ve previously defined in the module’s config.xml file;
  • in _getCustomCategory we fetch instances of the model with our category;
  • in getCustomCategoriesIds() we return an array with our main category ID and all its children’s IDs.

Now, let’s create our Observer using the setHandleForCustomCategory() method.

//file app/code/local/Magently/CustomHandle/Model/Observer.php

<?php

/**
 * Class Magently_Category_Model_Observer
 *
 * Setup custom handle for custom categories.
 */
class Magently_CustomHandle_Model_Observer
{
    /**
     * Method for add custom handle for custom category.
     *
     * @param Varien_Event_Observer $observer
     */
    public function setHandleForCustomCategory(Varien_Event_Observer $observer)
    {
        $currentCat = Mage::registry('current_category');
        $currentProd = Mage::registry('current_product');

        if(($currentProd instanceof Mage_Catalog_Model_Product)
          || !($currentCat instanceof Mage_Catalog_Model_Category)) {
          return;
        }

        $helper = Mage::helper('custom_handle');
        $categoriesId = $helper->getCustomCategoriesIds();

        $currentId = $currentCat->getId();

        if(in_array($currentId, $categoriesId)) {
            $handleName = Mage::getStoreConfig('custom_category/handle_name');

            $update = $observer->getEvent()->getLayout()->getUpdate();
            $update->addHandle($handleName);
        }
    }
}

The setHandleForCustomCategory() method first checks if we’re not on the category page at the moment and whether we’re on a product page. The reason is that, if we were on a product page, our handle would still work, which could lead to unexpected results. We want to create handles only for the category pages. Next, we check if the current category ID is present in the array with our categories’ IDs. We fetch the name of our handle from the config.xml file – just like for our category ID.

Now, in the local.xml file of our theme we add a reference to our handle and set the one column layout:

//file app/design/frontend/PACKAGE/THEME_NAME/layout/local.xml 

<?xml version="1.0" encoding="UTF-8"?>
<layout version="0.1.0">
  ...
  <CATALOG_CUSTOM_HANDLE>
    <reference name="root">
      <action method="setTemplate"><template>page/1column.phtml</template></action>
    </reference>
  </CATALOG_CUSTOM_HANDLE>
 ...
</layout>