In this post, we will see how we can create a category menu.
First, we need to have our module and theme ready. Please follow the links below if you haven’t created them yet.
Now, we will create a new block named Menu.php in the following location:
app/code/Mymodule/Test/Block/Menu.php
Add following code to this file:
<?php namespace Mymodule\Test\Block; use Magento\Framework\View\Element\Template; use Magento\Catalog\Helper\Category; use Magento\Framework\View\Element\Template\Context; use Magento\Catalog\Model\Indexer\Category\Flat\State; class Menu extends Template { protected $_categoryHelper; protected $categoryFlatConfig; public function __construct( Category $categoryHelper, State $categoryFlatState, Context $context ){ $this->_categoryHelper = $categoryHelper; $this->categoryFlatConfig = $categoryFlatState; parent::__construct($context); } public function getRootCategories(){ $categories = $this->_categoryHelper->getStoreCategories(true, false, true); return $categories; } public function getSubCategories($category) { if ($this->categoryFlatConfig->isFlatEnabled() && $category->getUseFlatResource()) { $subCategories = (array)$category->getChildrenNodes(); } else { $subCategories = $category->getChildren(); } return $subCategories; } public function getCategoryUrl($category){ return $this->_categoryHelper->getCategoryUrl($category); } }
Now, add following reference to your default.xml in your theme:
<referenceContainer name="header.container"> <container name="common-header" label="Header common to all pages" as="common-header" htmlTag="div" htmlClass="main-header"> <block class="Mymodule\Test\Block\Header" template="header.phtml"> <block name="header.menu" class="Mymodule\Test\Block\Menu" template="menu.phtml"/> </block> </container> </referenceContainer>
Here, we added menu.phtml as the child of header.phtml. To render(show) our menu, we can write following line anywhere inside our header.phtml:
<?php $categoriesLevel0 = $this->getRootCategories(); if($categoriesLevel0) { echo "<ul>"; foreach ($categoriesLevel0 as $categoryLevel0) { ?> <li><a href="<?php echo $this->getCategoryUrl($categoryLevel0); ?>" class="menu-heading"><?php echo $categoryLevel0->getName(); ?></a> <?php $categoriesLevel1 = $this->getSubCategories($categoryLevel0); if ($categoriesLevel1) { echo "<ul>"; foreach ($categoriesLevel1 as $subCategoryLevel1) { echo "<li><a href='" . $this->getCategoryUrl($subCategoryLevel1) . "'>" . $subCategoryLevel1->getName() . "</a>"; $categoriesLevel2 = $this->getSubCategories($subCategoryLevel1); if ($categoriesLevel2) { echo "<ul>"; foreach ($categoriesLevel2 as $subCategoryLevel2) { echo "<li><a href='" . $this->getCategoryUrl($subCategoryLevel2) . "'>" . $subCategoryLevel2->getName() . "</a></li>"; } echo "</ul>"; } echo "</li>"; } echo "</ul>"; } echo "</li>"; } echo "</ul>"; }
Great. Thank you. What needs to be done to get access to other category information like description and image? Regards Petra
As someone very new to Magento this was a very good and easy to understand tutorial in regards to setting up a module, however this code did not output the store categories for me. The code executes and there are no errors but the foreach outputs nothing. Something is missing here, or I am missing something. Thank you for posting this though, I learned some things regardless.
Hello,
Thanks for this, it seems to work very fine, but each time I do bin/magento setup:di:compile I get a blank page on frontend.
The log gives me :
PHP Fatal error: Uncaught TypeError: Argument 1 passed to Mymodule\\Test\\Block\\CategoriesMenu::__construct() must be an instance of Magento\\Catalog\\Helper\\Category, instance of Magento\\Framework\\ObjectManager\\ObjectManager given, called in /var/www/vhosts/my-domain.com/httpdocs/vendor/magento/framework/ObjectManager/Factory/AbstractFactory.php on line 93 and defined in /var/www/vhosts/my-domain.com/httpdocs/app/code/Mymodule/Test/Block/Menu.php:15
bin/magento setup:upgrade gets the website working again.
Any idea on what could be wrong here please ?
Best regards