在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

您正在使用哪个Magento版本?
拉兹万·赞菲尔

Answers:


34

[编辑]
显然,在M2的最新版本中,此功能不再起作用。
感谢Max指出这一点。
对于更高版本,您需要添加的插件,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'。请添加一些示例。我想要此页面上的活动链接。
zed Blackbeard,

1
事件使用观察者。插件可以在任何公共方法上工作。我建议使用插件方法,因为在核心中使用了一种将类别添加到顶部菜单的方法。
马里乌斯

1
抱歉,我觉得自己是个白痴,但是如何添加多个菜单呢?如果我使用$menu->addChild($node)不止一次,则最后一个优先于其他。它仅显示一个菜单(最后一个)。
pinicio '18

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>

如何在新标签页中打开该链接?
贾法尔·品哈尔(Jafar Pinjar)

好问题。在代码中找到了一些东西。也许尝试一下:<argument name =“ attributes” xsi:type =“ array”> <item name =“ target” xsi:type =“ string”> _ blank </ item> </ argument>未测试,但是有属性选项可用。
约翰尼·朗内克

创建模块可以使其更加动态。与我合作的许多客户希望自己做一些事情,例如在这种情况下创建页面并将它们按特定顺序添加到顶层菜单中。
罗伊·耶里森

6

创建模块之外的另一个解决方案是覆盖topmenu.phtml。我将注意到,如果您希望链接继承导航类,则@Marius提供的解决方案是最好的方法。这确实显示在Magento的移动菜单中,只是没有适当的CSS。您可以使用css_class参数来相应地设置样式。

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>

在哪里可以找到CSS类参数的示例?
camdixon


您如何将模板文件链接到xml文件..
Sarvesh Tiwari,

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

谢谢!没意识到添加子菜单是如此简单!
朱利诺·巴尔加斯

主席先生,如果我想在我添加的自定义链接中显示我的自定义divTopmenu。就像当我将鼠标悬停在链接上时,它显示了我的自定义div
Asad Khan

1

使用Marius的上述答案,我添加了子菜单项。我还展示了一种方法,您可以在创建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);
        }
    }
}

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页面Gallery的链接,并具有以下设置:

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

添加以下样式以确保新链接正确对齐:

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

代码结果 (产品设置为示例类别)



0

对于那些想要添加is_active表达的人,尤其是上面问过的@zed Blackbeard。

我曾经链接过该联系人,当我链接到该联系人时,它也将与自定义模块一起使用。

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

//(表示确定是否选择菜单项的表达式)

希望它能帮助任何人。


0

这也是一个不错的选择:

应用/设计/前端/供应商/您的主题/ 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_Themehttps : //linkstraffic.net/adding-custom- menu-item-inside-magento2 / 我已经成功测试过,因此我与大家分享。


欢迎来到Magento SE。如果您在答案中发布链接,请确保该答案仍然有价值,如果该链接有时会失效:例如,汇总链接的文章或引用相关的部分。这很重要,因为StackExchange旨在成为一个知识数据库,而不是现在可以帮助一个人的支持论坛。未来的访客仍应从问题和解答中受益。
Siarhey Uchukhlebau
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.