Como adicionar manipuladores de layout personalizados programaticamente para a exibição de categoria no Magento 2

9

Então, eu quero adicionar um identificador de layout personalizado para todas as páginas de exibição de categoria. O identificador que deve ser carregado depende de certos parâmetros de categoria, portanto, o identificador precisa ser adicionado programaticamente com $page->addPageLayoutHandles()

Parece fácil ..? Aparentemente não

O Magento 2 fornece um bom sistema de afterExecute()plug-ins que eu usaria naturalmente, basta definir um plug-in para ser executado após a categoria original execute()e enviar todas as atualizações para o objeto Page a partir daí.

Infelizmente, não funciona dessa maneira. O motivo é que o execute()método original (no final) será executado $page->getConfig()->addBodyClass()- uma chamada para esse método forçará automaticamente o layout a ser completamente carregado e gerado, portanto, qualquer tentativa subsequente de adicionar novos alças de layout para a página são completamente inúteis. Olhei em volta para encontrar maneiras não tão elegantes de conseguir a mesma coisa (ainda usando plugins) .. não encontrei nenhuma.

Acabei executando meu próprio controlador para exibição de categoria, no entanto, eu não preferiria deixar dessa maneira.

Então, minha pergunta é .. como posso adicionar novos identificadores de layout de página (programaticamente) para exibição de categoria? e faça-o com elegância.

Kristjan H.
fonte
Qual versão do Magento você está usando? Porque onde você pode ver que $page->getConfig()->addBodyClass()carrega e gera seu layout? Estou tendo uma tarefa semelhante no momento, apenas com páginas do CMS.
Giel Berkers
Estou tão feliz que você tenha notado isso, pois me salvou de muita dor. Apenas para sua informação: o controlador de exibição de categoria também chama $ page-> getConfig () -> addBodyClass (), que torna um plug-in inútil para fazer isso.
Perry Holden

Respostas:

17

A maneira XML

Bem, uma maneira fácil é criar o seguinte arquivo na pasta do módulo: view/frontend/layout/catalog_category_view.xmlcom o seguinte conteúdo:

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

Não é mais ou menos elegante do que o modo PHP e, de acordo com o que você achou, é mais seguro.

O jeito PHP

Infelizmente, no seu caso, parece que o PHP é a única maneira de conseguir criar dinamicamente identificadores com base nos parâmetros que a categoria possui.

Via plugins

Em vez de criar um plugin no execute()método da sua classe de ação, você pode criar diretamente um plugin no addPageLayoutHandles()método deMagento\Framework\View\Result\Page

O principal problema é que ele será chamado toda vez que esse método for chamado e você terá que adicionar algumas condições no código do plug-in para garantir que você esteja em uma página de visualização por categoria.

Via preferências

Outra maneira de fazer isso seria usar preferências para a classe de ação de exibição de categoria:

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

Em sua classe de controlador personalizado, você simplesmente substitui o execute()método copiando / colando o método original e adicionando suas modificações diretamente nesse método.

O principal problema é que, quando você atualizar sua instalação do Magento, se forem adicionadas alterações à classe de ação original do Magento, ela não será refletida na sua classe de ação personalizada.

Raphael na Digital Pianism
fonte
O problema é .. ele precisa ser adicionado programaticamente. Simplesmente porque o identificador que está sendo carregado depende dos parâmetros que a categoria possui.
precisa
@KristjanH. hmmm eu ver que é embaraçoso, deixe-me cavar ainda mais
Raphael em Digital pianismo
@KristjanH. veja minha atualização
Raphael no Digital Pianism
11
Usando <preference> .. ou seja, o que fiz antes de escrever a pergunta aqui, no entanto, não estou feliz com isso. Mesmo com o uso de um plug-in no addPageLayoutHandles, não quero chamar um plug-in o tempo todo, mesmo que a penalidade de desempenho seja inexistente, isso não é correto. Vamos ver se outras soluções aparecem aqui.
precisa
Você tentou outra maneira depois disso?
LM_Fielding 12/12
8

Eu tive um problema parecido. para categorias que não mostram listagens de produtos, eu precisava de uma alça extra. depois de não adicionar o identificador através do XML de layout personalizado da categoria, acabei adicionando-o em um observador no layout_load_beforeevento:

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

há um pequeno impacto no desempenho envolvido, pois o observador é chamado para todas as visualizações de página. infelizmente, todos os eventos relacionados a 'category_view' parecem muito cedo (categoria ainda não carregada) ou muito tarde (layout já processado).

alternar
fonte
Obrigado! Eu tive um problema semelhante ( magento.stackexchange.com/questions/156231/… ) e um plug-in ativado\Magento\Cms\Controller\Page\View::execute() e \Magento\Framework\View\Result\Page::addPageLayoutHandles() or render()não funcionou. Essa solução de último recurso foi a única solução que funcionou para mim.
Giel Berkers
1

Vamos tentar observar o evento layout_load_before. A função de execução será a mesma:

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

Espero que isso ajude

Hồ Trung Nghĩa
fonte