I'm trying to override the Topmenu block in Magento 2.1 but can't find any guide to do so. Everything I've found on here and elsewhere either seems to apply only to version 2.0 which appears to use a different folder structure or only has partial code examples which expects me to already know their proper context (which I don't).
My current folder structure for a custom theme is app/design/frontend/Vendor/theme_name
. Within this I have the registration, theme, and composer files as well as folders for the various modules, e.g. Magento_Theme
and Magento_Search
.
From what I understand I need to start with an etc/di.xml
file like below, edited from here:
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Magento\Theme\Block\Html\Topmenu" type="[Namespace]\[Module]\Block\Html\Topmenu" />
</config>
I also understand that the next step is to add a Block/Html/Topmenu.php
file like the below (again edited from the above source):
namespace [Namespace]\[Module]\Block\Html;
class Topmenu extends \Magento\Theme\Block\Html\Topmenu
{
protected function _addSubMenu($child, $childLevel, $childrenWrapClass, $limit)
{
}
}
However, it's not clear to me what I should use for [Namespace]
and [Module]
, or where to place these files. I've tried using the vendor and theme name, and placing the etc
and Block
folders in app/design/frontend/Vendor/theme_name
, as well as placing them in app/design/frontend/Vendor/theme_name/Magento_Theme
, amending the namespaces to Vendor\theme_name\Magento_Theme\Block\Html
, but neither have any effect.
If anyone could help explain exactly what I need to do to override the Topmenu block (and by inference any other block) in version 2.1 I would be much appreciated.
Addendum
I've attempted Khoa TruongDinh's answer but it has had no affect. I've used the following files:
app/code/Vendor/MagentoTheme/Block/Html/Topmenu.php
<?php
namespace Vendor\MagentoTheme\Block\Html;
class Topmenu extends \Magento\Theme\Block\Html\Topmenu
{
protected function _addSubMenu($child, $childLevel, $childrenWrapClass, $limit)
{
$html = '';
if (!$child->hasChildren())
{
return $html;
}
$colStops = null;
if ($childLevel == 0 && $limit)
{
$colStops = $this->_columnBrake($child->getChildren(), $limit);
}
// Added "test" class to test
$html .= '<ul class="level' . $childLevel . ' test submenu">';
$html .= $this->_getHtml($child, $childrenWrapClass, $limit, $colStops);
$html .= '</ul>';
return $html;
}
}
app/code/Vendor/MagentoTheme/composer.json
{
"name": "vendor/magento-theme",
"description": "",
"require": {
"php": "~5.5.0|~5.6.0|~7.0.0",
"magento/framework": "100.0.*"
},
"type": "magento2-module",
"version": "100.0.1",
"license": [
"OSL-3.0",
"AFL-3.0"
],
"autoload": {
"files": [ "registration.php" ],
"psr-4": {
"Vendor\\MagentoTheme\\": ""
}
}
}
app/code/Vendor/MagentoTheme/etc/di.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Magento\Theme\Block\Html\Topmenu" type="Vendor\MagentoTheme\Block\Html\Topmenu" />
</config>
app/code/Vendor/MagentoTheme/etc/module.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Vendor_MagentoTheme" setup_version="1.0.0"></module>
</config>
app/code/Vendor/MagentoTheme/registration.php
<?php
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'Vendor_MagentoTheme',
__DIR__
);
I've then removed the contents of pub/static/frontend
, var/generation
, and var/view_preprocessed
, and flushed the Magento cache. The submenu doesn't have the intended "test" class added:
<ul class="level0 submenu ui-menu ui-widget ui-widget-content ui-corner-all" role="menu" aria-expanded="false" style="display: none; top: 52.6719px; left: 487.5px;" aria-hidden="true">...</ul>
ul
to confirm that I've successfully overriden the Topmenu class.