vendredi 25 septembre 2026

À propos

Contact

E-commerce

Antipatterns WooCommerce : les erreurs de requêtes qui ralentissent une boutique

query_posts mal utilisé, boucles de get_post_meta, comptages répétés du panier : les erreurs de requêtes les plus fréquentes vues en audit sur des boutiques WooCommerce.

Par Clément Hadrot • 30 mai 2022 • 5 min de lecture • Aucun commentaire
Antipatterns WooCommerce : les erreurs de requêtes qui ralentissent une boutique

Sur les audits de performance que nous menons régulièrement, une bonne moitié des ralentissements constatés sur une boutique WooCommerce ne vient ni de l’hébergement ni du thème, mais d’un petit nombre de motifs de code qui se répètent d’un projet à l’autre. Ce sont des erreurs classiques, souvent issues d’un tutoriel copié sans recul ou d’un correctif rapide jamais retravaillé. En voici les plus fréquentes, avec ce qu’il faut faire à la place.

Aucun de ces antipatterns n’est propre à un thème ou une extension particulière : ils traversent les projets, ce qui en fait une bonne base de vérification systématique lors d’un audit de boutique existante.

Antipattern n° 1 : utiliser query_posts pour afficher des produits

Ce que l’on voit : un développeur veut afficher une liste de produits personnalisée sur une page et utilise query_posts() directement dans le template, en pensant simplement « remplacer » la requête par défaut.

Pourquoi c’est un problème : query_posts() détruit et reconstruit la requête principale de la page, ce qui casse la pagination native, désynchronise les hooks WooCommerce qui dépendent du contexte de boucle (woocommerce_product_loop_start, notamment), et provoque une requête SQL supplémentaire totalement inutile puisque la requête principale avait déjà été exécutée avant d’être jetée.

Quoi faire à la place : utiliser WP_Query dans une instance séparée pour un affichage secondaire, ou le shortcode [products] / le bloc Produits de WooCommerce pour un affichage standard, ou encore pre_get_posts pour modifier la requête principale existante sans la recréer :

add_action( 'pre_get_posts', function ( $query ) {
    if ( ! is_admin() && $query->is_main_query() && is_shop() ) {
        $query->set( 'posts_per_page', 24 );
        $query->set( 'orderby', 'popularity' );
    }
} );

Antipattern n° 2 : appeler wc_get_product dans une boucle sans mise en cache

Ce que l’on voit : une boucle qui affiche une liste d’articles apparentés ou de produits favoris, avec un appel à wc_get_product( $id ) à chaque itération pour récupérer chaque produit un par un.

Pourquoi c’est un problème : chaque appel non mis en cache déclenche potentiellement une requête SQL séparée. Sur une page qui affiche vingt produits liés, cela peut représenter des dizaines de requêtes supplémentaires, alors qu’une seule requête groupée suffirait. WooCommerce met en cache les objets produit récemment chargés dans le cache d’objets WordPress, mais seulement si celui-ci est persistant (Redis ou Memcached) — sur un cache d’objets non persistant, chaque nouvelle requête HTTP repart de zéro.

Quoi faire à la place : charger les produits en une seule requête via wc_get_products() avec un tableau d’identifiants, plutôt qu’un appel unitaire répété :

$produits = wc_get_products( [
    'include' => $tableau_ids_produits,
    'limit'   => -1,
] );
L'essentiel à retenir : query_posts casse la requête principale et ne devrait jamais servir à afficher des produits ; Appeler wc_get_product dans une boucle sans cache produit un nombre de requêtes qui explose ; Les hooks déclenchés sur chaque page ne doivent jamais contenir de requête non mise en cache

Antipattern n° 3 : recalculer le panier à chaque affichage de page

Ce que l’on voit : un mini-panier personnalisé dans le header qui appelle WC()->cart->get_cart_contents_count() ou recharge WC()->cart->calculate_totals() à chaque chargement de page, y compris sur des pages où le contenu du panier n’a strictement aucune raison d’avoir changé.

Pourquoi c’est un problème : calculate_totals() recalcule taxes, frais de port et remises à chaque appel, une opération relativement coûteuse qui n’a de sens qu’après une modification réelle du panier (ajout, suppression, changement de quantité). L’appeler systématiquement sur chaque affichage de page, y compris pour un simple compteur d’articles, gaspille des cycles CPU sur chaque requête du site.

Quoi faire à la place : utiliser WC()->cart->get_cart_contents_count() seul pour un compteur, qui lit directement le contenu du panier en session sans redéclencher de calcul de totaux, et réserver calculate_totals() aux hooks qui suivent une modification effective, comme woocommerce_add_to_cart ou woocommerce_cart_item_removed.

Antipattern n° 4 : des hooks globaux qui exécutent une requête non mise en cache

Ce que l’on voit : une action accrochée à wp_footer ou woocommerce_before_shop_loop, exécutée sur chaque page du site, qui interroge la base de données pour afficher un bandeau de produits « les plus vus » sans jamais mettre le résultat en cache.

Pourquoi c’est un problème : un hook déclenché sur chaque page transforme une requête ponctuellement coûteuse en charge permanente sur le serveur, à chaque visite, alors que le résultat change rarement d’une minute à l’autre.

Quoi faire à la place : envelopper la requête dans un transient avec une durée de vie raisonnable :

$produits_populaires = get_transient( 'produits_plus_vus' );
if ( false === $produits_populaires ) {
    $produits_populaires = wc_get_products( [
        'orderby' => 'popularity',
        'limit'   => 8,
    ] );
    set_transient( 'produits_plus_vus', $produits_populaires, HOUR_IN_SECONDS );
}

Comment les repérer sur une boutique existante

  • Activer Query Monitor en environnement de recadrage et observer le nombre total de requêtes SQL sur les pages boutique, catégorie et fiche produit ;
  • Rechercher query_posts dans l’ensemble du thème et des extensions personnalisées : sa présence est presque toujours un signal d’alerte ;
  • Repérer les appels à get_post_meta, wc_get_product ou calculate_totals situés à l’intérieur d’une boucle foreach.

Un audit de performance qui ne regarde que le temps de réponse global manque souvent l’essentiel : le nombre de requêtes SQL par page est un indicateur bien plus révélateur de dette technique qu’un simple chronomètre.

En résumé

Ces quatre antipatterns reviennent avec une régularité frappante d’un projet à l’autre, et aucun ne demande de réécriture complexe pour être corrigé : remplacer query_posts par pre_get_posts, grouper les appels produit, limiter les recalculs de panier à leur contexte réel, et mettre en cache les requêtes déclenchées globalement. Ce sont souvent ces corrections modestes, plutôt qu’un changement d’hébergement, qui rendent une boutique WooCommerce nettement plus rapide.

Partager :

À propos de l'auteur

Clément Hadrot

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi