Par défaut, Magento 2 utilise un template PHTML unique pour afficher les listes produits d’une catégorie et de ses sous-catégories. Il s’agit du fichier vendor/magento/module-catalog/view/frontend/templates/product/list.phtml
.
L’un des problèmes posé par ce mode de fonctionnement réside dans le fait qu’on se retrouve avec une page catégorie principale/main qui affiche, dans une liste unique, tous les produits contenus dans cette catégorie ainsi que ses sous-catégories et ceux sans aucun distingo. Ce qui nous donne, de manière très schématisée:
|
<h1>Ma catégorie principale</h1> <ul> <li>Produit issu de ma sous catégorie #1</li> <li>Produit issu de ma sous catégorie #1</li> <li>Produit issu de ma sous catégorie #3</li> <li>Produit issu de ma sous catégorie #4</li> <li>Produit issu de ma sous catégorie #1</li> <li>Produit issu de ma sous catégorie #2</li> <li>Produit issu de ma sous catégorie #2</li> </ul> |
Le code décrit dans ce billet va permettre d’obtenir ceci:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
<h1>Ma sous catégorie #1</h1> <ul> <li>Produit issu de ma sous catégorie #1</li> <li>Produit issu de ma sous catégorie #1</li> <li>Produit issu de ma sous catégorie #1</li> </ul> <h1>Ma sous catégorie #2</h1> <ul> <li>Produit issu de ma sous catégorie #2</li> <li>Produit issu de ma sous catégorie #2</li> </ul> <h1>Ma sous catégorie #3</h1> <ul> <li>Produit issu de ma sous catégorie #3</li> </ul> <h1>Ma sous catégorie #4</h1> <ul> <li>Produit issu de ma sous catégorie #4</li> </ul> |
Création d’un Helper: app/code/Pdv/Catalog/Helper/Data.php
Note: j’avais déjà créé ce Helper pour récupérer les Simple Products associés à un Configurable Product. Consulter le billet en question pour de plus amples infos si vous ne souhaitez pas exploiter tout le code ci-dessous. Ce Helper étend vendor/magento/module-catalog/Helper/Data.php
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
|
<?php namespace Pdv\Catalog\Helper; use Magento\Framework\Exception\NoSuchEntityException; /** * Catalog data helper * */ class Data extends \Magento\Framework\App\Helper\AbstractHelper { /** * @var \Pdv\Catalog\Model\Layer\Resolver $resolver */ protected $resolver; /** * @var \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable */ protected $typeConfigurableResourceModel; // 1. Du nom du model dont je veux injecter la propriété de la classe /** * @var \Magento\Catalog\Api\CategoryRepositoryInterface $categoryRepository */ protected $categoryRepository; public function __construct( \Pdv\Catalog\Model\Layer\Resolver $resolver, \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable $typeConfigurableResourceModel, // 2. Demande à Magento une instance de mon configurable ressource model \Magento\Catalog\Api\CategoryRepositoryInterface $categoryRepository ) { $this->resolver = $resolver; $this->typeConfigurableResourceModel = $typeConfigurableResourceModel; // 3. ...et mappe le paramètre du constructeur avec la propriété de la classe $this->categoryRepository = $categoryRepository; } /** * @param int $id * @return \Magento\Catalog\Api\Data\CategoryInterface | \Magento\Catalog\Model\Category * * @throws NoSuchEntityException */ public function getCategory($id = null) { return $id ? $this->categoryRepository->get($id) : $this->resolver->getCurrentCategory(); } /** * @param $childId * @return string[] */ public function getConfigurableParentIdsByChildId($childId) { // 4. Je donne accès à ma nouvelle méthode dans le PHTML return $this->typeConfigurableResourceModel->getParentIdsByChild($childId); } } |
Rajouts par rapport au Helper existant:
Sous la ligne namespace Pdv\Catalog\Helper;
:
|
use Magento\Framework\Exception\NoSuchEntityException; |
Sous la ligne protected $typeConfigurableResourceModel; // 1. Du nom du model dont je veux injecter la propriété de la classe
:
|
/** * @var \Magento\Catalog\Api\CategoryRepositoryInterface $categoryRepository */ protected $categoryRepository; |
Dans le constructeur, sous la ligne \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable $typeConfigurableResourceModel // 2. Demande à Magento une instance de mon configurable ressource model
(EN RAJOUTANT UNE VIRGULE en fin de la ligne existante):
|
\Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable $typeConfigurableResourceModel, // 2. Demande à Magento une instance de mon configurable ressource model \Magento\Catalog\Api\CategoryRepositoryInterface $categoryRepository |
Sous la ligne $this->typeConfigurableResourceModel = $typeConfigurableResourceModel; // 3. ...et mappe le paramètre du constructeur avec la propriété de la classe
:
|
$this->categoryRepository = $categoryRepository; |
Le commentaire:
|
/** * @return \Magento\Catalog\Model\Category */ |
…est enrichi comme suit:
|
/** * @param int $id * @return \Magento\Catalog\Api\Data\CategoryInterface | \Magento\Catalog\Model\Category * * @throws NoSuchEntityException */ |
Et la fonction getCurrentCategory()
qui suit…
|
public function getCurrentCategory() { return $this->resolver->getCurrentCategory(); } |
…est remaniée en:
|
public function getCategory($id = null) { return $id ? $this->categoryRepository->get($id) : $this->resolver->getCurrentCategory(); } |
app/design/frontend/Sodifrance/pdv/Magento_Catalog/templates/product/list_abonnements_category.phtml
Ce template PHTML se contente de boucler, autant de fois qu’il y a de sous-catégories, sur le template Magento_Catalog::product/list_abonnements_subcategory.phtml
qui est une version custom du template vendor/magento/module-catalog/view/frontend/templates/product/list.phtml
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
<?php /** @var \Magento\Catalog\Block\Product\ListProduct $block */ $objectManager = \Magento\Framework\App\ObjectManager::getInstance(); $category = $objectManager->get('Magento\Framework\Registry')->registry('current_category'); $subcats = $category->getChildrenCategories(); $objectManager = \Magento\Framework\App\ObjectManager::getInstance(); $categoryFactory = $objectManager->get('\Magento\Catalog\Model\CategoryFactory'); ?> <ul class="product details product-item-details"> <?php /** @var \Magento\Catalog\Model\Category $subcat */ foreach ($subcats as $subcat) { if ($subcat->getIsActive()) { /** @var \Magento\Catalog\Block\Product\ListProduct $categoryBlock */ $categoryBlock = $block->getLayout()->createBlock("Magento\Catalog\Block\Product\ListProduct") ->setTemplate("Magento_Catalog::product/list_abonnements_subcategory.phtml") ->setCategoryId($subcat->getid()); echo $categoryBlock->toHtml(); } } ?> </ul> |
L’équivalent de ce fichier list_abonnements_subcategory.phtml
DOIT exister dans votre projet. Si vous n’avez pas besoin d’en créer un spécifique, vous pouvez boucler sur le template par défaut fourni par Magento 2. Dans le code ci-dessus: ->setTemplate("Magento_Catalog::product/list.phtml")
. Edit: il faut en créer un spécifique pour exploiter notre Helper.
app/design/frontend/Sodifrance/pdv/Magento_Catalog/templates/product/list_abonnements_subcategory.phtml
Ce template PHTML doit partir de vendor/magento/module-catalog/view/frontend/templates/product/list.phtml
. Il est impératif de rajouter les lignes suivantes en haut de fichier, sous la ligne $hoverChange = $themeSettingConfig->getStoreConfig('themesettings/catalog/hover_change');
:
|
/** @var \Pdv\Catalog\Helper\Data $helper */ $helper = $this->helper('Pdv\Catalog\Helper\Data'); /** @var \Magento\Catalog\Model\Category $currentCategory */ $currentCategory = $helper->getCategory($this->getCategoryId()); $currentCategoryProductCount = $currentCategory->getProductCount(); |
app/design/frontend/Sodifrance/pdv/Magento_Theme/page_layout/abonnements_category.xml
Reportez-vous à ce billet pour voir comment afficher un layout différent selon une catégorie spécifique. Cette étape est indispensable pour faire pointer notre catégorie vers notre template PHTML spécifique app/design/frontend/Sodifrance/pdv/Magento_Catalog/templates/product/list_abonnements_category.phtml
. Un exemple de code pour ce fichier ci-dessous:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
<?xml version="1.0"?> <layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_layout.xsd"> <update handle="empty"/> <referenceContainer name="page.wrapper"> <container name="header.container" as="header_container" label="Page Header Container" htmlTag="header" htmlClass="page-header" before="main.content"/> <container name="page.top" as="page_top" label="After Page Header" after="header.container"/> <container name="footer-container" as="footer" before="before.body.end" label="Page Footer Container" htmlTag="footer" htmlClass="page-footer"/> </referenceContainer> <referenceContainer name="catalog.leftnav" remove="true" /> <!-- From: vendor/magento/module-catalog/view/frontend/layout/catalog_category_view.xml--> <referenceContainer name="columns.top"> <referenceBlock name="category.products.list" template="Magento_Catalog::product/list_abonnements_category.phtml"> <action method="setTemplate"> <argument name="template" xsi:type="string">Magento_Catalog::product/list_abonnements_category.phtml</argument> </action> </referenceBlock> </referenceContainer> <referenceContainer name="before.body.end"> <block class="Magento\Framework\View\Element\Template" name="custom.file" before="-" template="Magento_Catalog::product/list_abonnements_js.phtml" /> </referenceContainer> </layout> |
Vous voudrez aussi créer le layout XML app/design/frontend/Sodifrance/pdv/Magento_Theme/page_layout/abonnements_subcategory.xml
…pour fairez pointer les sous-catégories vers le template PHTML
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
<?xml version="1.0"?> <layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_layout.xsd"> <update handle="empty"/> <referenceContainer name="page.wrapper"> <container name="header.container" as="header_container" label="Page Header Container" htmlTag="header" htmlClass="page-header" before="main.content"/> <container name="page.top" as="page_top" label="After Page Header" after="header.container"/> <container name="footer-container" as="footer" before="before.body.end" label="Page Footer Container" htmlTag="footer" htmlClass="page-footer"/> </referenceContainer> <referenceContainer name="catalog.leftnav" remove="true" /> <!-- From: vendor/magento/module-catalog/view/frontend/layout/catalog_category_view.xml--> <referenceContainer name="columns.top"> <referenceBlock name="category.products.list" template="Magento_Catalog::product/list_abonnements_subcategory.phtml"> <action method="setTemplate"> <argument name="template" xsi:type="string">Magento_Catalog::product/list_abonnements_subcategory.phtml</argument> </action> </referenceBlock> </referenceContainer> <referenceContainer name="before.body.end"> <block class="Magento\Framework\View\Element\Template" name="custom.file" before="-" template="Magento_Catalog::product/list_abonnements_js.phtml" /> </referenceContainer> </layout> |
Externaliser le code JS
Afin que le code JS initialement présent au bas du fichier list.phtml
ne soit pas exécuté autant de fois qu’il existe de sous-catégories, il a été externalisé dans un fichier app/design/frontend/Sodifrance/pdv/Magento_Catalog/templates/product/list_abonnements_js.phtml
et déclaré de la sorte dans nos layouts XML spécifiques:
|
<referenceContainer name="before.body.end"> <block class="Magento\Framework\View\Element\Template" name="custom.file" before="-" template="Magento_Catalog::product/list_abonnements_js.phtml" /> </referenceContainer> |
app/design/frontend/Sodifrance/pdv/Magento_Catalog/templates/product/list_abonnements_js.phtml
Le code de ce fichier, sorti de list.phtml
:
|
<script type="text/javascript"> require([ 'jquery' ], function(jQuery){ (function($) { $('.action-filter').click(function(){ $(this).toggleClass('active'); $('.filter-content').slideToggle(); }); })(jQuery); }); </script> |