Как добавить собственные маркеры макетов программно для просмотра по категориям в Magento 2

9

Итак, я хочу добавить собственный дескриптор макета для всех страниц просмотра категорий ... дескриптор, который должен быть загружен, зависит от определенных параметров категории, поэтому дескриптор необходимо добавлять программно с помощью $page->addPageLayoutHandles()

Кажется легким ..? Очевидно нет

Magento 2 предоставляет замечательную систему плагинов, которую я собирался использовать естественным образом, просто определите afterExecute()плагин, который будет запускаться после исходной категории, execute()и вставляйте любые обновления в объект Page оттуда.

К сожалению, это не совсем так работает .. причина в том, что оригинальный execute()метод (в самом конце) будет выполнен $page->getConfig()->addBodyClass()- вызов этого метода автоматически заставит макет быть полностью загруженным и сгенерированным, поэтому любые последующие попытки добавить новый Дескрипторы макета для Page совершенно бесполезны. Я посмотрел вокруг, чтобы найти какие-то не очень элегантные способы достижения того же самого (все еще используя плагины) .. не нашел ни одного.

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

Итак, мой вопрос ... как я могу добавить новые маркеры макета страницы (программно) для просмотра по категориям? и сделать это элегантно.

Кристьян Х.
источник
Какую версию Magento вы используете? Потому что где вы можете увидеть, что $page->getConfig()->addBodyClass()загружает и генерирует ваш макет? У меня сейчас аналогичная задача, только со страницами CMS.
Giel Berkers
Я так рад, что вы заметили это, поскольку вы спасли меня от горя. Просто к сведению: контроллер представления категорий также вызывает $ page-> getConfig () -> addBodyClass (), что делает плагин бесполезным для выполнения этого.
Перри Холден

Ответы:

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()метода вашего класса действий, вы можете напрямую создать плагин для 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, он не будет отражаться в вашем классе пользовательских действий.

Рафаэль в цифровом пианизме
источник
Проблема заключается в том, что .. это должно быть добавлено программно. Просто потому, что загружаемый дескриптор зависит от параметров, которые имеет категория.
Кристьян Х.
@KristjanH. хммм, я вижу, это стыдно, позвольте мне копать дальше
Рафаэль в Digital Pianism
@KristjanH. смотрите мое обновление
Рафаэль на цифровом пианизме
1
Используя <preference> .. то есть то, что я сделал перед тем, как написать вопрос здесь, однако, я не доволен этим. То же самое с использованием плагина на addPageLayoutHandles, я не хочу вызывать плагин все время, даже если снижение производительности отсутствует, это просто неправильно. Посмотрим, появятся ли здесь другие решения.
Кристьян Х.
Вы пробовали другой способ после этого?
LM_Fielding
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', кажутся либо слишком ранними (категория еще не загружена), либо слишком поздними (макет уже обработан).

alternize
источник
Спасибо! У меня была похожая проблема ( 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');
        }
    }

Надеюсь, это поможет

Hồ Trung Nghĩa
источник