Magento 2 Top Menu – How to Add Link with Content

magento2navigationtoplinkstopmenu

I am wondering how to add programmatically a new link (to main top menu in header) with submenu (custom content visible on hover – styles is not a problem).

How to achieve that, via xml or via (php) plugin?

More descriptive image below:

enter image description here

Best Answer

You can add elements to the top menu using the event page_block_html_topmenu_gethtml_before.

Step 1 - So you need to create a module with these files (all the files should be in app/code/[Namespace]/[Module]):

Step 2 - app/code/[Namespace]/[Module]/etc/module.xml - the module declaration file

<?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="[Namespace]_[Module]" setup_version="2.0.0">
        <sequence>
            <module name="Magento_Theme"/>
        </sequence>
    </module>
</config>

Step 3 - app/code/[Namespace]/[Module]/registration.php - the registration file

<?php
\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    '[Namespace]_[Module]',
    __DIR__
);

Step 4 - app/code/[Namespace]/[Module]/etc/frontend/events.xml - the events declaration file

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="page_block_html_topmenu_gethtml_before">
        <observer name="[namespace]_[module]_observer" instance="[Namespace]\[Module]\Observer\Topmenu" />
    </event>
</config>

Step 5 - app/code/[Namespace]/[Module]/Observer/Topmenu.php - the actual observer

<?php
namespace [Namespace]\[Module]\Observer;
use Magento\Framework\Event\Observer as EventObserver;
use Magento\Framework\Data\Tree\Node;
use Magento\Framework\Event\ObserverInterface;
class Topmenu implements ObserverInterface
{
    public function __construct(
        ...//add dependencies here if needed
    )
    {
    ...
    }
    /**
     * @param EventObserver $observer
     * @return $this
     */
    public function execute(EventObserver $observer)
    {
        /** @var \Magento\Framework\Data\Tree\Node $menu */
        $menu = $observer->getMenu();
        $tree = $menu->getTree();
        $data = [
            'name'      => __('Menu item label here'),
            'id'        => 'some-unique-id-here',
            'url'       => 'url goes here',
            'is_active' => (expression to determine if menu item is selected or not)
        ];
        $node = new Node($data, 'id', $tree, $menu);
        $menu->addChild($node);
        return $this;
    }
}
Related Topic