Magento - Breadcrumbs on category page

22,151

Solution 1

create local.xml under app/design/fontend/yourpackage/yourtemplate/layout

Remove breadcrumbs all pages using xml


then add breadcrumbs for catalog pages.

code if local.xml is

    <?xml version="1.0"?>
    <layout version="0.1.0">
    <default>
<reference name="root">
    <remove name="breadcrumbs"/>
</reference>
    </default>
    <catalog_category_default translate="label">
    <reference name="category.products">
    <block type="page/html_breadcrumbs" name="onlybreadcrumbs" as="onlybreadcrumbs"/>
    </reference>
    </catalog_category_default>
    <catalog_category_layered translate="label">
    <reference name="category.products">
    <block type="page/html_breadcrumbs" name="onlybreadcrumbs" as="onlybreadcrumbs"/>
    </reference>
    </catalog_category_layered>

    </layout>

put the code view.phtml

echo $this->getChildHtml('onlybreadcrumbs')

Solution 2

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.

Solution 3

I feel there is a more elegant way to do that. Rajeev K Tomy explanations of the problem are good but I would like to propose what IMO is a cleaner solution both on the layout side (no need to redefine catalog.products block) and on the code side (no need to rebuild the breadcrumbs).

Layout

<catalog_category_default>
    <reference name="root">
        <action method="unsetChild">
            <!-- For EE - Child to unset may be different in CE -->
            <alias>breadcrumbsContainer</alias>
        </action>
    </reference>

    <reference name="category.products">
        <!-- Create a block from a custom local module -->
        <block type="my_module/breadcrumbs" name="my_module.breadcrumbs"/>
    </reference>
</catalog_category_default>

<catalog_category_layered>
    <reference name="root">
        <action method="unsetChild">
            <!-- For EE - Child to unset may be different in CE -->
            <alias>breadcrumbsContainer</alias>
        </action>
    </reference>

    <reference name="category.products">
        <!-- Create a block from a custom local module -->
        <block type="my_module/breadcrumbs" name="my_module.breadcrumbs"/>
    </reference>
</catalog_category_layered>

All we do here in the layout is unsetting the original breadcrumbs block (rather than removing it) and adding a my_module.breadcrumbs block to the category.products.

Code of My_Module_Block_Breadcrumbs

class My_Module_Block_Breadcrumbs extends Mage_Catalog_Block_Breadcrumbs
{
    protected function _prepareLayout()
    {
        // Create a breadcrumbs block in order to parent::_prepareLayout to do its job
        $this->getLayout()->createBlock(
            'page/html_breadcrumbs',
            'breadcrumbs',
            array('template' => 'page/html/breadcrumbs.phtml')
        );

        return parent::_prepareLayout();
    }


    protected function _toHtml()
    {
        return $this->getLayout()->getBlock('breadcrumbs')->toHtml();
    }
}

The idea of this code is to recreate the missing breadcrumbs block that we removed in layout. As soon as this breadcrumbs block exists, Mage_Catalog_Block_Breadcrumbs::_prepareLayout can work! And it will then create the breadcrumbs properly without the need for us to recode it.

At last we create the _toHtml() method in which we retrieve the breadcrumbs block that is now populated and spit its HTML content.

Last thing to do is call our my_module.breadcrumbs block in the right template file.

In your theme's catalog/category/view.phtml file

As stated in catalog.xml core layout files, the template used for the category.products reference we use in our layout file above is catalog/category/view.phtml. So all we have to do is render the HTML of the my_module.breadcrumbs in this template.

...
<?php echo $this->getChildHtml('my_module.breadcrumbs'); ?>
...
Share:
22,151
Jinal Dabhi
Author by

Jinal Dabhi

Updated on July 22, 2022

Comments

  • Jinal Dabhi
    Jinal Dabhi over 1 year

    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 ?

  • Jinal Dabhi
    Jinal Dabhi over 9 years
    I did this. But it's not working. I put xml code in catalog.xml file. Do I need to put it in page.xml file ?
  • Jinal Dabhi
    Jinal Dabhi over 9 years
    what have you changed ? And where do I put local.xml file ?
  • Rajeev K Tomy
    Rajeev K Tomy over 9 years
    This won't work @AmitBera . Take a look on my answer.
  • Jinal Dabhi
    Jinal Dabhi over 9 years
    If I user your module, everything will be set automatically ? or I need to change anything than ?
  • Rajeev K Tomy
    Rajeev K Tomy over 9 years
    yes you need to do one thing. You need to call my breadcrumbs block like this . <?php echo $this->getChildHtml('category_breadcrumbs'); ?> in your category/view.phtml
  • Jinal Dabhi
    Jinal Dabhi over 9 years
    Still it's not working. I have added in view.phtml page.
  • Rajeev K Tomy
    Rajeev K Tomy over 9 years
    i have developed and checked it in my system and it works fine
  • Jinal Dabhi
    Jinal Dabhi over 9 years
    It works now. Thank you very much. I have cleared cache and reindex data and suddenly it's working now.
  • Rajeev K Tomy
    Rajeev K Tomy over 9 years
  • Jinal Dabhi
    Jinal Dabhi over 9 years
    It was not working. And I installed your script. Your script works fine. Now if I want to use same script on product/list.phtml, what I need to do? Only needs to put getChildHtml code there, right ?
  • Jinal Dabhi
    Jinal Dabhi over 9 years
    This is wokring great.
  • Carlos Faria
    Carlos Faria about 8 years
    Best explanation I've seen on stackoverflow of a Magento related issue. Should be the accepted solution. Amit's one doesn't work at all.
  • Rajeev K Tomy
    Rajeev K Tomy about 8 years
    @CarlosFaria Thanks. Glad to help you out.