Hinzufügen eines Links, der keine Kategorie ist, zu den Navigationslinks in Magento 2

29

Ich bin nicht sicher, was ich hier falsch mache. Der Block, in dem sich die Kategorielinks befinden, wird als navigation.sections bezeichnet. Ich dachte, indem ich die folgenden Argumente auf den Container richtete, könnte ich einen neuen Link darunter erstellen. Jede Hilfe wird geschätzt.

<referenceContainer name="navigation.sections">
            <block class="Magento\Framework\View\Element\Html\Links" name="mylink">
                    <arguments>
                        <argument name="label" xsi:type="string">Mylink</argument>
                        <argument name="path" xsi:type="string">mypath</argument>
                        <argument name="css_class" xsi:type="string">mycss</argument>
                    </arguments>
            </block>
</referenceContainer>
themanwhoknowstheman
quelle
Ich frage mich das selbe .. Hast du eine Lösung dafür gefunden?
Beide aufgeführten Lösungen haben bei mir funktioniert.
themanwhoknowstheman
An welcher Magento-Version arbeiten Sie?
Razvan Zamfir

Antworten:

34

[EDIT]
Anscheinend funktioniert dies in den neuesten Versionen von M2 nicht mehr.
Vielen Dank an Max für diesen Hinweis.
Für eine spätere Version müssen Sie Magento\Theme\Block\Html\Topmenuanstelle eines Beobachters ein Plugin für hinzufügen .
Fügen Sie dies zuetc/frontend/di.xml

<type name="Magento\Theme\Block\Html\Topmenu">
    <plugin name="[module]-topmenu" type="[Namespace]\[Module]\Plugin\Block\Topmenu" />
</type>

und erstellen Sie die Plugin-Klassendatei [Namespace]/[Module]/Plugin/Block/Topmenu.php

<?php 

namespace [Namespace]\[Module]\Plugin\Block;

use Magento\Framework\Data\Tree\NodeFactory;

class Topmenu
{
    /**
     * @var NodeFactory
     */
    protected $nodeFactory;

    public function __construct(
        NodeFactory $nodeFactory
    ) {
        $this->nodeFactory = $nodeFactory;
    }

    public function beforeGetHtml(
        \Magento\Theme\Block\Html\Topmenu $subject,
        $outermostClass = '',
        $childrenWrapClass = '',
        $limit = 0
    ) {
        $node = $this->nodeFactory->create(
            [
                'data' => $this->getNodeAsArray(),
                'idField' => 'id',
                'tree' => $subject->getMenu()->getTree()
            ]
        );
        $subject->getMenu()->addChild($node);
    }

    protected function getNodeAsArray()
    {
        return [
            'name' => __('Label goes here'),
            'id' => 'some-unique-id-here',
            'url' => 'http://www.example.com/',
            'has_active' => false,
            'is_active' => false // (expression to determine if menu item is selected or not)
        ];
    }
}

[/ EDIT]
Ursprüngliche Antwort:
Sie können dem Hauptmenü mithilfe des Ereignisses Elemente hinzufügen page_block_html_topmenu_gethtml_before.

Sie müssen also ein Modul mit diesen Dateien erstellen (alle Dateien sollten sich in befinden app/code/[Namespace]/[Module]):

etc/module.xml - die Moduldeklarationsdatei

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

registration.php - die Registrierungsdatei

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

etc/frontend/events.xml - die Ereignisdeklarationsdatei

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

Observer/Topmenu.php - der tatsächliche Beobachter

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

Führen Sie nun das CLI aus php bin/magento setup:upgrade, um das Modul zu installieren, und Sie können loslegen .

Marius
quelle
Fehlt Topmenu.php Teil des Codes?
themanwhoknowstheman
1
@Solide. Die Reihenfolge der Links hängt von der Reihenfolge ab, in der die Beobachter ausgeführt werden. Wenn Ihr Homepage-Beobachter vor dem Katalog ausgeführt wird, sollte zuerst der Homepage-Link hinzugefügt werden. Wenn nicht, können Sie sich diesen Ansatz ansehen, um die Reihenfolge der Links zu ändern : magento.stackexchange.com/q/7329/146 . Der Ansatz ist für Magento1, aber Sie können ihn in M2-Code übersetzen.
Marius
1
@Marius: was soll das sein 'is_active'. Bitte fügen Sie ein Beispiel hinzu. Ich möchte einen aktiven Link auf dieser Seite.
Zed Blackbeard
1
Ein Beobachter wird für ein Ereignis verwendet. Ein Plugin kann auf jeder öffentlichen Methode funktionieren. Ich würde empfehlen, den Plugin-Ansatz zu verwenden, da dieser im Kern verwendet wird, um die Kategorien zum oberen Menü hinzuzufügen.
Marius
1
Entschuldigung, ich fühle mich wie ein Idiot, aber wie kann man mehr als ein Menü hinzufügen? Wenn ich $menu->addChild($node)mehr als einmal benutze , überschreibt der letzte die anderen. Es wird nur ein Menü angezeigt (das letzte).
Pinicio
17

Warum wollen alle immer ein Modul schreiben? Ich habe das in meinem gemacht layout.xmlund es hat wie ein Zauber funktioniert:

    <referenceBlock name="catalog.topnav">
        <block class="Magento\Framework\View\Element\Html\Link" name="contact-link">
            <arguments>
                <argument name="label" xsi:type="string" translate="true">Contact us</argument>
                <argument name="path" xsi:type="string" translate="true">contact</argument>
            </arguments>
        </block>
    </referenceBlock>
Johnny Longneck
quelle
Wie öffne ich diesen Link in einem neuen Tab?
Jafar Pinjar
Gute Frage. Hab was im Code gefunden. Versuchen Sie Folgendes: <argument name = "attributes" xsi: type = "array"> <item name = "target" xsi: type = "string"> _ blank </ item> </ argument> Nicht getestet, aber es gibt das Attributoption verfügbar.
Johnny Longneck
Das Erstellen eines Moduls macht es viel dynamischer. Viele Kunden, mit denen ich arbeite, möchten Dinge selbst erledigen, wie in diesem Fall Seiten erstellen und sie in einer bestimmten Reihenfolge zum Top-Menü hinzufügen.
Roy Jeurissen
6

Eine andere Lösung außerhalb des Erstellens eines Moduls ist das Überschreiben von topmenu.phtml. Ich werde bemerken, dass die von @Marius bereitgestellte Lösung der beste Weg ist, dies zu tun, wenn Sie beabsichtigen, dass Ihre Links die Navigationsklassen erben. Dies wird im mobilen Menü von Magento angezeigt, nur ohne das richtige CSS. Sie können das Argument css_class verwenden, um eine entsprechende Formatierung vorzunehmen.

YourTheme / Magento_Theme / templates / html / topmenu.phtml

<?php $columnsLimit = $block->getColumnsLimit() ?: 0; ?>
<?php $_menu = $block->getHtml('level-top', 'submenu', $columnsLimit) ?>

<nav class="navigation" role="navigation">
    <ul data-mage-init='{"menu":{"responsive":true, "expanded":true, "position":{"my":"left top","at":"left bottom"}}}'>
        <?php /* @escapeNotVerified */ echo $_menu; ?>
        <?php echo $block->getChildHtml() ?>
    </ul>
</nav>

YourTheme / Magento_Theme / layout / default.xml

<referenceContainer name="catalog.topnav">
               <block class="Magento\Framework\View\Element\Html\Link\Current" name="your.link">
                    <arguments>
                        <argument name="label" xsi:type="string">Link-name</argument>
                        <argument name="path" xsi:type="string">Link-url</argument>
                    </arguments>
              </block>
</referenceContainer>
themanwhoknowstheman
quelle
Wo finde ich ein Beispiel für das CSS-Klassenargument?
Camdixon
Wie verknüpfen Sie Template-Datei mit XML-Datei ..
Sarvesh Tiwari
6

Diese Antwort wurde von Marius bereitgestellt. ♦ Ich habe sie soeben geändert, dass sie eine untergeordnete Kategorie im Menü der Registerkarte Kategorie hinzufügt. Sie können auf die Antwort von Marius verweisen. Ich habe gerade die untergeordnete Datei Topmenu.php geändert, um eine untergeordnete Kategorie in der Hauptkategorie hinzuzufügen

<?php 

namespace Ktpl\Navigationlink\Plugin\Block;

use Magento\Framework\UrlInterface;
use Magento\Framework\Data\Tree\NodeFactory;
use Magento\Store\Model\StoreManagerInterface;

class Topmenu
{
    /**
     * @var NodeFactory
     */
    protected $nodeFactory;
    protected $urlBuilder;
    protected $_storeManager;

    public function __construct(
        UrlInterface $urlBuilder,
        NodeFactory $nodeFactory,
        StoreManagerInterface $storeManager
    ) {
        $this->urlBuilder = $urlBuilder;
        $this->nodeFactory = $nodeFactory;
        $this->_storeManager = $storeManager;
    }

    public function beforeGetHtml(
        \Magento\Theme\Block\Html\Topmenu $subject,
        $outermostClass = '',
        $childrenWrapClass = '',
        $limit = 0
    ) {
        // condition for store
        if($this->getStoreCode() == 'store_id'):
        $productNode = $this->nodeFactory->create(
            [
                'data' => $this->getNodeAsArray('Products','products'),
                'idField' => 'id',
                'tree' => $subject->getMenu()->getTree()
            ]
        );
        $stockistsNode = $this->nodeFactory->create(
            [
                'data' => $this->getNodeAsArray('Stockists','stockists'),
                'idField' => 'id',
                'tree' => $subject->getMenu()->getTree()
            ]
        );
        $ourstoryNode = $this->nodeFactory->create(
            [
                'data' => $this->getNodeAsArray('Our Story','ourstory'),
                'idField' => 'id',
                'tree' => $subject->getMenu()->getTree()
            ]
        );
        $contactsNode = $this->nodeFactory->create(
            [
                'data' => $this->getNodeAsArray('Customer Care','contacts'),
                'idField' => 'id',
                'tree' => $subject->getMenu()->getTree()
            ]
        );
        /******* contacts's child *******/
        $warrantyRegistrationNode = $this->nodeFactory->create(
            [
                'data' => $this->getNodeAsArray('Warranty Registration','warranty-registration'),
                'idField' => 'id',
                'tree' => $subject->getMenu()->getTree()
            ]
        );
        $faqNode = $this->nodeFactory->create(
            [
                'data' => $this->getNodeAsArray('Frequently Asked Questions','faq'),
                'idField' => 'id',
                'tree' => $subject->getMenu()->getTree()
            ]
        );
        $ourProductGuaranteeNode = $this->nodeFactory->create(
            [
                'data' => $this->getNodeAsArray('Our Product Guarantee','our-product-guarantee'),
                'idField' => 'id',
                'tree' => $subject->getMenu()->getTree()
            ]
        );
        $warrantiesNode = $this->nodeFactory->create(
            [
                'data' => $this->getNodeAsArray('Warranties, Repairs & Spare Parts','warranties-repairs-spare-parts'),
                'idField' => 'id',
                'tree' => $subject->getMenu()->getTree()
            ]
        );
        $termsNode = $this->nodeFactory->create(
            [
                'data' => $this->getNodeAsArray('Terms & Conditions','terms-and-conditions'),
                'idField' => 'id',
                'tree' => $subject->getMenu()->getTree()
            ]
        );
        $privacyPolicyNode = $this->nodeFactory->create(
            [
                'data' => $this->getNodeAsArray('Our Privacy Policy','privacy-policy'),
                'idField' => 'id',
                'tree' => $subject->getMenu()->getTree()
            ]
        );
        $bookNode = $this->nodeFactory->create(
            [
                'data' => $this->getNodeAsArray('Book A Viewing','book-a-viewing'),
                'idField' => 'id',
                'tree' => $subject->getMenu()->getTree()
            ]
        );

        $contactsNode->addChild($warrantyRegistrationNode);
        $contactsNode->addChild($faqNode);
        $contactsNode->addChild($ourProductGuaranteeNode);
        $contactsNode->addChild($warrantiesNode);
        $contactsNode->addChild($termsNode);
        $contactsNode->addChild($privacyPolicyNode);
        $contactsNode->addChild($bookNode);
        /******* end contacts's child *******/

        $subject->getMenu()->addChild($productNode);
        $subject->getMenu()->addChild($stockistsNode);
        $subject->getMenu()->addChild($ourstoryNode);
        $subject->getMenu()->addChild($contactsNode);
        endif;
    }

    protected function getNodeAsArray($name,$id)
    {
        return [
            'name' => __($name),
            'id' => $id,
            'url' => $this->urlBuilder->getUrl($id),
            'has_active' => false,
            'is_active' => false // (expression to determine if menu item is selected or not)
        ];
    }

    public function getStoreCode()
    {
        return $this->_storeManager->getStore()->getCode();
    }
}

Sie müssen einen Knoten für die übergeordnete Kategorie und die untergeordnete Kategorie erstellen. Anschließend können Sie der übergeordneten Kategorie eine untergeordnete Kategorie zuweisen, indem Sie die Methode addChild verwenden. Dies ist ein Beispiel

$contactsNode->addChild($warrantyRegistrationNode);
Vaibhav Ahalpara
quelle
Vielen Dank! wusste nicht, dass es so einfach ist, ein Untermenü hinzuzufügen!
Juliano Vargas
und Sir, wenn ich mein benutzerdefiniertes Div auf dem von mir hinzugefügten benutzerdefinierten Link anzeigen möchte Topmenu. Wie wenn ich mit der Maus über den Link schwebe, dann zeigt er meine benutzerdefinierte Div
Asad Khan
1

Unter Verwendung der obigen Antwort von Marius habe ich Untermenüpunkte hinzugefügt. Ich zeige auch, wie Sie den Baum bearbeiten können, bevor der HTML-Code erstellt wird, und wie Sie den HTML-Code direkt bearbeiten, sobald er erstellt wurde. Es funktioniert in Magento 2.1. Aktualisiere Topmenu.php mit:

<?php
namespace Seatup\Navigation\Observer;
use Magento\Framework\Event\Observer as EventObserver;
use Magento\Framework\Data\Tree\Node;
use Magento\Framework\Event\ObserverInterface;
class Topmenu implements ObserverInterface
{
    protected $_cmsBlock;

    public function __construct(
        \Magento\Cms\Block\Block $cmsBlock
    )
    {
        $this->_cmsBlock = $cmsBlock;
    }
    /**
     * @param EventObserver $observer
     * @return $this
     */
    public function execute(EventObserver $observer)
    {
        /** @var \Magento\Framework\Data\Tree\Node $menu */
        $eventName = $observer->getEvent()->getName();
        if($eventName == 'page_block_html_topmenu_gethtml_before'){
            // With the event name you can edit the tree here
            $menu = $observer->getMenu();
            $tree = $menu->getTree();
            $children = $menu->getChildren();

            foreach ($children as $child) {
                if($child->getChildren()->count() > 0){ //Only add menu items if it already has a dropdown (this could be removed)
                    $childTree = $child->getTree();
                    $data1 = [
                        'name'      => __('Menu item label here'),
                        'id'        => 'some-unique-id-here',
                        'url'       => 'url goes here',
                        'is_active' => FALSE
                    ];
                    $node1 = new Node($data1, 'id', $childTree, $child);
                    $childTree->addNode($node1, $child);
                }
            }
            return $this;
        } else if($eventName == 'page_block_html_topmenu_gethtml_after'){
            // With the event name you can edit the HTML output here
            $transport = $observer['transportObject'];

            //get the HTML
            $old_html = $transport->getHtml();

            //render the block. I am using a CMS block
            $new_output = $this->_cmsBlock->getLayout()->createBlock('Magento\Cms\Block\Block')->setBlockId('cms_block_identifier')->toHtml();
            //the transport now contains html for the group/class block
            //which doesn't matter, because we already extracted the HTML into a 
            //string primitive variable
            $new_html = str_replace('to find', $new_output , $old_html);    
            $transport->setHtml($new_html);
        }
    }
}
Cypher909
quelle
1

Möchten Sie einen Link zur oberen Navigation in hinzufügen <header>
Hinzufügen eines Links zur CMS-Seite Galerie ?

Bearbeiten / Platzieren Sie default.xml hier:

app/design/frontend/Vendor/theme/Magento_Theme/layout/default.xml

Fügen Sie den folgenden Code hinzu:

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceContainer name="catalog.topnav">
           <block class="Magento\Framework\View\Element\Html\Link\Current" name="gallery.link">
                <arguments>
                    <argument name="label" xsi:type="string">Gallery</argument>
                    <argument name="path" xsi:type="string">gallery</argument>
                </arguments>
          </block> 
       </referenceContainer>
    </body>
</page>

Dies fügt einen Link zur CMS-Seite Galerie mit den folgenden Einstellungen hinzu:

Title = Gallery
Url Key = gallery
Link = https://example.com/gallery/

Fügen Sie den folgenden Stil hinzu, um sicherzustellen, dass der neue Link korrekt ausgerichtet ist:

.navigation .nav.item {
margin: 0 10px 0 0;
display: inline-block;
position: relative;
}

Ergebnisse des Codes (Produkte ist als Kategorie für ein Beispiel eingerichtet)

Joshua34
quelle
0

Für diejenigen, die hinzufügen möchten is_active Ausdruck möchten, insbesondere @zed Blackbeard, der oben gefragt hat.

Ich habe verwendet, um den Kontakt zu verknüpfen, und es wird mit benutzerdefinierten Modul auch funktionieren, wie ich zu einem verknüpfe.

'is_active' => ($ this-> request-> getFrontName () == 'contact'? true: false)

// (Ausdruck, um zu bestimmen, ob ein Menüelement ausgewählt ist oder nicht)

Hoffe es hilft jedem.

Juliano Vargas
quelle
0

Dies ist auch eine gute Option:

app / design / frontend / Vender / yourtheme / Magento_Theme / layout / default.xml

<referenceBlock name="header.links">
    <block class="Magento\Framework\View\Element\Html\Link" name="yourlinkname" before='wish-list-link'>
        <arguments>
            <argument name="label" xsi:type="string" translate="true">yourlink</argument>
            <argument name="path" xsi:type="string" translate="true">yourlink</argument>
        </arguments>
    </block>
</referenceBlock>
Sarfaraz Bheda
quelle
-1

Nur für einen Navigationsmenü-Link sind nicht viele Schritte zu erledigen. Ich habe ein kurzes Tutorial dazu gefunden. Es impliziert ein Thema, das die topmenu.phtmlDatei aus dem Magento_ThemeModul überschreibt : https://linkstraffic.net/adding-custom- menu-item-inside-magento2 / Ich habe es erfolgreich getestet und teile es mit euch.

Jimmy
quelle
Willkommen bei Magento SE. Wenn Sie in einer Antwort Links posten, stellen Sie sicher, dass die Antwort auch dann noch wertvoll ist, wenn der Link zu einem bestimmten Zeitpunkt nicht mehr funktioniert: Fassen Sie beispielsweise den verknüpften Artikel zusammen oder zitieren Sie die relevanten Teile. Dies ist wichtig, da StackExchange eine Wissensdatenbank sein soll und kein Support-Forum, das einer Person im Moment hilft. Zukünftige Besucher sollten weiterhin von den Fragen und Antworten profitieren.
Siarhey Uchukhlebau