3

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

3

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;
    }
}
  • great tip, it's definitely a more readable approach than using php plugins here - thanks! A link is visible in top links menu but I am still not sure how to add content (submenu) which will be visible on hover. I found _addSubMenu function in Magento\Theme\Block\Html\Topmenu but I don't now how to use it correctly with created observer. Do you have any idea? – Rob Feb 7 '18 at 8:58
  • Do you also want to add child menus to it?I haven't tried adding child menus though but you can try adding submenus like $node->addChild($childNode); the $childnode can be created similar to how $node was created. Refer this class Magento\Framework\Data\Tree\Node for method definition and other tweaks – Shireen N Feb 7 '18 at 9:04
  • ok - got it, I will try, but do you have any idea how to add a child, node with html content which will be presented instead of the simple link? – Rob Feb 7 '18 at 9:33
  • It is possible to do that but it will take time to develop. Why don't you check this free extension if it suits your requirement - store.ibnab.com/free-magento-2-easy-megamenu.html – Shireen N Feb 7 '18 at 9:36
  • already I am working with custom top menu implementation so using next extension here will be problematic to maintain. Anyway, your answer with comments help me a lot and cover my question - thanks once again! I will try to update a bit _getHtml function in Magento\Theme\Block\Html\Topmenu to reach own goal :) – Rob Feb 7 '18 at 9:49
0

The simple way to do this is here given below. For example Here I am using Solwin/freego theme so I have to navigate

/httpdocs/app/design/frontend/Solwin/freego/Magento_Theme/templates/html/topmenu.phtml (it might be different in your case)

And here I can add as much as the menu I want with a Home link

<?php
/**
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
// @codingStandardsIgnoreFile
?>
<?php
/**
 * Top menu for store
 *
 * @see \Magento\Theme\Block\Html\Topmenu
 */
?>
<?php $columnsLimit = $block->getColumnsLimit() ? : 0; ?>
<?php $_menu = $block->getHtml('level-top', 'submenu', $columnsLimit) ?>
<?php
$helper = $this->helper( 'Solwin\Cpanel\Helper\Data' );
$baseUrl = $helper->getBaseUrl();
$curr_Url = $helper->getCurrentUrl();
$ishome = $helper->getIsHomePage();
$showhomelink = $helper->getEnablehomelink();
?>

<nav class="navigation" role="navigation">
    <ul data-mage-init='{"menu":{"responsive":true, "expanded":true, "position":{"my":"left top","at":"left bottom"}}}'>
        <?php if ($showhomelink) { ?>
        <li class="level0 level-top <?php if ($ishome) { ?> active <?php } ?>">
            <a class="level-top" href="<?php echo $baseUrl; ?>">
                    Home
                </a>
        </li>
        <?php } ?>
        <li class="level0 level-top">
            <a class="level-top" href="<?php echo $baseUrl; ?>about-us">
                    About us
                </a>
        </li>
        <?php /* @escapeNotVerified */ echo $_menu; ?>
        <li class="level0 level-top">
            <a class="level-top" href="<?php echo $baseUrl; ?>faqs">
                    FAQs
                </a>

        </li>
        <li class="level0 level-top">
            <a class="level-top" href="<?php echo $baseUrl; ?>contact-us">
                    Contact Us
                </a>
        </li>
        <li class="level0 level-top">
            <a class="level-top" href="<?php echo $baseUrl; ?>account">
                    My Account
                </a>
        </li>
    </ul>
</nav>
  • It's such a bad approach to put application logic into views. It's hard to maintain and extend, it's imposible to debugging and finally it's breaching of any coding standarts. – Kirill Jan 18 at 13:18
-1

How can we move cms link at the beginning of the menu? Is it possible to add home link in front of all other links? On line 228, vendor/magento/module-theme/Block/Html/Topmenu.php there is a method $child->setIsFirst($counter == 1);, but it does not work.

  • Please add answers in the answer section. To ask a question create a separate thread. – Ghulam.M May 7 at 9:44
  • @Ghulam.M I thought it is related to this question suggested by StackExchange. Can you answer my question here? – Biswajit Paul May 8 at 11:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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