Sur un site d’information, une page lente coûte des lecteurs. Dans une boutique en ligne, elle coûte des commandes, et le lien est bien plus direct. Une étude Deloitte de 2020 réalisée avec Google, portant sur des dizaines de sites de différents secteurs, a montré qu’une amélioration d’à peine un dixième de seconde des temps de chargement sur mobile était associée, dans le commerce de détail, à une hausse des conversions d’environ 8 %. Ce n’est pas une loi universelle, mais cela confirme ce que constate chaque jour quiconque gère un site e-commerce : la vitesse n’est pas un détail technique, c’est une ligne du compte de résultat.
WooCommerce est la plateforme e-commerce la plus utilisée dans le monde WordPress, et c’est aussi l’un des endroits où l’on perd le plus facilement les Core Web Vitals. Non pas parce qu’elle serait lente en soi, mais parce qu’elle réunit les caractéristiques d’un CMS et celles d’une application : des pages publiques que l’on peut mettre en cache, des pages personnelles qui ne le peuvent pas, des sessions, des paniers, des calculs de prix et de livraison, des scripts de paiement et un écosystème de plugins très riche. Dans cet article, nous suivons le parcours d’achat page par page, pour voir où cela ralentit et que faire.
Pages de catégorie : la vitrine
La page de catégorie est souvent le premier contact avec la boutique, surtout pour les visiteurs qui arrivent depuis Google ou depuis une campagne. C’est une grille de produits avec des images, des prix, des badges et des filtres, et ses problèmes typiques concernent le LCP et le CLS.
Pour le LCP, le plus grand élément est presque toujours la première image produit ou une bannière de catégorie. Les règles sont celles que nous avons vues pour le LCP : les images de la première ligne ne doivent pas être en lazy loading, la principale peut recevoir fetchpriority="high", et toutes doivent être servies dans le bon format et à la bonne taille. Un catalogue de milliers de photos transmises par les fournisseurs, souvent de plusieurs mégaoctets chacune, est le cas idéal pour la conversion automatique en WebP ou AVIF et pour des tailles responsives correctes.
Pour le CLS, les coupables habituels sont les filtres à facettes qui apparaissent après le chargement, les badges de remise ou de disponibilité insérés en JavaScript, les prix mis à jour après le premier affichage par des plugins de devises ou de listes de prix, et les bannières promotionnelles qui repoussent la grille vers le bas. Chaque élément qui arrive plus tard doit avoir son espace réservé dès le départ, comme l’explique l’article sur le CLS. Les plugins de filtrage les plus lourds méritent aussi une attention particulière côté serveur : sur de grands catalogues, les requêtes sur les taxonomies et les attributs de produits peuvent faire monter sensiblement le TTFB des pages filtrées, rarement mises en cache.
La fiche produit : là où se prend la décision
La fiche produit est l’endroit où l’utilisateur décide d’acheter, et c’est souvent la page la plus lourde de la boutique : galerie avec zoom et lightbox, variations, avis, produits associés, widgets de paiement en plusieurs fois, pixels publicitaires, parfois de la vidéo. L’image principale est presque toujours l’élément LCP : elle doit figurer dans le HTML initial, et non être générée par un slider JavaScript, et elle doit avoir des dimensions explicites. Les images suivantes de la galerie peuvent être en lazy loading, et le zoom ne se charge qu’à l’interaction.
Les variations méritent un développement à part. Pour les produits variables, WooCommerce place dans la page les données de toutes les variations, dans un attribut que JavaScript lit pour mettre à jour le prix, l’image et la disponibilité quand l’utilisateur choisit une taille ou une couleur. Au-delà d’un certain seuil, 30 variations par défaut, les données ne sont plus incluses et chaque choix déclenche une requête vers le serveur. Dans les deux cas, l’interaction peut devenir lente : avec beaucoup de données, à cause du travail sur le thread principal ; avec des requêtes, à cause de l’attente de la réponse. C’est l’un des endroits où l’INP d’une boutique se dégrade le plus souvent, surtout sur les smartphones de milieu de gamme, et c’est aussi le moment où l’utilisateur est le plus proche de l’achat.
Le bouton « Ajouter au panier » est l’autre interaction critique. Si le clic lance une requête AJAX, met à jour le mini-panier, ouvre un panneau latéral et envoie des événements à plusieurs plateformes publicitaires, le tout dans la même tâche, l’utilisateur peut attendre plusieurs centaines de millisecondes sans aucun retour visuel. La règle est de donner un retour immédiat, par exemple un bouton qui change d’état, et de reporter le reste après l’affichage.
Le panier et le problème du cache
Pour un visiteur anonyme, les pages d’une boutique peuvent être servies depuis le cache de page, avec un TTFB de quelques dizaines de millisecondes, comme nous l’avons vu à propos du TTFB et du cache de page. Mais dès que l’utilisateur ajoute un produit au panier, WooCommerce dépose des cookies de session, comme woocommerce_items_in_cart, et la plupart des configurations de cache cessent de servir des pages en cache à cet utilisateur, sur l’ensemble du site. C’est un choix prudent, pour éviter de montrer le panier d’une autre personne à un visiteur, mais il a une conséquence paradoxale : les utilisateurs les plus précieux, ceux qui ont déjà choisi quelque chose, naviguent sur la version la plus lente de la boutique.
Le panier, le tunnel de commande et le compte client ne peuvent par définition pas être mis en cache. Leur TTFB dépend entièrement de PHP et de la base de données, et ce qui fait la différence ici, c’est la version de PHP, un cache d’objets comme Redis, le nettoyage des options chargées automatiquement, la gestion des sessions et le stockage des commandes haute performance (HPOS), que WooCommerce utilise par défaut sur les nouvelles boutiques et qui déplace les commandes dans des tables dédiées.
Les cart fragments
Il existe ensuite un mécanisme qui a pénalisé pendant des années les boutiques WooCommerce, même avec le cache activé : ce que l’on appelle les cart fragments. Pour mettre à jour le mini-panier dans l’en-tête, un script envoie une requête AJAX vers ?wc-ajax=get_refreshed_fragments, qui ne peut pas être mise en cache et exige l’exécution complète de WordPress. La page arrive du cache en quelques millisecondes, mais juste après, le serveur a encore du travail à faire.
Depuis la version 7.8, WooCommerce ne charge ce script que là où le widget classique de mini-panier est réellement utilisé, et le mini-panier à base de blocs utilise une API différente, plus légère. De nombreux thèmes et plugins le réactivent toutefois sur chaque page. Le vérifier est simple : dans le panneau Network des DevTools, sur n’importe quelle page, cherchez la requête get_refreshed_fragments. Si elle apparaît même quand le panier est vide, c’est un coût payé à chaque page vue, et lors d’une promotion à fort trafic, elle peut saturer les ressources PHP au moment précis où elles sont nécessaires pour le panier et le paiement.
Le paiement : la dernière ligne droite
Le paiement est la page à la plus forte valeur par visite, et souvent celle dont on se soucie le moins en matière de performance. C’est un formulaire comportant de nombreux champs, dont chacun peut déclencher des validations, des calculs de livraison et de taxes, et des mises à jour du récapitulatif ; et il héberge les scripts des moyens de paiement, qui chargent à leur tour des iframes et des ressources provenant de domaines externes.
- Des mises à jour à chaque champ. Dans le tunnel de commande classique, modifier l’adresse, le code postal ou le mode de livraison lance une requête de mise à jour du récapitulatif. Si le serveur est lent, chaque modification se transforme en attente visible. La rapidité de cette requête dépend du TTFB des pages dynamiques, donc des mêmes mesures que celles décrites plus haut.
- Des scripts de paiement partout. De nombreux plugins de paiement chargent leurs propres scripts sur chaque page du site, même là où ils ne servent pas, pour afficher des messages promotionnels ou des boutons de paiement rapide. Les limiter à la fiche produit, au panier et au paiement, où ils sont réellement nécessaires, allège tout le reste.
- Champs et saisie semi-automatique. Saisie semi-automatique des adresses, validation du numéro de TVA, contrôles en temps réel : c’est utile, mais chacun ajoute du travail au thread principal pendant que l’utilisateur tape. Il faut les mesurer avec l’INP, et pas seulement les essayer à la main sur un ordinateur rapide.
- Paiement par blocs. Le tunnel de commande à base de blocs, par défaut dans les installations récentes, gère les mises à jour par l’API dédiée de la boutique et se comporte généralement mieux que le tunnel classique, mais il faut vérifier la compatibilité de chaque plugin qui touche au paiement avant de migrer.
Les services tiers du e-commerce
Une boutique en ligne tend à accumuler plus de code tiers que n’importe quel autre site : pixels de plusieurs plateformes publicitaires, outils de remarketing, widgets d’avis, chat, notifications d’achats récents, paiement en plusieurs fois, programmes de fidélité, tests A/B. Chacun a sa justification commerciale, et chacun prend du temps au thread principal. La méthode pour les garder sous contrôle est celle décrite dans l’article sur les scripts tiers : faire l’inventaire, mesurer le coût, retirer ce qui n’est plus utilisé, différer ce qui n’est pas nécessaire tout de suite. Sur un site e-commerce, il y a un avantage supplémentaire : on peut comparer la valeur de chaque outil au chiffre d’affaires qu’il contribue à générer, donc au coût en conversions que représente son poids.
Mesurer par modèle de page
Une boutique compte peu de modèles de page et beaucoup de pages par modèle : une page d’accueil, quelques dizaines de catégories, des milliers de produits. Les Core Web Vitals doivent donc se lire par groupe. La Search Console regroupe déjà les URL similaires ; un système de real user monitoring permet d’aller plus loin, en répartissant les données par modèle, par appareil et, surtout, par état de l’utilisateur : anonyme, avec des produits dans le panier, client connecté. C’est souvent le seul moyen de voir que la boutique est rapide pour ceux qui arrivent et lente pour ceux qui achètent.
L’étape suivante consiste à relier ces données aux indicateurs métier. Comparer le taux de conversion des sessions à bon LCP ou INP à celui des sessions à valeurs médiocres, sur un même modèle de page, donne une mesure concrète de ce que vaut une amélioration. C’est aussi le moyen le plus efficace de fixer les priorités : une modification de la fiche produit ayant un effet mesurable sur les conversions vaut plus qu’un score parfait sur une page institutionnelle.
Par où commencer
- Cache et TTFB. Cache de page pour les visiteurs anonymes, cache d’objets pour les pages dynamiques, PHP à jour, base de données propre, HPOS activé. Sans cette base, le reste rapporte peu.
- Requêtes non cachables. Vérifier les cart fragments et toute autre requête AJAX qui se déclenche à chaque page.
- Images du catalogue. Formats modernes, tailles correctes, pas de lazy loading pour les images au-dessus de la ligne de flottaison, priorité à l’image principale de la fiche produit.
- Interactions du parcours d’achat. Variations, ajout au panier, mise à jour des quantités, champs du paiement : mesurer l’INP et donner un retour immédiat.
- Services tiers et plugins. Limiter les scripts aux pages où ils sont nécessaires, retirer ce qui n’apporte aucune valeur, différer le reste.
- Navigation interne. Une fois les bases en place, les Speculation Rules entre catégorie et produit et la compatibilité avec le back/forward cache rendent instantanés les déplacements les plus fréquents, aller et retour entre la liste et la fiche produit.
En bref
Avec WooCommerce, les Core Web Vitals se perdent tout au long du parcours d’achat : LCP et CLS sur les catégories, LCP et INP sur la fiche produit, TTFB et INP dans le panier et le paiement. Le problème le plus sous-estimé est le cache : les utilisateurs ayant un panier actif, les plus proches de l’achat, naviguent souvent sans cache de page et supportent tout le poids de PHP et de la base de données, en plus de requêtes non cachables comme les cart fragments.
La voie à suivre est de mesurer par modèle de page et par état de l’utilisateur, de relier les indicateurs aux conversions et d’intervenir dans l’ordre : d’abord la base serveur, puis les requêtes superflues, les images, les interactions et les services tiers. Dans une boutique en ligne, chaque dixième de seconde a une valeur économique mesurable, et savoir où on la perd est le premier pas pour la récupérer.