Dodanie linku bez kategorii do łączy nawigacyjnych w magento 2

29

Nie jestem pewien, co robię źle tutaj. Blok, w którym znajdują się linki kategorii, jest nazywany sekcją navigation.section. Myślałem, kierując następujące argumenty w stronę kontenera, że ​​będę mógł utworzyć pod nim nowy link. Każda pomoc jest mile widziana.

<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>
o tym wie
źródło
Zastanawiam się nad tym samym ... Czy znalazłeś rozwiązanie?
Oba wymienione rozwiązania działały dla mnie.
themanwhoknowstheman
Nad którą wersją Magento pracujesz?
Razvan Zamfir

Odpowiedzi:

34

[EDYCJA]
Najwyraźniej w najnowszych wersjach M2 to już nie działa.
Dzięki Max za zwrócenie na to uwagi.
W nowszej wersji musisz dodać wtyczkę Magento\Theme\Block\Html\Topmenuzamiast obserwatora.
Dodaj to doetc/frontend/di.xml

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

i utwórz plik klasy wtyczki [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)
        ];
    }
}

[/ EDYCJA]
Oryginalna odpowiedź:
Możesz dodać elementy do górnego menu za pomocą zdarzenia page_block_html_topmenu_gethtml_before.

Musisz więc utworzyć moduł z tymi plikami (wszystkie pliki powinny znajdować się w app/code/[Namespace]/[Module]):

etc/module.xml - plik deklaracji modułu

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

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

etc/frontend/events.xml - plik deklaracji zdarzeń

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

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

Teraz uruchom w cli, php bin/magento setup:upgradeaby zainstalować moduł i możesz zacząć.

Marius
źródło
Czy w Topmenu.php brakuje części kodu?
themanwhoknowstheman
1
@Solide. Kolejność linków zależy od kolejności wykonywania obserwatorów. Jeśli Twój obserwator strony głównej jest wykonywany przed katalogiem, najpierw należy dodać link do strony głównej. Jeśli nie, możesz rzucić okiem na to podejście do zmiany kolejności linków: magento.stackexchange.com/q/7329/146 . podejście dotyczy Magento1, ale można go przetłumaczyć na kod M2.
Marius
1
@Marius: co powinno być 'is_active'. Dodaj przykład. Chcę aktywny link na tej stronie.
Zed Blackbeard
1
Obserwator jest używany podczas zdarzenia. Wtyczka może działać na dowolnej publicznej metodzie. Radziłbym skorzystać z wtyczki, ponieważ ta jest używana w rdzeniu, aby dodać kategorie do górnego menu.
Marius
1
Przepraszam, czuję się jak idiota, ale jak dodać więcej niż jedno menu? Jeśli użyję $menu->addChild($node)więcej niż jeden raz, ostatni z nich zastąpi pozostałe. Pokazuje tylko jedno menu (ostatnie).
pinicio
17

Dlaczego wszyscy zawsze chcą napisać moduł. Zrobiłem to w sobie layout.xmli działało to jak urok:

    <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
źródło
jak otworzyć ten link w nowej karcie?
jafar pinjar
Dobre pytanie. Znaleziono coś w kodzie. Może spróbuj: <argument name = "atrybuty" xsi: type = "array"> <item name = "target" xsi: type = "string"> _ blank </item> </argument> Nie przetestowano, ale jest dostępna opcja atrybutów.
Johnny Longneck,
Utworzenie modułu czyni go znacznie bardziej dynamicznym. Wielu klientów, z którymi współpracuję, chce robić rzeczy samodzielnie, w tym przypadku tworząc strony i dodając ich do menu głównego w określonej kolejności.
Roy Jeurissen
6

Innym rozwiązaniem poza tworzeniem modułu jest zastąpienie topmenu.phtml. Zauważę, że rozwiązanie dostarczone przez @Marius jest najlepszym sposobem na zrobienie tego, jeśli twoje linki mają odziedziczyć klasy nawigacyjne. To pokazuje się w mobilnym menu Magento, tylko bez odpowiedniego css. Możesz użyć argumentu css_class do odpowiedniego stylu.

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>
o tym wie
źródło
Gdzie mogę znaleźć przykład argumentu klasy css?
camdixon
jak połączyć plik szablonu z plikiem xml ..
Sarvesh Tiwari
6

Ta odpowiedź pochodzi od Mariusza ♦ Właśnie ją zmodyfikowałem, aby dodać kategorię podrzędną w menu zakładki kategorii, do której możesz odnieść odpowiedź Mariusa ♦. Właśnie zmodyfikowałem podrzędny plik Topmenu.php, aby dodać kategorię podrzędną do głównej kategorii

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

Musisz utworzyć węzeł dla kategorii nadrzędnej i kategorii podrzędnej, a następnie możesz przypisać kategorię podrzędną do kategorii nadrzędnej za pomocą metody addChild. Oto przykład

$contactsNode->addChild($warrantyRegistrationNode);
Vaibhav Ahalpara
źródło
Dzięki! nie zdawałem sobie sprawy, że tak łatwo było dodać podmenu!
Juliano Vargas,
i Sir, jeśli chcę pokazać mój niestandardowy div na niestandardowym linku, który dodałem Topmenu. Jak kiedy najecham myszką na link, pokazuje mój niestandardowy div
Asad Khan
1

Korzystając z powyższej odpowiedzi Mariusza, dodałem pozycje podmenu. Pokazuję także sposób edycji drzewa przed utworzeniem HTML, a następnie sposób edycji HTML bezpośrednio po jego utworzeniu. Działa w Magento 2.1. Zaktualizuj Topmenu.php o:

<?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
źródło
1

Chcesz dodać link do górnej nawigacji w sekcji <header>
Dodawanie linku do strony CMS, Galeria

Edytuj / Umieść default.xml tutaj:

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

Dodaj następujący kod:

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

Dodaje to link do strony CMS, Galerii, z następującymi ustawieniami:

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

Dodaj następującą stylizację, aby zapewnić prawidłowe wyrównanie nowego łącza:

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

Wyniki kodu (Produkty są ustawione jako kategoria na przykład)

Joshua34
źródło
0

Dla tych, którzy chcą dodać is_activewyraz, szczególnie @zed Czarnobrody, który pytał powyżej.

Kiedyś łączyłem kontakt i będzie on również działał z niestandardowym modułem, ponieważ łączę się z jednym.

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

// (wyrażenie określające, czy element menu jest wybrany, czy nie)

Mam nadzieję, że to pomoże każdemu.

Juliano Vargas
źródło
0

Jest to również dobra opcja:

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
źródło
-1

Tylko dla łącza menu nawigacyjnego nie ma wiele kroków do osiągnięcia, znalazłem krótki samouczek na ten temat, sugeruje motyw, który zastępuje topmenu.phtmlplik z Magento_Thememodułu: https://linkstraffic.net/adding-custom- menu-item-inside-magento2 / Udało mi się to przetestować, więc udostępniam wam.

Jimmy
źródło
Witamy w Magento SE. Jeśli zamieszczasz linki w odpowiedzi, upewnij się, że odpowiedź jest nadal cenna, jeśli link kiedyś się zepsuje: na przykład streść powiązany artykuł lub podaj odpowiednie części. Jest to ważne, ponieważ StackExchange ma być bazą wiedzy, a nie forum wsparcia, które pomaga obecnie jednej osobie. Przyszli goście powinni nadal korzystać z pytań i odpowiedzi.
Siarhey Uchukhlebau