« Pourquoi la mairie de la commune B voit-elle parfois s’afficher un bandeau d’alerte météo destiné à la commune A ? » Cette question, posée par un chargé de communication, a ouvert un audit qui a révélé un défaut d’architecture bien plus large qu’un simple bug d’affichage : sur ce réseau multisite regroupant les sites de 500 communes, l’objet de cache Redis partagé mélangeait, dans certaines conditions, les transients de sites différents.
Arborescence du réseau et du cache
Réseau multisite WordPress (500 sites)
├── Site 1 (commune-a.reseau.fr) — blog_id = 2
│ └── transient: alerte_meteo (censé être propre au site 2)
├── Site 2 (commune-b.reseau.fr) — blog_id = 3
│ └── transient: alerte_meteo (lu par erreur depuis le site 2 !)
├── ...
└── Instance Redis partagée (object-cache.php, un seul serveur)
└── Espace de clés commun à tous les blog_id
Le point de vigilance sur un multisite tient au fait que WordPress isole nativement les données en base par préfixe de table (wp_2_options, wp_3_options…), mais que cette isolation ne se propage pas automatiquement au cache objet si l’implémentation ne le prévoit pas explicitement.
Où se cachait la fuite
Le plugin d’objet de cache Redis utilisé préfixait correctement les clés par blog_id pour l’immense majorité des groupes de cache. Mais un groupe personnalisé, ajouté par une extension tierce de gestion des alertes météo communales, avait été déclaré comme « global » via wp_cache_add_global_groups(), une fonction précisément conçue pour les données réellement partagées entre tous les sites du réseau (comme les options réseau). Le développeur de cette extension l’avait utilisée par erreur pour un cache qui, en réalité, devait rester local à chaque site.

// Erreur trouvée dans l'extension tierce :
wp_cache_add_global_groups( [ 'alertes_meteo' ] );
// Cette déclaration retire le préfixe blog_id pour tout ce groupe,
// rendant ses clés visibles et partagées par les 500 sites du réseau.
Concrètement, une clé alerte_meteo_du_jour écrite par le site de la commune A écrasait ou masquait la même clé pour les 499 autres sites, puisque le groupe global ne préfixe jamais par blog_id, contrairement aux groupes standards.
Architecture recommandée pour un cache Redis partagé à grande échelle
- Une seule instance Redis peut parfaitement servir 500 sites, à condition que chaque clé porte un préfixe de site non ambigu, généré automatiquement par l’objet de cache et jamais contournable par une extension tierce.
- La liste des groupes globaux doit rester courte, documentée, et revue à chaque ajout d’extension : en pratique, seuls les réglages réellement partagés au niveau réseau (comme les rôles utilisateurs réseau) justifient ce statut.
- Un audit périodique des clés Redis, via
redis-cli --scan --patterncouplé à un script qui vérifie la cohérence des préfixesblog_id, permet de détecter une fuite avant qu’un utilisateur ne la signale.
La correction appliquée
La correction a consisté à retirer alertes_meteo de la liste des groupes globaux, pour qu’il redevienne un groupe standard préfixé automatiquement par site. Un script de purge complète du cache Redis a ensuite été exécuté pour éliminer toute clé mal préfixée restante, suivi d’un contrôle manuel sur un échantillon de dix communes pour confirmer que chacune ne voyait plus que ses propres alertes.
wp redis flush --network
wp cache flush --url=commune-a.reseau.fr
wp cache flush --url=commune-b.reseau.fr
Ce qu’il faut vérifier avant chaque nouvelle extension
Depuis cet incident, toute extension tierce installée sur ce réseau passe par une revue de code ciblée sur un point précis : recherche de tout appel à wp_cache_add_global_groups() ou wp_cache_add_non_persistent_groups(), et validation explicite que l’usage est justifié. Cette vérification prend moins de cinq minutes par extension et a déjà permis d’écarter deux autres cas similaires avant leur mise en production.
Sur un multisite, un groupe de cache déclaré « global » par erreur n’est pas un ralentissement : c’est une fuite de données entre organisations qui n’ont rien à voir entre elles.
En résumé
Un cache d’objets Redis partagé entre 500 sites d’un même réseau multisite fonctionne parfaitement à condition que l’isolation par blog_id reste garantie sur chaque groupe de cache. Le risque ne vient généralement pas de Redis lui-même, mais d’une extension tierce qui déclare à tort un groupe comme global. Un audit de code ciblé sur cette fonction, répété à chaque nouvelle extension, reste la meilleure prévention contre ce type de fuite silencieuse.