Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Magento - Breadcrumbs on category page

I have defined breadcrumbs like this on catalog/category/view.phtml page.

echo $this->getChildHtml('breadcrumbs')

I want to show breadcrumbs on category page only. Do I need to add anything else to use above code ?

Do I need to define this in xml file as well ?

like image 546
Jinal Dabhi Avatar asked Dec 14 '22 20:12

Jinal Dabhi


1 Answers

Breadcumbs is a structural block in Magento. That means it is a part of Magento structure. So if you need to reposition the breadcumb's position, you really need to alter the magento layout structure definition. Breadcump is defined in page.xml

Location: app/design/frontend/base/default/layout/page.xml

<default>
    ....
    <!-- bradcumb block definition -->
     <block type="page/html_breadcrumbs" name="breadcrumbs" as="breadcrumbs"/>

    ....
</default>

Obviously this block is called using getchildHtml() method in the page layout templates. These templates are present in the location app/design/frontend/base/default/tempate/page/. Take a look on those files. Here I include the code inside 1column.phtml template

 <div class="main">
     <?php echo $this->getChildHtml('breadcrumbs') ?>
    <div class="col-main">
        <?php echo $this->getChildHtml('global_messages') ?>
        <?php echo $this->getChildHtml('content') ?>
    </div>
</div>

What you did wrong

Your code will not going to work. Because you used getChildHtml() method to include the breadcumb block. If you want that code work, then breadcumb block should be a child block of block that defines categor/view.phtml. The block that define this template is Mage_Catalog_Block_Category_View. In layout file this block is referenced with a name category.products. You can see this block in catalog.xml

What should you do

Remove the breadcrumps first

You don't need breadcrumbs in every page and you want to change the position where it now seems. For this you should have to remove the breadcrumb block from default layout. This will remove the breadcrumb block from every page. The best way to do this is shown below

create a layout file at app/design/<package>/<theme>/layout/local.xml and put this code inside

<layout>
    <default>
        <reference name="content">
            <remove name="breadcrumbs" />
        </reference>
    </default>
</layout>   

Local.xml file is processes at last after every other layout files are processed. So this is the perfect place to remove breadcrumps block. Now clear the cache and load the page. You will see breadcrump get dissappeard from every pages.

Redefine the breadcrumps in catalog page only

Now you need to put breadcrumb block in category pages only. As I already mentioned, what you need to do is, make the bredcrumbs block child for catalog/category_view block. But here is anothe problem. Generally there are two types of category pages . Category page with layered navigation and category page without layered navigation. Magento has seperate layout structure for both these types. So you need to specify breadcrumbs block for both of these category types.

Location: app/design/<package>/<theme>/layout/catalog.xml

<catalog_category_default>
    ....
    <reference name="content">
            <block type="catalog/category_view" name="category.products" template="catalog/category/view.phtml">
                <block type="page/html_breadcrumbs" name="breadcrumbss" as="breadcrumbss"/>

                ...
            </block>
            ...
    </reference>
    ....
</catalog_category_default>
<catalog_category_layered>
    ....
    <reference name="content">
            <block type="catalog/category_view" name="category.products" template="catalog/category/view.phtml">
                <block type="page/html_breadcrumbs" name="breadcrumbss" as="breadcrumbss"/>

                ...
            </block>
            ...
    </reference>
    ....
</catalog_category_layered>

Work is not over. Now you need to call this breadcrumbs block in template file also

File : app/design/<package>/<theme>/template/catalog/category/view.phtml

<?php echo $this->getChildHtml('breadcrumbss'); ?>

Call this wherever you needed inside view.phtml. You are done. Now clear cache and load the page again.

OOOPSSSS!!!!!

Not showing anything right ?

But our block is there definitely. In order to confirm it, open the breadcrumbs template file and put any text inside it. Now load the page again. You will see the content for sure. So what happend previous time. Let us look.

Breadcrumbs blocks are special block in which we need to set some data before it get rendered. Otherwise it will provide an empty result. The method used to set breadcrumbs block is addCrumb(). Take a look on breadcrumb block Mage_Page_Block_Html_Breadcrumbs. We need to look _toHtml() method, this is what coverts this block into html.

protected function _toHtml()
{
    if (is_array($this->_crumbs)) {
        reset($this->_crumbs);
        $this->_crumbs[key($this->_crumbs)]['first'] = true;
        end($this->_crumbs);
        $this->_crumbs[key($this->_crumbs)]['last'] = true;
    }
    $this->assign('crumbs', $this->_crumbs);
    return parent::_toHtml();
}

So it is essential that $this->_crumbs to be set before invoking this method. Otherwise it will pass an empty array to the breadcrumbs template. This will output nothing in frontend. This is what happens now. That means there is some how the way magento set $this->_crumbs variable changed along with changes that we maded now. So we need to find where the default flow broken now.

Magento sets $this->_crumbs variable using a function addCrumb() which is defined in breadcrumbs block itself. Let us have a look on that method.

public function addCrumb($crumbName, $crumbInfo, $after = false)
{
    $this->_prepareArray($crumbInfo, array('label', 'title', 'link', 'first', 'last', 'readonly'));
    if ((!isset($this->_crumbs[$crumbName])) || (!$this->_crumbs[$crumbName]['readonly'])) {
       $this->_crumbs[$crumbName] = $crumbInfo;
    }
    return $this;
} 

As you can see, this is the method that is responsible for making breadcrumb block active. You can see that $this->_crumbs variable is setting inside this method.

For category page, breadcrumb setting process starts in caetgory view block. Let us have a look on category view block. That is

 `Mage_Catalog_Block_Category_View::_prepareLayout()`

 protected function _prepareLayout()
{
    parent::_prepareLayout();

    $this->getLayout()->createBlock('catalog/breadcrumbs');
    ....
}

Here as you can see it creates new breadcrumb block Mage_Catalog_Block_Breadcrumbs during layout preparation. So we need to find what this block does.

#Mage_Catalog_Block_Breadcrumbs::_preapareLayout()

protected function _prepareLayout()
{
    if ($breadcrumbsBlock = $this->getLayout()->getBlock('breadcrumbs')) {
        $breadcrumbsBlock->addCrumb('home', array(
            'label'=>Mage::helper('catalog')->__('Home'),
            'title'=>Mage::helper('catalog')->__('Go to Home Page'),
            'link'=>Mage::getBaseUrl()
        ));

        $title = array();
        $path  = Mage::helper('catalog')->getBreadcrumbPath();

        foreach ($path as $name => $breadcrumb) {
            $breadcrumbsBlock->addCrumb($name, $breadcrumb);
            $title[] = $breadcrumb['label'];
        }

        if ($headBlock = $this->getLayout()->getBlock('head')) {
            $headBlock->setTitle(join($this->getTitleSeparator(), array_reverse($title)));
        }
    }
    return parent::_prepareLayout();
}

Yes there it is. Breadcrumbs for category block is setting by this block. Now why it didn't work for us now. This is the most trickiest area that we need to understand.

The thing is this. We have our breadcrumbs block is defined inside catalog categoy view page . As you can see this block looking for breadcrumb block in its layout. Unfortunately the block will not be availble now, since that block is actually defines inside category view block. At this stage blocks that are defined above category view block only available here. When breadcrumbs block were insdie page.xml file, this block will be available here. So the method will work perfectly.

Now how can we get outside of this? In my mind, there are two ways to do this

1. Use observer method

2. Change the definition of breadcrumbs block.

I would like to go with second method. Since it would be the best method that we have available now. Here what we need to do is, we need to replicate the functions that does by Mage_Catalog_Block_Breadcrumbs block. After applying changes accordingly, your breadcrumbs page now look like

<?php
/**
* Html page block
*
* @category Mage
* @package Mage_Page
* @author Magento Core Team <[email protected]>
*/
class Rkt_CategoryBreadcrumbs_Block_Page_Html_Breadcrumbs extends Mage_Core_Block_Template
{
/**
* Array of breadcrumbs
*
* array(
* [$index] => array(
* ['label']
* ['title']
* ['link']
* ['first']
* ['last']
* )
* )
*
* @var array
*/
protected $_crumbs = null;
/**
* Cache key info
*
* @var null|array
*/
protected $_cacheKeyInfo = null;
protected $_title = null;
public function __construct()
{
    parent::__construct();
    $this->setTemplate('page/html/breadcrumbs.phtml');
    $this->addCrumb('home', array(
    'label'=>Mage::helper('catalog')->__('Home'),
    'title'=>Mage::helper('catalog')->__('Go to Home Page'),
    'link'=>Mage::getBaseUrl()
    ));
    $this->_title = array();
    $path = Mage::helper('catalog')->getBreadcrumbPath();
    foreach ($path as $name => $breadcrumb) {
    $this->addCrumb($name, $breadcrumb);
    $this->_title[] = $breadcrumb['label'];
    }
}
protected function _prepareLayout(){
    if ($headBlock = $this->getLayout()->getBlock('head')) {
    $headBlock->setTitle(join($this->getTitleSeparator(), array_reverse($this->_title)));
    }
    return parent::_prepareLayout();
}
public function addCrumb($crumbName, $crumbInfo, $after = false)
{
$this->_prepareArray($crumbInfo, array('label', 'title', 'link', 'first', 'last', 'readonly'));
if ((!isset($this->_crumbs[$crumbName])) || (!$this->_crumbs[$crumbName]['readonly'])) {
$this->_crumbs[$crumbName] = $crumbInfo;
}
return $this;
}
/**
* Get cache key informative items
*
* @return array
*/
public function getCacheKeyInfo()
{
if (null === $this->_cacheKeyInfo) {
$this->_cacheKeyInfo = parent::getCacheKeyInfo() + array(
'crumbs' => base64_encode(serialize($this->_crumbs)),
'name' => $this->getNameInLayout(),
);
}
return $this->_cacheKeyInfo;
}
protected function _toHtml()
{
if (is_array($this->_crumbs)) {
reset($this->_crumbs);
$this->_crumbs[key($this->_crumbs)]['first'] = true;
end($this->_crumbs);
$this->_crumbs[key($this->_crumbs)]['last'] = true;
}
$this->assign('crumbs', $this->_crumbs);
return parent::_toHtml();
}
public function getTitleSeparator($store = null)
{
$separator = (string)Mage::getStoreConfig('catalog/seo/title_separator', $store);
return ' ' . $separator . ' ';
}
}

Note that I simply applied what we seen above to this block via _construct,_prepareLayout() and getTitleSeparator(). That's it . We are done

Now again remove cache and load the page again. There it is . Our breadcrumbs only appear for category pages now.

Note: Do not edit core files as I described here. You need to do these things without touching the core files. You need to create a module according to the details that I have given here.

If you don't have time. I have made it for you. Its free.

like image 128
Rajeev K Tomy Avatar answered Dec 24 '22 17:12

Rajeev K Tomy