Frage

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

War es hilfreich?

Lösung

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;
    }
}

Andere Tipps

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>

We can achieve this goal by overwrite default Magento file vendor/magento/module-theme/view/frontend/templates/html/topmenu.phtml. But this is not good practice by making changes in default Magento functionality. We will use the plugin to implement this.

Step -1 We have to create app/code/VendorName/ModuleName/etc/di.xml file where we will define our plugin.

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <!-- Add Plugin for add custom link in navigation -->
    <type name="Magento\Theme\Block\Html\Topmenu">
        <plugin name="add_menu_item_plugin" type="VendorName\ModuleName\Plugin\Topmenu" sortOrder="10" disabled="false"/>
    </type>
</config>

Step -2 Now we have to create app/code/VendorName/ModuleName/Plugin/Topmenu.php

<?php

namespace Test\TestCustomMenu\Plugin;

class Topmenu
{
    /**
     * @param Context $context
     * @param array $data
     */
    public function __construct(
        \Magento\Customer\Model\Session $session
    ) {
        $this->Session = $session;
    }


    public function afterGetHtml(\Magento\Theme\Block\Html\Topmenu $topmenu, $html)
    {
        $swappartyUrl = $topmenu->getUrl('testCustomMenu/custommenu'); //here you can set link
        $magentoCurrentUrl = $topmenu->getUrl('*/*/*', ['_current' => true, '_use_rewrite' => true]);
        if (strpos($magentoCurrentUrl, 'testCustomMenu/custommenu') !== false) {
            $html .= "
";
        } else {
            $html .= "
";
        }
        $html .= "" . __("Custom Menu") . "";
        $html .= "
";
        return $html;
    }
}

Step -3 After adding above files please run following command :-

php bin/magento setup:di:compile
php bin/magento cache:flush

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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit magento.stackexchange
scroll top