Contact

Vous cherchez un spécialiste de Woocommerce

Vous ne comprenez rien à la création d'une grille de produits sous Woocommerce ! Contactez-nous.
Faites appel à un développeur spécialiste de Woocommerce et de Wordpress pour votre boutique. Nous étudions toutes les demandes de personnalisation.

Nous trouver

Afterglow Web Agency
5, rue Alexandre Dumas
06100 Nice
France

Woocommerce 4.0 + | Créer une grille de produits sur mesure

24 Août 2020 Par Cédric Moris Kelly

Woocommerce

1 . Les modèles utilisés par Woocommerce pour créer la grille de produits

Nous avons besoin de modifier trois templates dans le répertoire de notre thème pour créer notre grille de produits sur mesure :
woocommerce/content-product.php
woocommerce/loops/loop-start.php
woocommerce/loop/loop-end.php

content-product.php

Le modèle par défaut d’item de grille de produits dans Woocommerce est fourni par le template content-product.php :

wp-content/plugins/woocommerce/templates/content-product.php

Il intègre le bouton de mise au panier et un lien vers la page produit sur l’image du produit.

Vous pouvez le modifier en l’overriddant avec un fichier du mème nom dans le répertoire de votre thème selon le chemin de dossiers suivant :

wp-content/themes/votre-theme/woocommerce/content-product.php

C’est ce fichier que vous modifierez pour créer votre propre item de grille de produits.

Ce modèle content-product.php fournit le template pour un seul produit de la grille. Il ne fournit pas le conteneur de la grille de produits.

loop-start.php et loop-end.php

Le conteneur / wrapper de la grille de produits de Woocommerce est affiché par les fonctions :

woocommerce_product_loop_start();
/* et */
woocommerce_product_loop_end();

qui appellent respectivement les templates :

woocommerce/templates/loops/loop-start.php
/* et */
woocommerce/templates/loop/loop-end.php

Allez voir dans le répertoire « templates » de Woocommerce. Ces deux fonctions sont utilisées dans les modèles suivants :

archive-product.php, single-product/up-sells.php, single-product/related.php, cart/cross-sells.php

Le wrapper de la grille de produits par défaut nous fournit la classe CSS .products ainsi qu’une classe générée par l’option dans l’administration de Woocommerce qui règle le nombre de colonnes pour la grille de produits.

Modifier proprement les templates de Woocommerce

Il en va de même pour tous les fichiers de template Woocommerce que vous souhaiteriez modifier. Reprenez le chemin à partir de :

wp-content/plugins/woocommerce/templates/

et créez des fichiers ou dossier du même nom dans le répertoire « woocommerce » de votre thème situé sur le chemin :

wp-content/themes/votre-theme/woocommerce/

On appelle cela « overrider » un template.

2 . Créer son propre conteneur de grille de produits

Si vous souhaitez modifier le conteneur de grille de produits de Woocommerce, vous pouvez overrider les templates :
woocommerce/templates/loop/loop-start.php
woocommerce/templates/loop/loop-end.php
Toujours en les copiant dans le répertoire woocommerce de votre thème.

Utilisez le framework CSS Bootsrap

Pour intégrer une grille responsive en HTML, l’utilisation d’un Framework aussi pratique que Bootsrap est une étape presque incontournable pour une intégration mobile facile.
Nous allons inclure la version 4.4.1 de la librairie CSS dans notre thème WordPress en ajoutant le code suivant au fichier functions.php à la racine de notre thème :

add_action( 'wp_enqueue_scripts', 'afg_enqueue_styles' );
function afg_enqueue_styles() {
    wp_enqueue_style( 'bootstrap', '//stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css',array(), '4.4.1', 'all');
    wp_enqueue_style( 'theme-style', get_template_directory_uri() . '/style.css', array('bootstrap'), '1', false );
}

Dans l’idéal, si vous avez la maîtrise sur l’inclusion de la feuille de style principale de votre thème (votre-theme/style.css), vous devrez indiquer à la fonction wp_enqueue_style() que Bootsrap est une dépendance. Cela vous permettra de reprendre le contrôle sur les styles de Bootstrap si nécessaire.

loop-start.php

Maintenant que Bootsrap est disponible nous allons modifier le conteneur de grille de produits dans woocommerce/loop/loop-start.php

<?php
/**
 * Product Loop Start
 *
 * This template can be overridden by copying it to yourtheme/woocommerce/loop/loop-start.php.
 *
 * HOWEVER, on occasion WooCommerce will need to update template files and you
 * (the theme developer) will need to copy the new files to your theme to
 * maintain compatibility. We try to do this as little as possible, but it does
 * happen. When this occurs the version of the template file will be bumped and
 * the readme will list any important changes.
 *
 * @see         https://docs.woocommerce.com/document/template-structure/
 * @package     WooCommerce/Templates
 * @version     3.3.0
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}
?>
<ul class="products columns-<?php echo esc_attr( wc_get_loop_prop( 'columns' ) ); ?>">

La partie HTLM nous intéresse.

<ul class="products columns-<?php echo esc_attr( wc_get_loop_prop( 'columns' ) ); ?>">

Nous la remplaçons par :

<div class="row products">
  • Il est préférable de conserver la classe CSS products mise en place par Woocommerce pour assurer la compatibilité avec les plugins qui pourraient s’en servir.
  • La classe CSS de nombre de colonnes fournie par la partie suivante :
columns-<?php echo esc_attr( wc_get_loop_prop( 'columns' ) );
  • pourra être remplacée dans chaque produit de la grille dans le template content-product.php.
  • La classe CSS row est fournie par Bootsrap.
  • Libre à vous d’utiliser des classes CSS supplémentaires.

loop-end.php

Modifiez également le template woocommerce/loop/loop-end.php en changeant la balise HTML </ul> fermante par une balise </div> fermante.

<?php
/**
 * Product Loop End
 *
 * This template can be overridden by copying it to yourtheme/woocommerce/loop/loop-end.php.
 *
 * HOWEVER, on occasion WooCommerce will need to update template files and you
 * (the theme developer) will need to copy the new files to your theme to
 * maintain compatibility. We try to do this as little as possible, but it does
 * happen. When this occurs the version of the template file will be bumped and
 * the readme will list any important changes.
 *
 * @see         https://docs.woocommerce.com/document/template-structure/
 * @package     WooCommerce/Templates
 * @version     2.0.0
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}
?>
<!--</ul>-->
</div>

3 . Créer un produit / item de grille de produits

Dans votre thème, créez et éditer le fichier :
woocommerce/content-product.php
Voici l’original dans le plugin Woocommerce :

<?php
/**
 * The template for displaying product content within loops
 *
 * This template can be overridden by copying it to yourtheme/woocommerce/content-product.php.
 *
 * HOWEVER, on occasion WooCommerce will need to update template files and you
 * (the theme developer) will need to copy the new files to your theme to
 * maintain compatibility. We try to do this as little as possible, but it does
 * happen. When this occurs the version of the template file will be bumped and
 * the readme will list any important changes.
 *
 * @see     https://docs.woocommerce.com/document/template-structure/
 * @package WooCommerce/Templates
 * @version 3.6.0
 */

defined( 'ABSPATH' ) || exit;

global $product;

// Ensure visibility.
if ( empty( $product ) || ! $product->is_visible() ) {
	return;
}
?>
<li <?php wc_product_class( '', $product ); ?>>
	<?php
	/**
	 * Hook: woocommerce_before_shop_loop_item.
	 *
	 * @hooked woocommerce_template_loop_product_link_open - 10
	 */
	do_action( 'woocommerce_before_shop_loop_item' );

	/**
	 * Hook: woocommerce_before_shop_loop_item_title.
	 *
	 * @hooked woocommerce_show_product_loop_sale_flash - 10
	 * @hooked woocommerce_template_loop_product_thumbnail - 10
	 */
	do_action( 'woocommerce_before_shop_loop_item_title' );

	/**
	 * Hook: woocommerce_shop_loop_item_title.
	 *
	 * @hooked woocommerce_template_loop_product_title - 10
	 */
	do_action( 'woocommerce_shop_loop_item_title' );

	/**
	 * Hook: woocommerce_after_shop_loop_item_title.
	 *
	 * @hooked woocommerce_template_loop_rating - 5
	 * @hooked woocommerce_template_loop_price - 10
	 */
	do_action( 'woocommerce_after_shop_loop_item_title' );

	/**
	 * Hook: woocommerce_after_shop_loop_item.
	 *
	 * @hooked woocommerce_template_loop_product_link_close - 5
	 * @hooked woocommerce_template_loop_add_to_cart - 10
	 */
	do_action( 'woocommerce_after_shop_loop_item' );
	?>
</li>

Ce modèle est un peu déstabilisant à première vue car entièrement composé d’exécutions de Hooks.
Lire « Qu’est-ce qu’un hook ? »
Les commentaires sont très claires sur la manière d’utiliser chaque hook et sur les fonctions déjà connectées à chaque hook.

Deux choix s’offrent à vous pour modifier l’item de grille de produit :

1 . Passer hook par hook (lire « Qu’est-ce qu’un hook ? »)

Pour filtrer le html généré par des fonctions telle que la fonction woocommerce_template_loop_product_title() ou l’overrider quand le html est placé dans un template en dure comme woocommerce/loop/rating.php ou woocommerce/loop/price.php

À mon sens la maintenance du code devient vite problématique avec cette conception à la fois factorisée et inconsistante de Woocommerce :
Factorisée car tout est découpé en petits morceaux réutilisables ou filtrables
Inconstistante car ces petits morceaux sont parfois des fonctions, parfois des templates.

Le fait d’écrire des modèles HTML à la fois dans des hooks et des fichiers dispersés rend le code de votre thème rapidement dure à maintenir. Je conseille d’ailleurs de regrouper les hooks woocommerce dans une Classe PHP de votre thème. Plus globalement, utilisez la POO pour structurer le code de votre thème.

C’est hooks sont donc conseillés quand vous faites des modifications ponctuelles. Si vous souhaitez créer une grille de produit entièrement sur mesure, préférez le choix 2.

2. Négliger ces hooks et reconstruire un produit pour la grille

Vous pouvez aussi faire le choix d’ignorer les plugins qui pourraient se connecter sur ces hooks, le but étant d’avoir sa propre grille de produits et donc d’avoir la main sur toutes les fonctionnalités futures que vous souhaiteriez ajouter.
Créons une classe PHP appelée afg_productGrid qui nous servira à regrouper les fonctions qui généreront notre grille de produit. Notez que les fonctions sont appelées méthodes en POO dans le contexte d’une classe.

<?php
if( ! defined( 'ABSPATH' ) ) exit;//If WP Constant ABSPATH doesn't exist, exit the script
 
    /**
    * We create a PHP class called 'Main' which contains all our templates parts
    */
    if ( ! class_exists('afg_productGrid') ) {
     
        class afg_productGrid {
     
            public function getGridProduct() {
                global $product;
                $class='col-lg-3 col-md-6 afg-grid-product';
                $rating = $product->get_average_rating();
		        $rating_count = $product->get_rating_count();
                $id = $product->get_id();
                $html = '';
     
                $html .= '<div '.wc_product_class( $class, $product ).' id="post-'.$id.'">';// 'wc_product_class()' mixes and returns the CSS Classes we set in $class with Woocommerce classes.
                    
                    $html .= '<figure role="group">';
                        $html .= $this->getProductGallery();
                    $html .= '</figure>';

                    $html .= '<div class="afg-text">';
	                $html .= '<div class="afg-price">';
		            $html .= $this->getPriceAndSale();
	                $html .= '</div>';
	                $html .= '<h2><a href="'.get_the_permalink().'" title="'.get_the_title().'">'.get_the_title().'</a></h2>';
                        ob_start();
			               woocommerce_template_single_add_to_cart();//USE ETHEIR THIS FOR FULL ADD TO CART FORM
                           /*OR*/
                           woocommerce_template_loop_add_to_cart();//THIS FOR A SIMPLE ADD TO CART BUTTON
			               $html .= ob_get_contents();
			            ob_end_clean();
	                $html .= '<div>';
			        $html .= $rating_count > 0 ? $this->getStarRatingHtml($rating) : '';
		            $html .= $this->getProductAttribute();
		            $html .= $this->getStockStatus();
	                $html .= '</div>';
                    $html .= '</div>';

                $html .= '</div>';
     
                return $html;
            }
        
        // We will show this methods in later chapters 
        public function getProductGallery(){}
        public function getPriceAndSale(){}
        public function getStarRatingHtml(){}
        public function getProductAttribute(){}
        public function getStockStatus(){}
     
    }//end Class
 
}//endif Class exists
  • L’intérêt de placer votre modèle directement dans une fonction est de rendre le template content-product.php à la fois modulaire et lisible. Vous pourrez aussi facilement utiliser cette fonction dans d’autres templates.
  • Cela permettra aussi de facilement proposer plusieurs modèles d’item de produit en écrivant plusieurs fonctions de ce type.
  • Le fait de placer le html dans une variable $html plutôt que de l’envoyer vers la sortie de php permettra d’inclure ce modèle dans un modèle plus complexe
  • Dans l’idéal, pour une question de maintenance du code, il est préférable d’utiliser la POO et de créer une classe PHP dédiée à vos fonctions de templates.
  • Nous détaillerons les méthodes getProductGallery(), getPriceAndSale(), getProductAttribute(), getStockStatus() dans les paragraphes suivants. Leur nom est explicite, elles font toutes appel à des fonctions Woocommerce correspondantes.

Nous enregistrons notre classe afg_ProductGrid dans le fichier :
/mon-theme/inc/class.productGrid.php
(Vous pourriez faire de même avec un plugin en créant le fichier /mon-plugin/inc/class.productGrid.php)

Nous pouvons charger notre classe en plaçant le hook suivant dans notre fichier :
/mon-theme/functions.php

add_action( 'init', 'afg_loadThemeIncludes' );

function afg_loadThemeIncludes($inc = null) {
    $class_path = get_template_directory() . '/inc/';
    foreach ( glob( $class_path."*.php" ) as $file ) {
        require_once $file;//Be aware that all PHP files in /inc/ will be loaded.
    }
}

Une fois que votre classe est correctement chargée, vous pouvez modifier woocommerce/content-product.php comme suit :

<?php
/**
 * The template for displaying product content within loops
 *
 * This template can be overridden by copying it to yourtheme/woocommerce/content-product.php.
 *
 * HOWEVER, on occasion WooCommerce will need to update template files and you
 * (the theme developer) will need to copy the new files to your theme to
 * maintain compatibility. We try to do this as little as possible, but it does
 * happen. When this occurs the version of the template file will be bumped and
 * the readme will list any important changes.
 *
 * @see     https://docs.woocommerce.com/document/template-structure/
 * @package WooCommerce/Templates
 * @version 3.6.0
 */

defined( 'ABSPATH' ) || exit;

global $product;
$main = new Main;
// Ensure visibility.
if ( empty( $product ) || ! $product->is_visible() ) {
	return;
}
?>
<?php echo $main->getGridProduct(); ?>

4. Créer un slider d’images pour chaque produit dans la grille | $this->getProductGallery()

L’objet $product Woocommerce nous fournit deux méthodes pour récupérer les images du produit :
$product->get_image_id() permet de récupérer l’ID de l’image mise en avant (featured image).
$product->get_gallery_image_ids() permet de récupérer les IDs des images de la galerie du produit.

HTML

public function getProductGallery() {
    $html = '';
    $imageIds = array();
    global $product;
 
    $imageIds = $product->get_gallery_image_ids();//We get product gallery image Ids
    if( $product->get_image_id() ) array_unshift( $imageIds, $product->get_image_id() );//We put featured image Id on the top of the Array
    if (count($imageIds) >= 1 ) {
            foreach ($imageIds as $imageId) {
                $html .= '<figure>';
                    $html .= sprintf(
                        '<img src="%s" alt="%s"/>', 
                        esc_url( wp_get_attachment_image_url($imageId, 'afg_classic' ) ), 
                        get_post_meta($imageId, '_wp_attachment_image_alt', TRUE)
                    );
                $html .= '</figure>';
            }
    }
    return $html;
}

Javascript

Nous avons besoin d’un peu de Javascript pour animer notre galerie d’images.
Nous allons utiliser pour ça la micro librairie Js Slick.
Nous l’incluons dans notre fonction d’ajout de scripts et styles dans mon-theme/functions.php, lignes 3 et 5 dans l’exemple ci-dessous.

add_action( 'wp_enqueue_scripts', 'afg_enqueue_styles' );
function afg_enqueue_styles() {
    wp_enqueue_style( 'slick-css', '//cdn.jsdelivr.net/npm/slick-carousel@1.8.1/slick/slick.css',array(), '1.8.1', 'all');
    wp_enqueue_style( 'bootstrap', '//stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css',array(), '4.4.1', 'all');
    wp_enqueue_script( 'slick-js', '//cdn.jsdelivr.net/npm/slick-carousel@1.8.1/slick/slick.js',array(), '1.8.1', 'all');
    wp_enqueue_style( 'theme-style', get_template_directory_uri() . '/style.css', array('slick-css','bootstrap'), '1', false );
  	wp_enqueue_script( 'main-script', get_template_directory_uri() . '/assets/js/functions.js', array( 'jquery','slick-js' ), '1', true );
  	wp_localize_script( 'main-script', 'afterglowAjax', array(
	'ajaxurl'=> admin_url( 'admin-ajax.php' )
	) );
}

Nous créons le fichier mon-theme/assets/js/functions.js

jQuery(document).ready(function($){

    $('.afg-grid-product > figure').slick({
      infinite: true,
      dots: true,
      autoplay: true,
      autoplaySpeed: 2000,
      responsive: [
        {
          breakpoint: 992,
          settings: {
            arrows: true,
            dots: false,
          }
        }
      ]
    });

});

Vous pouvez retrouver ici toutes les options de Slick.
Dans cet exemple nous instancions un slider image par image, en lecture automatique et bouclée.
Nous affichons les contrôles par pastilles et par flèches.