Comment ajouter des poignées de présentation personnalisées par programme pour l'affichage des catégories dans Magento 2

9

Donc, je veux ajouter une poignée de mise en page personnalisée pour toutes les pages de vue de catégorie. La poignée qui est censée être chargée dépend de certains paramètres de catégorie, donc la poignée doit être ajoutée par programme avec $page->addPageLayoutHandles()

Semble facile ..? Apparemment non

Magento 2 fournit un joli système de plugins que j'allais naturellement utiliser, il suffit de définir un afterExecute()plugin à exécuter après la catégorie d'origine execute()et de pousser toutes les mises à jour dans l'objet Page à partir de là.

Malheureusement, cela ne fonctionne pas tout à fait de cette façon. La raison étant que la execute()méthode d' origine (à la toute fin) s'exécutera $page->getConfig()->addBodyClass()- un appel à cette méthode forcera automatiquement la mise en page à être complètement chargée et générée, donc toute tentative ultérieure d'ajouter de nouvelles les poignées de mise en page vers la page sont complètement inutiles. J'ai regardé autour de moi pour trouver des moyens pas si élégants de réaliser la même chose (en utilisant toujours des plugins). Je n'en ai pas trouvé.

J'ai fini par exécuter mon propre contrôleur pour l'affichage des catégories, mais je ne préférerais pas le laisser de cette façon.

Donc, ma question est .. comment puis-je ajouter de nouvelles poignées de mise en page (par programme) pour l'affichage des catégories? et faites-le avec élégance.

Kristjan H.
la source
Quelle version de Magento utilisez-vous? Parce que où pouvez-vous voir qui se $page->getConfig()->addBodyClass()charge et génère votre mise en page? J'ai une tâche similaire en ce moment, uniquement avec les pages CMS.
Giel Berkers du
Je suis tellement contente que vous ayez noté cela, car vous m'avez sauvé un tas de chagrin. Juste pour info: le contrôleur de vue de catégorie appelle également $ page-> getConfig () -> addBodyClass () ce qui rend un plugin inutile pour accomplir cela.
Perry Holden

Réponses:

17

La manière XML

Eh bien, un moyen simple est de créer le fichier suivant dans votre dossier de module: view/frontend/layout/catalog_category_view.xmlavec le contenu suivant:

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

Il n'est pas plus ou moins élégant que la méthode PHP et selon ce que vous avez trouvé, il est plus sûr.

La façon PHP

Malheureusement, dans votre cas, il semble que PHP soit le seul moyen de créer dynamiquement des descripteurs en fonction des paramètres de la catégorie.

Via des plugins

Au lieu de créer un plugin sur la execute()méthode de votre classe d'action, vous pouvez directement créer un plugin sur la addPageLayoutHandles()méthode deMagento\Framework\View\Result\Page

Le problème principal est qu'il sera appelé à chaque appel de cette méthode et vous devrez ajouter certaines conditions dans votre code de plugin pour vous assurer que vous êtes sur une page d'affichage de catégorie.

Via les préférences

Une autre façon de le faire serait d'utiliser les préférences pour la classe d'actions d'affichage de catégorie:

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

Ensuite, dans votre classe de contrôleur personnalisé, vous remplacez simplement la execute()méthode en copiant / collant la méthode d'origine et ajoutez vos modifications directement dans cette méthode.

Le problème principal est que lorsque vous mettrez à niveau votre installation Magento, si des modifications sont ajoutées à la classe d'action native de Magento, cela ne se reflétera pas dans votre classe d'action personnalisée.

Raphael chez Digital Pianism
la source
Le problème est ... il doit être ajouté par programme. Tout simplement parce que la poignée en cours de chargement dépend des paramètres de la catégorie.
Kristjan H.
@KristjanH. hmmm je vois que c'est embarrassant, laissez-moi creuser plus loin
Raphael au Digital Pianism
@KristjanH. voir ma mise à jour
Raphael au Digital Pianism
1
En utilisant <préférence> .. c'est-à-dire ce que j'ai fait juste avant d'écrire la question ici, cependant, je ne suis pas satisfait de cela. De même avec l'utilisation d'un plugin sur addPageLayoutHandles, je ne veux pas appeler un plugin tout le temps, même si la pénalité de performance est inexistante, ce n'est tout simplement pas correct. Voyons si d'autres solutions apparaissent ici.
Kristjan H.
Avez-vous essayé d'une autre manière après cela?
LM_Fielding
8

J'avais un problème similaire. pour les catégories qui ne présentent pas de listes de produits, j'avais besoin d'une poignée supplémentaire. après avoir échoué à ajouter le handle via le XML de mise en page personnalisée de la catégorie, j'ai fini par l'ajouter dans un observateur sur l' layout_load_beforeévénement:

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

il y a un petit succès de performance impliqué car l'observateur est appelé pour chaque page vue. malheureusement, tous les événements liés à 'category_view' semblent soit trop tôt (catégorie pas encore chargée) ou trop tard (disposition déjà traitée).

alterner
la source
Merci! J'ai eu un problème similaire ( magento.stackexchange.com/questions/156231/… ) et un plugin \Magento\Cms\Controller\Page\View::execute()et \Magento\Framework\View\Result\Page::addPageLayoutHandles() or render()je n'ai pas fait l'affaire. Cette solution de dernier recours était la seule solution qui a fonctionné pour moi.
Giel Berkers
1

Essayons d'observer l'événement layout_load_before. La fonction d'exécution sera la même que celle-ci:

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

J'espère que cela vous aidera

Hồ Trung Nghĩa
la source