如何以编程方式为Magento 2中的类别视图添加自定义布局句柄


9

因此,我想为所有类别视图页面添加自定义布局句柄。应该加载的句柄取决于某些类别参数,因此需要以编程方式添加该句柄 $page->addPageLayoutHandles()

似乎很简单..?显然不是

Magento 2提供了一个很好的插件系统,我自然会使用它,只需定义一个afterExecute()在原始类别之后运行的插件,execute()然后将任何更新从那里推送到Page对象。

不幸的是,它不是那样工作的。.原因是原始execute()方法(最终)将执行$page->getConfig()->addBodyClass()-对该方法的调用将自动强制布局完全加载和生成,因此任何后续尝试添加新布局Page的布局句柄完全没有用。我环顾四周,找到任何不太优雅的方法来实现相同的目的(仍然使用插件)..找不到任何东西。

我最终运行了自己的类别视图控制器,但是我不希望这样。

所以我的问题是.. 如何为类别视图添加(以编程方式)新的页面布局句柄?并优雅地做。


您使用的是哪个Magento版本?因为您可以在哪里看到$page->getConfig()->addBodyClass()加载并生成布局?目前,我仅在CMS页面上有类似的任务。
Giel Berkers,2015年

我很高兴您注意到这一点,因为您救了我一堆悲伤。仅供参考:类别视图控制器还调用$ page-> getConfig()-> addBodyClass(),这使插件无法完成此操作。
佩里·霍尔顿

Answers:


17

XML方式

一种简单的方法是在模块文件夹中创建以下文件:view/frontend/layout/catalog_category_view.xml具有以下内容:

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <update handle="your_custom_handle"/>
</page>

它并不比PHP方式优雅,但根据您的发现,它更安全。

PHP方式

不幸的是,对于您而言,似乎PHP是实现基于类别所具有的参数动态创建句柄的唯一方法。

通过插件

而不是创建的插件的execute()Action类的方法,你可以直接在创建插件addPageLayoutHandles()的方法Magento\Framework\View\Result\Page

主要问题在于,每次调用此方法时都会调用该方法,并且您必须在插件代码中添加一些条件,以确保您位于类别视图页面上。

通过首选项

另一种方法是对类别视图操作类使用首选项:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Magento\Catalog\Controller\Category\View"
                type="Vendor\Module\Controller\Category\View"/>
</config>

然后,在您的自定义控制器类中,您只需execute()复制/粘贴原始方法并直接在此方法中添加您的修改即可覆盖该方法。

主要问题是,当您升级Magento安装时,如果将更改添加到原始的本机Magento操作类中,则它不会反映在您的自定义操作类中。


问题是..它需要以编程方式添加。仅仅因为要加载的句柄取决于类别具有的参数。
克里斯蒂安H.16年

@KristjanH。嗯,我觉得这很尴尬,让我进一步探讨
拉斐尔(Raphael)在Digital Pianism上2016年

@KristjanH。看到我的更新
Raphael在Digital Pianism上2016年

1
使用<preference> ..即我在此处编写问题之前所做的事情,但是,我对此并不满意。与在addPageLayoutHandles上使用插件相同,我不想一直调用插件,即使不存在性能损失,这也不对。让我们看看是否还有其他解决方案出现在这里。
克里斯蒂安H.16年

之后,您是否尝试过其他方法?
LM_Fielding '16

8

我有一个类似的问题。对于不显示产品列表的类别,我需要一个额外的句柄。无法通过类别的“自定义布局XML” 添加句柄后,我最终在layout_load_before事件的观察者中添加了该句柄

class LayoutLoadBefore implements \Magento\Framework\Event\ObserverInterface
{
    /**
     * @var \Magento\Framework\Registry
     */
    protected $_registry;

    public function __construct(
        \Magento\Framework\Registry $registry
    )
    {
        $this->_registry = $registry;
    }

    /**
     * add a custom handle to categories of page type 'PAGE'
     *
     * @param \Magento\Framework\Event\Observer $observer
     * @return $this
     */
    public function execute(\Magento\Framework\Event\Observer $observer)
    {
        $action = $observer->getData('full_action_name');
        if ($action != 'catalog_category_view')
            return $this;

        $category = $this->_registry->registry('current_category');
        if (!$category)
            return $this;

        if ($category->getDisplayMode() == $category::DM_PAGE) {
            $layout = $observer->getData('layout');
            $layout->getUpdate()->addHandle('catalog_category_view_cms');
        }

        return $this;
    }
}

由于每次浏览量都需要调用观察者,因此对性能的影响不大。不幸的是,所有与“ category_view”相关的事件似乎都为时过早(尚未加载类别)或太晚了(布局已处理)。


谢谢!我遇到了类似的问题(magento.stackexchange.com/questions/156231/…)和一个插件\Magento\Cms\Controller\Page\View::execute()\Magento\Framework\View\Result\Page::addPageLayoutHandles() or render()但没有解决问题。这个最后解决方案是唯一对我有用的解决方案。
Giel Berkers

1

让我们尝试观察事件layout_load_before。执行功能将与此相同:

public function execute(\Magento\Framework\Event\Observer $observer)
    {
        if($observer->getFullActionName() == 'catalog_category_view'){
            $observer->getLayout()->getUpdate()->addHandle('your_custom_handles');
        }
    }

希望这会有所帮助

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.