Добавление ссылки без категории на навигационные ссылки в magento 2

29

Я не уверен, что я делаю не так здесь. Блок, в котором содержатся ссылки на категории, упоминается как navigation.sections. Я подумал, что, направив следующие аргументы в сторону контейнера, я смогу создать новую ссылку под ним. Любая помощь приветствуется.

<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
источник
Мне интересно то же самое. Вы нашли решение для этого?
Оба перечисленных решения сработали для меня.
Themanwhoknowstheman
Над какой версией Magento вы работаете?
Разван Замфир

Ответы:

34

[EDIT]
По-видимому, в последних версиях M2 это больше не работает.
Спасибо Максу за то, что указал на это.
Для более поздней версии вам нужно добавить плагин Magento\Theme\Block\Html\Topmenuвместо наблюдателя.
Добавьте это кetc/frontend/di.xml

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

и создайте файл класса плагина [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]
Оригинальный ответ:
Вы можете добавить элементы в верхнее меню, используя событие page_block_html_topmenu_gethtml_before.

Поэтому вам нужно создать модуль с этими файлами (все файлы должны быть в app/code/[Namespace]/[Module]):

etc/module.xml - файл декларации модуля

<?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 - регистрационный файл

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

etc/frontend/events.xml - файл объявления событий

<?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 - фактический наблюдатель

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

Теперь запустите в cli, php bin/magento setup:upgradeчтобы установить модуль, и все готово.

Мариус
источник
Topmenu.php отсутствует часть кода?
Themanwhoknowstheman
1
@Solide. Порядок ссылок зависит от порядка выполнения наблюдателей. Если обозреватель вашей домашней страницы выполняется до каталога, то ссылка на домашнюю страницу должна быть добавлена ​​первой. Если нет, вы можете взглянуть на этот подход для изменения порядка ссылок: magento.stackexchange.com/q/7329/146 . подход для Magento1, но вы можете перевести его в код M2.
Мариус
1
@Marius: что должно быть 'is_active'. Пожалуйста, добавьте пример. Я хочу активную ссылку на этой странице.
Зед Черная Борода
1
Наблюдатель используется на событии. Плагин может работать на любом публичном методе. Я бы посоветовал использовать плагинный подход, поскольку он используется в ядре для добавления категорий в верхнее меню.
Мариус
1
Извините, я чувствую себя идиотом, но как вы можете добавить более одного меню? Если я использую $menu->addChild($node)более одного раза, последний переопределяет другие. Показывает только одно меню (последнее).
Pinicio
17

Почему все всегда хотят написать модуль. Я сделал это по-своему, layout.xmlи это сработало как шарм:

    <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>
Джонни Лонгнек
источник
как открыть эту ссылку в новой вкладке?
Джафар Пинджар
Хороший вопрос. Нашел что-то в коде. Может быть, попробуйте это: <аргумент name = "attribute" xsi: type = "array"> <item name = "target" xsi: type = "string"> _ blank </ item> </ аргумент> Не проверено, но есть Доступна опция атрибутов.
Джонни Лонгнек,
Создание модуля делает его гораздо более динамичным. Многие клиенты, с которыми я работаю, хотят сами делать вещи, например, в этом случае, создавая страницы и добавляя их в верхнее меню в определенном порядке.
Рой Джеуриссен
6

Другое решение помимо создания модуля - перезапись topmenu.phtml. Отмечу, что решение, предоставляемое @Marius, является лучшим способом сделать это, если вы намерены, чтобы ваши ссылки наследовали классы навигации. Это отображается в мобильном меню Magento, просто без надлежащего CSS. Вы можете использовать аргумент css_class для стиля соответственно.

YourTheme / Magento_Theme / шаблоны / 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 / макет / 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
источник
Где я могу найти пример аргумента класса css?
Камдиксон
как связать файл шаблона с XML-файлом ..
Сарвеш Тивари
6

Этот ответ предоставлен Marius ♦ Я только что изменил его, чтобы добавить дочернюю категорию в меню на вкладке категории, в котором вы можете сослаться на ответ Marius ♦. Я просто изменил дочерний файл Topmenu.php, чтобы добавить дочернюю категорию в основную категорию

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

Вам необходимо создать узел для родительской категории и для дочерней категории, и после этого вы можете назначить дочернюю категорию для родительской категории с помощью метода addChild. Вот пример

$contactsNode->addChild($warrantyRegistrationNode);
Вайбхав Ахалпара
источник
Благодарность! не понимал, что это так легко добавить подменю!
Джулиано Варгас
и сэр, если я хочу показать свой пользовательский div в пользовательской ссылке, которую я добавил Topmenu. Например, когда я наводю указатель мыши на ссылку, она показывает мой пользовательский элемент
Асад Хан
1

Используя приведенный выше ответ Мариуса, я добавил пункты подменю. Я также показываю, как вы можете редактировать дерево перед созданием html, а затем, как редактировать html непосредственно после его создания. Работает в Magento 2.1. Обновите Topmenu.php следующим образом:

<?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
источник
1

Хотите добавить ссылку на верхнюю навигацию в разделе <header>
Добавление ссылки на страницу CMS, Галерея

Отредактируйте / разместите файл default.xml здесь:

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

Добавьте следующий код:

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

Это добавляет ссылку на страницу CMS, Галерея, со следующими настройками:

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

Добавьте следующий стиль, чтобы убедиться, что новая ссылка выравнивается правильно:

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

Результаты кода (Продукты настроены в качестве категории для примера)

Joshua34
источник
0

Если вы хотите добавить CMS Pages или другое, это было бы лучше

https://github.com/Mestrona/Mestrona_CategoryRedirect

Работал для меня :)

Анкит Шах
источник
Я попробовал этот модуль, но он не работает в Magento 2.1.3
Nikunj Vadariya
0

Для тех, кто хочет добавить is_activeвыражение, особенно @zed Blackbeard, которые спрашивали выше.

Я привык связывать контакт, и он будет работать с пользовательским модулем, так как я ссылаюсь на него.

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

// (выражение для определения, выбран элемент меню или нет)

Надеюсь, это кому-нибудь поможет.

Джулиано Варгас
источник
0

Это тоже хороший вариант:

приложение / дизайн / интерфейс / Вендер / yourtheme / Magento_Theme / макет / 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>
Сарфараз бхеда
источник
-1

Просто для ссылки в меню навигации не так много шагов, я нашел краткое руководство по этому вопросу, оно подразумевает тему, которая переопределяет topmenu.phtmlфайл из Magento_Themeмодуля: https://linkstraffic.net/adding-custom- menu-item-inside-magento2 / Я успешно проверил это, поэтому я делюсь этим с вами, ребята.

Джимми
источник
Добро пожаловать в Magento SE. Если вы публикуете ссылки в ответе, убедитесь, что ответ по-прежнему полезен, если ссылка через некоторое время перестает работать: например, подведите итог по статье или укажите соответствующие части. Это важно, потому что StackExchange стремится быть базой знаний, а не форумом поддержки, который помогает одному человеку прямо сейчас. Будущие посетители должны по-прежнему получать пользу от вопросов и ответов.
Сергей Учухлебау