This question is about following Magento2 best practices.

I had to rewrite \Magento\Theme\Block\Html\Topmenu::_addSubMenu() method in order to add some wrappers around elements. Now, because it's a protected method, my understanding is that I have to use preference feature:

<preference for="Magento\Theme\Block\Html\Topmenu" type="MyCompany\Theme\Block\Html\Topmenu" />

and add a class with my rewrites:


namespace MyCompany\Theme\Block\Html;

class Topmenu extends \Magento\Theme\Block\Html\Topmenu
    protected function _addSubMenu($child, $childLevel, $childrenWrapClass, $limit)
        // my stuff

Although the default class got rewritten, on the next page reload I got the following error:

main.CRITICAL: Invalid template file: 'html/topmenu.phtml' in module: 'MyCompany_Theme' block's name: 'catalog.topnav' [] []

Magento is trying to find html/topmenu.phtml under my extension and not under Magento_Theme. I do understand that this is correct behaviour, but I was thinking about practical aspects of this. Does this mean that whenever we rewrite a block, we need to rewrite its template too, even if we don't necessarily need to touch anything HTML related?

One way around this would be to rewrite _toHtml() method too, like this:

protected function _toHtml()
    return parent::_toHtml();

Now, Magento is looking into Magento_Theme module for the template file again. But, this looks like a hack to me.

So, my question is: what is a recommendation in this situations? Should we always copy relevant template when rewritting block class, or the workaround is fine? Is there a better approach for this?


2 Answers 2


Since there are discussions around the proposed solution in pull request (https://github.com/magento/magento2/pull/1895), meanwhile you just need to "pin" original template when do change of original block class name:

<referenceBlock name="catalog.topnav" class="***" template="Magento_Theme::html/topmenu.phtml"/>
  • This is a good suggestion, although for certain blocks it would be impractical at best since it's used in so many layouts (Catalog\Block\Product\View). I think the OP's suggestion is still the best solution for that instance.
    – Erfan
    Commented Feb 25, 2017 at 7:00

you just need to add one code in this file



<referenceBlock name="catalog.topnav" class="Company_name\Override\Block\Html\Topmenu" template="Magento_Theme::html/topmenu.phtml"/>

and add below code in your override module file name :


code :

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd">
    <preference for="Magento\Theme\Block\Html\Topmenu" type="Company_name\Override\Block\Html\Topmenu" />
    <preference for="Magento\Paypal\Model\Config" type="Company_name\Override\Model\Paypal\Config" />

Add Topmenu.php file in File : app/code/Company_name/Override/Block/Html/Topmenu.php you can add whatever function you want to override.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.