Custom category menu navigation in Magento

Magento has its top menu reserved for category navigation. It’s pretty solid for displaying categories, even when there is a large number of them.
What some of the clients want is a vertical (sidebar) category menu, so they can display sibling categories of a category their customers are exploring.
In this article we’ll cover the creation of a full vertical menu. We’ll go 3 levels deep: category, subcategory, and sub-subcategory. You can always expand on this, but I believe 3 levels are more than enough for most stores.
The layout
Open app/design/frontend/base/default/layout/page.xml or your theme’s equivalent.
Place the following code under default tag:
<reference name="right">
<block type="core/template" name="catalog.sidenav" template="page/custom.phtml" before="cart_sidebar"/>
</reference>
This will tell Magento to load our template on each page that sports a layout with a right column.
Now, let’s create our template file.
The template
What we need to do is go through all of the store’s categories, get their subcategories (2nd level), sub-subcategories (3rd level) and display them. In the process we need to look for a case when the ID of the category in our list matches the ID of a current category. When we find it – we’ll make it bold.
Create app/design/frontend/base/default/template/page/custom.phtml with the following content:
<ul>
<?php
$obj = new Mage_Catalog_Block_Navigation();
$storeCategories = $obj->getStoreCategories();
Mage::registry('current_category') ? $currentCategoryId = Mage::registry('current_category')->getId() : $currentCategoryId='';
foreach ($storeCategories as $_category):
?>
<li>
<strong><?php echo $_category->getName(); ?></strong>
<?php $categoryChildren = $_category->getChildren(); ?>
<?php if($categoryChildren->count()) : ?>
<ul>
<?php foreach($categoryChildren as $_categoryChild) : ?>
<?php $_categoryChildModel = Mage::getModel('catalog/category')->load($_categoryChild->getId());?>
<?php $categoryGrandchildren=$_categoryChild->getChildren(); ?>
<li>
<?php
$currentCategoryId===$_categoryChild->getId() ? $bold="style=\"font-weight:bold\"" : $bold='';
echo ' ' . '<a href="' . $_categoryChildModel->getUrl() . '"' . $bold . '>' . $_categoryChild->getName() . '(' . $_categoryChildModel->getProductCollection()->count() . ')</a>';
?>
</li>
<?php if($categoryGrandchildren->count()) : ?>
<?php foreach($categoryGrandchildren as $_categoryGrandchild) : ?>
<?php $_categoryGrandchildModel = Mage::getModel('catalog/category')->load($_categoryGrandchild->getId());?>
<li>
<?php
$currentCategoryId===$_categoryChild->getId() ? $bold="style=\"font-weight:bold\"" : $bold='';
echo '  ' . '<a href="' . $_categoryGrandchildModel->getUrl() . '"' . $bold . '>' . $_categoryGrandchild->getName() . '(' . $_categoryGrandchildModel->getProductCount() . ')</a>';
?>
</li>
<?php endforeach; ?>
<?php endif; ?>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</li>
<?php endforeach ?>
</ul>
The result
Et voilà! You should be able to see the navigation on the right column of your page. It’s not exactly the prettiest list, but I trust you’ll be able to style it to suit your needs.
You can also insert this template to any other page by coding a layout update or via admin, by inserting this line as content of your CMS page:
{{block type="core/template" template="page/custom.phtml"}}
Download zipped source or take a look at it on GitHub.
Note: This is a revamp of the article originally written in January 2009.
In case all of this sounds amazing and you simply want to improve current state of your Magento shop, we can create a detailed customized report based on our Magento Technical Audit! Feel free to contact us.
16 comments
i want remove the link form navigation not from top links in magento now the link name is shop online.
I want to show main category images can you please help me
getStoreCategories(false, true, false) ?>
I am using this to get current category…
My question is that Can i set the subcategory level 1 to all its sub-category pages
i.e.
Category1
category1.1
category1.2
category1.3
when ever i select any sub-category like category1.1..i want to show Category1 on top and category1.1, category1.2, category1.3 as dropdown of it.
and what if i want only furniture category from that
I have this code and it works fine but i’d like to have a responsive accordion menu using this script but cannot get it working, can anyone let me know how I would get this script working as a accordion menu?
Thankyou
If you are looking for vertical navigation in Magento admin – check this article -http://nwdthemes.com/2015/06/18/how-to-create-vertical-navigation-menu-in-magento-admin/
How would you insert a menu into a custom 1 column layout. Basically what I’m looking to do is have a left hand menu right next to the product grid all housed in the same container so I can utilize bootstrap to tie it all together.
HI SIR,
GOOD ARTICLE .YOUR ALL ARTICLE IS VERY HELPFUL TO LEARN MORE ABOUT MAGENTO YOUR TEAM IS AWESOME.
I PUT YOUR CODE INTO LEFT NAVIGATION
BUT WHEN I SET “IS ADD TO TOP MENU === NO” FROM ADMIN THEN CATEGORY WILL ALSO HIDE FORM LEFT CATEGORY
ANY SOLUTION FOR THIS?
I WANT IF I SELECT “IS ADD TO TOP MENU= NO” THEN IT WILL DISABLE FROM TOP MENU BUT VISIBLE IN LEFT NAVIGATION
THANK YOU IN ADVANCE
How would you modify your script to allow linking to the top level cat? Tried getUrl(); ?> and doesn’t work. Thank you
Thank you for this simple manual!
I’m using the RWD theme so I wanted to keep the functionality of the responsive menu but still wanted to have a vertical menu for large screens. So I enden up by just hiding the #header-nav by setting “display” to “none” and inserting the code from this page.
Hello!
Does loading the model of each child category impact the speed if there are many categories?
Or is loading a model not so time consuming?
Thank you.
Thank you very much it worked.
Hi
Thank you. But this is applicable for two level of categories. How to display unlimited level of categories?
Any idea?
thank you very much it worked like a champ !! you saved my day
Hi Dan,
I agree that this probably isn’t the best method.
Another way would be to instantiate the block in template without ‘new’ operator by replacing $obj with
The best to way would probably be to create your own block that extends on Mage_Catalog_Block_Navigation and include that block in the layout instead.
Keep in mind that this is proof-of-concept code. I don’t expect Magento developers to just copy/paste this (although it would work), but to take it as a base and improve it (like you did :))
Hi Peter,
don’t think that instancing blocks in template and using new operator is the way to go when coding for Magento, but that’s just me.