Cache PrestaShop : erreurs fréquentes et bonnes pratiques multiboutique

Table des matières : Cartographier le “cache PrestaShop” en multiboutique (ce qui est réellement en jeu) En multiboutique, parler de “cache PrestaShop” comme d’un seul mécanisme est l’erreur racine. Vous avez au minimum trois couches qui se superposent et se contredisent parfois : (1) le cache applicatif côté PrestaShop (Smarty, Cache/ObjectModel, index de classes), (2)…

Ordinateur affichant du code avec symboles de cache et sécurité.

Table des matières :

  1. Cartographier le “cache PrestaShop” en multiboutique (ce qui est réellement en jeu)
  2. Erreurs fréquentes : quand la purge casse une boutique… ou toutes
  3. Purger sans se tirer une balle : procédures de purge/warmup (PrestaShop 9.x, PHP 8.2/8.3)
  4. Bonnes pratiques multiboutique : isolation des clés (Redis), Vary/headers, et reverse proxy
  5. Diagnostiquer proprement : métriques, reproductibilité, et tests de charge par boutique
  6. Checklist opérationnelle (multiboutique) : ce qu’on valide avant d’activer/renforcer un cache

Cartographier le “cache PrestaShop” en multiboutique (ce qui est réellement en jeu)

En multiboutique, parler de “cache PrestaShop” comme d’un seul mécanisme est l’erreur racine. Vous avez au minimum trois couches qui se superposent et se contredisent parfois : (1) le cache applicatif côté PrestaShop (Smarty, Cache/ObjectModel, index de classes), (2) le cache framework (container Symfony, routing, templates Twig pour le Back Office), (3) les caches d’infrastructure (OPcache, Redis/Memcached/APCu, reverse proxy type Varnish, CDN). Le symptôme “j’ai vidé le cache et rien ne change” ou “une boutique A affiche le thème de B” vient presque toujours d’un décalage entre les couches purgées et celles qui continuent à servir.

Depuis PrestaShop 8.x et surtout PrestaShop 9.x (Symfony 6.4, PHP 8.2+ en production, souvent PHP 8.3 en 2026), la partie Symfony est structurante : var/cache/{dev,prod} contient le container compilé, des métadonnées et des artefacts côté Back Office (routing compilé, services, proxies…). Dans la documentation Symfony, le dossier var/cache/ est explicitement présenté comme l’emplacement des caches applicatifs (et sa purge mal maîtrisée est un classique des 500 “intermittentes” quand les droits ou le warmup ne sont pas cohérents). En pratique : si vous supprimez ce répertoire sans comprendre votre stratégie de déploiement (droits, warmup, UID/GID en conteneur, atomic deploy), vous vous fabriquez des erreurs 500 pendant la régénération et des temps de réponse dégradés au premier trafic.

Côté “legacy”, PrestaShop conserve des caches plus spécifiques : compilation Smarty (thèmes, overrides de templates), agrégation CCC (CSS/JS), et caches “métier” stockés via la classe Cache (selon driver : filesystem, APCu, Memcached, Redis). En multiboutique, le point clé n’est pas “activer Redis” mais “garantir l’isolation des clés” (prefix/namespace) et la prise en compte du contexte (id_shop, id_shop_group, langue, devise). Si un module met en cache une réponse en oubliant id_shop, il crée une contamination cross-shop qui ne se corrige pas avec une purge partielle : le bug reviendra dès que la clé sera recréée.

Pour vous aider à visualiser “quoi purge quoi”, voici une cartographie utile en incident (elle évite de purger au hasard) :

Couche Où ça vit (souvent) Portée réelle en multiboutique Symptôme typique Purge/Action efficace
Symfony cache var/cache/prod Global au codebase (pas “par boutique”) BO KO, routes/services incohérents, 500 après déploiement bin/console cache:clear + warmup, droits corrects
Smarty / templates front caches/compilations liés au thème (selon version) Souvent partagé si même thème, sinon “collision” possible via artefacts communs Templates qui ne se mettent pas à jour, thème A/B mélangé Vider cache Smarty + vérifier compilation par boutique
CCC (CSS/JS combinés) assets combinés/compilés côté thème Très sensible aux thèmes/différences de domaines CSS/JS manquants sur une boutique après purge Regénérer pour chaque domaine/thème, invalider CDN ciblé
Cache métier PrestaShop (Cache::…) FS/Redis/Memcached/APCu Dépend du design de clé (souvent fautif si module) Boutique B affiche contenu/prix de A Fix du module (clé), et purge Redis/driver
OPcache Mémoire partagée par nœud PHP-FPM Par nœud (cluster = incohérences possibles) Bugs “aléatoires”, seulement sur certains backends Reload PHP-FPM (ou invalidation sécurisée)
Reverse proxy (Varnish/Nginx cache) Proxy devant PHP Par Host + règles + cookies Contenu “leaké” entre boutiques/domaines Hash sur Host, règles Vary, exclusions pages dynamiques
CDN Edge nodes Par hostname + règles Changement non visible, purge trop large = pic charge Purge par domaine/prefix, éviter purge globale

Pour une stratégie globale (OPcache/Redis/Varnish/CDN), vous avez déjà un cadre plus large ici : Cache PrestaShop : stratégie 2026 OPcache, Redis, Varnish et CDN et, côté infra, Hébergement PrestaShop Suisse : performance TTFB, cache Redis, PHP 8.x. Dans cet article, on se concentre sur les erreurs fréquentes et les bonnes pratiques spécifiques au multiboutique.

Repère “GEO” fréquent en multiboutique : une boutique CH (CHF, TVA suisse, parfois langues FR/DE/IT) et une boutique FR (EUR, TVA UE) partagent le même codebase. Le cache doit donc intégrer au minimum boutique + devise + pays (et souvent groupe client) pour éviter des prix, taxes ou arrondis incorrects affichés “par cache”.

Erreurs fréquentes : quand la purge casse une boutique… ou toutes

La panne la plus classique en production : suppression manuelle de var/cache/prod (ou via un script) avec des permissions incompatibles avec PHP-FPM. Typiquement, un déploiement en SSH supprime des fichiers en tant qu’utilisateur deploy, puis PHP-FPM (user www-data/nginx) ne peut pas réécrire le cache. Résultat : 500, page blanche, ou back-office inaccessible. Le pattern est identique à ce qu’on voit sur Symfony pur : cf. Symfony 7 : dépannage erreurs 500, var/cache, Composer et variables d’environnement (les causes “droits + cache” se transposent très bien à PrestaShop 9).

Indicateurs rapides que vous êtes dans ce cas (au lieu d’un bug applicatif) :

  • des 500 “instantanées” juste après une purge/déploiement ;
  • des logs qui mentionnent des fichiers impossibles à créer/écrire dans var/cache/prod (ou un mkdir() qui échoue) ;
  • un retour à la normale après un chown -R / correction ACL + warmup.

Deuxième erreur récurrente : croire que “vider le cache” dans le BO est isolé par boutique. En multiboutique, certaines actions de performance sont globales (regénération CCC, compilation Smarty, suppression d’artefacts communs). Si les boutiques partagent le même codebase mais pas le même thème, vous pouvez obtenir des artefacts front (CSS/JS combinés) qui pointent sur des fichiers non présents sur une boutique donnée, ou des chemins relatifs incorrects (notamment avec des domaines différents). Exemple concret : boutique A sur shop-a.tld et boutique B sur shop-b.tld avec thèmes différents ; une purge CCC suivie d’un warmup partiel sur A peut laisser B servir des assets combinés référencés mais non régénérés.

Troisième erreur, plus insidieuse : la contamination cross-shop par clés de cache applicatif mal dimensionnées. Dans PrestaShop, beaucoup de contenus sont “contextuels” (prix TTC/HT, groupe client, devise, langue, règles de taxes, disponibilité). Un cache correct doit au minimum intégrer un identifiant de boutique (id_shop) et souvent id_lang, id_currency, id_country, id_group. On voit régulièrement des modules qui cachent un HTML de bloc (ex. “produits populaires”, “menu catégories”) uniquement par id_lang ou pire, sans contexte du tout.

Mini-scénario très réaliste en multiboutique :

  • Boutique A = B2C, Boutique B = B2B, même catalogue.
  • Un module “top ventes” met en cache une requête et rend du HTML sans tenir compte du groupe client.
  • Un client B2C reçoit un bloc généré lors du passage d’un B2B (prix HT / remises / produits restreints), sans qu’aucun cookie “session” ne soit en jeu : c’est purement la clé de cache.

Dans ce cas, une purge du cache filesystem/Redis corrige “par chance”, puis le bug revient. Le bon correctif n’est pas d’augmenter la fréquence de purge : c’est d’inclure le contexte dans la clé ou de désactiver le cache pour le bloc en question tant que le module n’est pas corrigé.

Quatrième erreur : OPcache non invalidé lors d’un déploiement (surtout sur cluster). OPcache sert à stocker du bytecode PHP précompilé en mémoire partagée, ce qui accélère l’exécution… mais peut aussi conserver une version obsolète si vous déployez sans stratégie d’invalidation. Sur un load balancer, vous obtenez alors des comportements divergents selon le nœud touché. En multiboutique, c’est encore plus piégeux : une boutique peut “sembler OK” parce qu’elle emprunte moins de chemins de code (modules/overrides) tandis qu’une autre explose en erreurs fatales. Référence utile (et vérifiable) : documentation officielle PHP sur OPcache : OPcache (PHP Manual)

Pour une liste plus large des causes “front 500 / back 500”, vous pouvez croiser avec Erreur 500 PrestaShop : 10 causes fréquentes et solutions rapides. Mais en multiboutique, retenez surtout : (a) permissions, (b) artefacts partagés (CCC/Smarty), (c) clé de cache oubliant id_shop, (d) incohérences d’OPcache dans un cluster.

Purger sans se tirer une balle : procédures de purge/warmup (PrestaShop 9.x, PHP 8.2/8.3)

Pré-requis non négociables avant toute opération “cache” en prod : accès shell (ou au minimum exécution de commandes via CI), connaissance de l’utilisateur effectif de PHP-FPM, et une fenêtre de maintenance si vous touchez à var/cache/prod sur une boutique à trafic. Si vous êtes sur conteneurs/Kubernetes, ajoutez : volume persistant ou cache éphémère maîtrisé, et déploiement rolling (sinon vous warmupez à chaque pod et vous vous auto-DDoS au redémarrage). Sur ces sujets de déploiement, les checklists d’infra vous aideront, même si elles ne sont pas “cache” au sens strict : Migration PrestaShop vers Kubernetes : checklist GitOps et pièges courants.

Avant de purger “profond”, validez 2 points simples qui évitent 80% des crashs :

  • Qui écrit dans var/cache/ ? (user/group PHP-FPM, ACL, umask). Un stat var/cache/prod ou un simple test d’écriture via le bon user vaut de l’or.
  • Avez-vous un warmup orchestré ? Si non, le premier trafic (humain ou bot) va compiler “en live” et vous verrez p95/p99 exploser.

Côté Symfony (donc PrestaShop 9.x), la purge correcte est la séquence : clear puis warmup, dans le bon environnement, et avec le bon utilisateur. Exemple (adapter le chemin PHP, l’admin folder, et exécuter en tant que user du pool PHP-FPM si possible) :

# Sur un PrestaShop 9.x (Symfony 6.4), en prod
cd /var/www/prestashop
sudo -u www-data php -d memory_limit=1G bin/console cache:clear --env=prod
sudo -u www-data php -d memory_limit=1G bin/console cache:warmup --env=prod

Cette approche évite le “premier visiteur” qui paye la compilation du container. En multiboutique, vous devez ensuite vérifier la régénération des caches front (Smarty/CCC) pour chaque boutique, parce que l’URL, le thème, et certaines configs peuvent différer.

Concrètement, un warmup “HTTP” (curl) par domaine est souvent nécessaire après une purge profonde : hit des pages critiques (home, catégorie, produit, panier, login) sur A et B. Sans cela, vous mesurez un TTFB catastrophique au début (et les robots aussi). Pour cadrer ces impacts, recoupez avec PrestaShop lent : diagnostic TTFB, bots et optimisation serveur.

Un warmup minimaliste et “safe” (à adapter) ressemble à ceci dans une CI/CD :

Évitez la purge “rm -rf var/cache/*” depuis un script exécuté en root sans chown/acl derrière. Si vous voulez vraiment nettoyer au niveau filesystem (cas d’un cache corrompu), faites-le de manière déterministe :

# Stopper les workers si vous avez du traitement de files qui affecte le front
# (optionnel selon votre architecture)

sudo -u www-data rm -rf var/cache/prod/*
sudo -u www-data mkdir -p var/cache/prod
sudo -u www-data php bin/console cache:warmup --env=prod

Enfin, si vous déployez du code PHP (modules/overrides), prévoyez l’invalidation OPcache par pool/nœud. Selon votre SAPI et votre politique, ça passe par un reload PHP-FPM (systemctl reload php8.3-fpm) ou par une endpoint dédiée (à sécuriser strictement). Ne mélangez pas : “vider le cache PrestaShop” ne purge pas OPcache.

Point important en multiboutique sur cluster : l’ordre des opérations compte. Si vous purgez var/cache/prod sur un nœud et pas sur un autre, vous créez une fenêtre où le load balancer sert deux versions de cache/container. La meilleure pratique est soit :

  • purge/warmup sur chaque nœud (orchestré), puis remise en rotation,
  • soit un déploiement “immutable” (nouvelle release + switch), pour éviter une purge in-place.

Bonnes pratiques multiboutique : isolation des clés (Redis), Vary/headers, et reverse proxy

Si vous utilisez Redis comme cache applicatif, basez-vous sur une séparation explicite des clés par environnement et par boutique (au moins). Redis est couramment utilisé comme cache, mais le problème n’est pas Redis ; le problème est votre key design. Dans PrestaShop multiboutique, vous devez auditer les clés émises (dans les modules critiques) et vérifier que id_shop est inclus. Quand ce n’est pas le cas, corriger le module est souvent plus rentable que “purger plus souvent”. Une purge agressive masque un bug de clé et finit en dette technique.

Bon réflexe d’audit (simple, mais efficace) :

  • identifiez 3–5 modules qui génèrent du HTML “bloc” (menu, cross-sell, produits populaires, CMS, avis),
  • reproduisez une page sur boutique A puis B (mêmes conditions navigateur),
  • regardez si le contenu change correctement sans purge,
  • si non : suspectez une clé de cache trop large (ou un reverse proxy mal isolé).

Sur une stack multi-pays (ex. FR/CH), ajoutez systématiquement au raisonnement que certaines différences ne se voient pas tout de suite (TVA, devise, arrondis, disponibilité selon pays). Un cache “bancal” peut être silencieux en période calme puis exploser lors d’un changement de taxe/règle de prix.

Sur reverse proxy (Varnish/Nginx cache), l’isolement se joue au niveau de la clé de cache HTTP : host + path ne suffit pas si votre boutique dépend de cookies, d’en-têtes, ou de paramètres. Varnish est un reverse proxy HTTP ; en multiboutique, la règle minimale est d’inclure Host dans le hash (sinon A et B partagent des objets), et de refuser de mettre en cache les pages personnalisées (panier, compte, checkout). Ensuite, gérez correctement Vary (langue, devise si pilotées par cookie) et les cookies PrestaShop. Le “Vary: Cookie” global est un anti-pattern : ça tue le hit ratio. Préférez whitelister des cookies pertinents (ex. langue) et ignorer ceux qui ne changent pas le HTML.

Astuce pragmatique côté HTTP (sans “sur-optimiser”) :

  • mettez en cache uniquement les pages réellement publiques (home, catégories, CMS publiques, fiches produit si prix/stocks ne dépendent pas d’un contexte cookie),
  • refusez le cache dès qu’un cookie de session/auth est présent,
  • et logguez un header de diagnostic (ex. X-Cache: HIT/MISS au niveau reverse proxy) pour arrêter de débattre “à l’aveugle” en incident.

Si vous avez un CDN devant des boutiques multi-domaines, vous devez clarifier la granularité : cache par hostname (recommandé) et invalidation ciblée (purge par prefix sur un domaine). Beaucoup de shops multiboutiques échouent sur une purge CDN “globale” qui invalide tout le parc et provoque un pic de charge simultané sur PrestaShop (thundering herd). Pour choisir un CDN et comprendre les implications de purge, voir CDN : comparatif Cloudflare, Fastly, Akamai, CloudFront, Bunny.net, KeyCDN.

Cas pratique (observé en prod) : deux boutiques partagent la même base, mais ont des règles de prix spécifiques. Un reverse proxy mal configuré met en cache /category/42 en se basant uniquement sur URL + host, alors que la boutique utilise un cookie groupe client (B2B/B2C). Résultat : un client B2C voit des prix B2B “cachés”. Ce n’est pas un bug PrestaShop, c’est une faute de design de cache HTTP. La correction : exclure ces pages du cache, ou intégrer le contexte dans la clé (header/cookie stable) — et accepter le coût sur le hit ratio.

Diagnostiquer proprement : métriques, reproductibilité, et tests de charge par boutique

La bonne pratique qui manque dans 80% des incidents “cache PrestaShop multiboutique” : instrumenter et mesurer. Sans métriques, vous ne savez pas si vous avez un problème de hit ratio, de verrouillage disque, de purge trop large, ou d’OPcache incohérent.

À minima (et en restant opérationnel), suivez par boutique/domaine :

  • TTFB p95 (et idéalement p99) : avant/après purge, avant/après warmup.
  • PHP-FPM : saturation (max children), slowlog, durée moyenne des requêtes.
  • MySQL/MariaDB : slow queries, locks, temps d’exécution des requêtes catalogue.
  • Redis (si utilisé) : hits/misses et latence ; une hausse des misses après purge est normale, mais une persistance de misses indique une clé instable (ou un cache jamais utilisé).
  • Reverse proxy : hit ratio, objets bannis/purgés, taux de pass.

Pour la supervision, une solution type Netdata est adaptée parce qu’elle vous donne rapidement des corrélations (CPU, IO, latence DB, saturation FPM) : Netdata : intégrer Prometheus, SNMP et StatsD pour tout surveiller.

En multiboutique, vos tests doivent être par boutique et par domaine, pas “le site”. Les caches d’assets, les cookies de contexte, et les règles SEO (hreflang/canonical) peuvent diverger. Exemple de protocole reproductible : (1) purge contrôlée, (2) warmup HTTP sur A, (3) warmup HTTP sur B, (4) test de charge séparé (k6/ab/wrk) sur A puis B, (5) comparaison des p95/p99 et du hit ratio. Si B se dégrade après warmup A, vous avez une contamination (clé cache applicatif ou reverse proxy). Pour les méthodes d’audit perf orientées parcours, recoupez avec Optimisation PrestaShop : audit performance checkout et plan d’action.

Quand le symptôme est “ça change selon le nœud”, suspectez OPcache et la cohérence de déploiement. Sur un cluster, ajoutez une vérification post-déploiement :

  • même commit SHA sur chaque nœud,
  • même timestamp des fichiers critiques (modules, overrides, vendor/),
  • même version de PHP et mêmes extensions chargées,
  • et un reload PHP-FPM orchestré (pas “au petit bonheur la chance”).

Si vous êtes sur Kubernetes, assurez-vous que l’image contient déjà les dépendances et que le pod n’exécute pas composer install à chaud (c’est un générateur de divergence + cache invalide). Pour cadrer les points de déploiement PHP-FPM/cache, la lecture croisée de Symfony 7 : déploiement PHP-FPM Nginx, cache et opcache reste pertinente.

Enfin, n’oubliez pas la reproductibilité au niveau base : une purge cache qui “résout” un bug peut simplement masquer une incohérence data (index manquant, requêtes lentes, contention InnoDB) qui revient à la première montée en charge. Si vos p95 explosent après purge, regardez MySQL/MariaDB (slow queries, buffer pool) avant d’accuser le cache. Sur ce volet, vous avez des guides solides : Audit MySQL/MariaDB : optimiser les requêtes lentes e‑commerce et PrestaShop performance : optimiser cache, images WebP et base MySQL.

Checklist opérationnelle (multiboutique) : ce qu’on valide avant d’activer/renforcer un cache

Validez d’abord l’isolation fonctionnelle : domaines distincts bien routés, contextes shop correctement détectés, et absence de modules qui partagent du contenu sans clé id_shop. En pratique, ça implique un audit de quelques caches sensibles : menus, blocs “featured”, prix, disponibilité, facettes, pages CMS.

Checklist courte (utile avant d’ajouter Varnish/CDN agressif) :

  • [ ] Chaque domaine pointe vers la bonne boutique (pas d’ambiguïté DNS/Host, pas de fallback “default shop”).
  • [ ] Les pages publiques affichent bien la bonne devise/langue/pays sans cookie (test en navigation privée).
  • [ ] Les modules “blocs HTML” critiques intègrent id_shop (et si besoin id_currency, id_country, id_group) dans leurs caches.
  • [ ] CCC/Smarty : purge et régénération testées pour chaque boutique (au moins home + catégorie + PDP).
  • [ ] Les règles d’exclusion cache HTTP couvrent compte/panier/checkout + toute page personnalisée (prix B2B/B2C, contenu selon login).
  • [ ] OPcache : stratégie d’invalidation documentée (reload pool/nœud à chaque déploiement PHP).

Les moteurs de recherche/facettes sont aussi des zones à cache “dangereux” : si vous avez ps_facetedsearch ou un moteur externe, les paramètres et la combinatoire peuvent exploser les clés et la taille mémoire. Si vous externalisez la recherche, le sujet est à traiter à part (et mieux) : Elasticsearch PrestaShop : accélérer la recherche et les facettes catalogue.

Validez ensuite la chaîne de purge : qui purge quoi, quand, et comment c’est orchestré. Une purge “globale” doit être exceptionnelle. En multiboutique, préférez : (a) purge ciblée par domaine (CDN), (b) invalidation par tags/prefix si votre reverse proxy le supporte, (c) warmup HTTP par boutique, (d) invalidation OPcache synchronisée. Si votre process de déploiement ne permet pas ça, la “bonne pratique cache” est de ne pas pousser des caches agressifs (Varnish full page) tant que l’outillage n’est pas au niveau.

Enfin, validez les garde-fous : logs exploitables, supervision, et procédure de rollback (code + config cache). Une configuration de cache multiboutique correcte doit être réversible rapidement : désactiver le reverse proxy, bypass CDN sur un domaine, repasser Cache en filesystem si Redis tombe, etc.

En cas d’incident, le bon réflexe n’est pas “vider tous les caches”, c’est de localiser la couche fautive (HTTP vs applicatif vs OPcache) et de corriger l’isolation. C’est moins spectaculaire, mais c’est la seule façon d’éviter que la même panne revienne au prochain pic de trafic.


À lire aussi