8

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:

<?php

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()
{
    $this->setModuleName($this->extractModuleName('Magento\Theme\Block\Html\Topmenu'));
    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?

mstojanov
  • 311
  • 4
  • 9
  • Don't have time to answer right now but i suggest you have a look at this question and the answers it might help you understand the concept: http://magento.stackexchange.com/q/112749/2380 – Raphael at Digital Pianism May 18 '16 at 19:20
  • 1
    interesting. The template could still be loaded from the original module if it would haven been prefixed with Magento_Theme::, but they did not https://github.com/magento/magento2/blob/develop/app/code/Magento/Theme/view/frontend/layout/default.xml#L69 I really wonder now if this was on purpose – David Verholen May 18 '16 at 19:25
  • @RaphaelatDigitalPianism Thanks. The thread you linked is about plugins. My scenario is different. – mstojanov May 18 '16 at 19:38
  • Yeah that's what I ended up finding once I understood what your problem was. Definitely not right sounds like a bug to me – Raphael at Digital Pianism May 18 '16 at 19:40
  • I've created an issue on GitHub addressing this problem: https://github.com/magento/magento2/issues/4564 waiting for an answer from the dev team and will make a PR if it ends up being a bug. – Raphael at Digital Pianism May 19 '16 at 07:33
  • BTW, here's a PR that fixes the issue: https://github.com/magento/magento2/pull/1895/files – Raphael at Digital Pianism May 19 '16 at 08:37

2 Answers2

4

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"/>
Vitalii K
  • 231
  • 2
  • 4
  • 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 Feb 25 '17 at 07:00
3

you just need to add one code in this file

app/design/frontend/chop/misty/Magento_Theme/layout/default.xml

with:

<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 :

app/code/Aims/Override/etc/di.xml

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" />
</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.

Thanks

Technocracker
  • 1,997
  • 1
  • 14
  • 26