« Ça fonctionne très bien sur nos dix sites de test » : cette phrase, entendue lors de la revue d’une extension réseau avant son déploiement sur un multisite de cinq cents sites, aurait dû alerter davantage. Une architecture d’extension réseau qui se comporte correctement à dix sites peut s’effondrer très différemment à cinq cents, non pas parce que le code contient un bug, mais parce que certains choix qui n’ont aucun impact mesurable à petite échelle deviennent des goulots d’étranglement sévères une fois multipliés par cinquante.
Le cas le plus révélateur concerne une extension qui synchronisait une table d’options partagées à chaque activation de plugin sur chaque site du réseau, via le hook wpmu_new_blog. Sur dix sites, l’opération passait inaperçue. Sur cinq cents, la création d’un nouveau site du réseau déclenchait cinq cents écritures en cascade dans la table réseau, ralentissant visiblement l’ensemble de l’interface d’administration du réseau pendant plusieurs secondes.
Où se situent les vrais goulots d’étranglement à cette échelle
Trois zones concentrent l’essentiel des problèmes de performance sur un multisite de grande taille : les tables partagées au niveau réseau (wp_sitemeta, wp_blogs), les hooks globaux exécutés systématiquement sur chaque site, et le cache d’objet quand il n’est pas correctement segmenté par site. Une extension conçue sans anticiper ces trois zones fonctionnera à petite échelle et deviendra un problème de performance réseau à mesure que le nombre de sites augmente.
La table wp_sitemeta comme piège classique
Stocker un réglage global d’extension dans wp_sitemeta via update_network_option() est parfaitement adapté à une configuration réseau unique, partagée par tous les sites. Le piège survient quand un développeur y stocke, par erreur d’architecture, des données spécifiques à chaque site individuel sous des clés dynamiques (mon_ext_reglages_site_42), ce qui transforme une table pensée pour un nombre restreint d’entrées globales en une table qui grossit linéairement avec le nombre de sites, ralentissant chaque requête qui la parcourt intégralement.
Éviter les hooks globaux coûteux à la création de site

Le hook wpmu_new_blog (ou son équivalent plus récent wp_initialize_site) doit être traité avec une prudence particulière : tout ce qui s’y exécute a un coût multiplié par le rythme de création de nouveaux sites du réseau. Une extension bien conçue à cette échelle différencie l’initialisation strictement nécessaire à la création (créer les tables propres au site, définir les valeurs par défaut minimales) de tout ce qui peut être différé au premier accès réel du site :
add_action( 'wp_initialize_site', function ( WP_Site $site ) {
switch_to_blog( $site->blog_id );
// Uniquement le strict nécessaire : pas de synchronisation
// lourde, pas d'appel API externe à ce stade.
add_option( 'mon_ext_version_installee', MON_EXT_VERSION );
restore_current_blog();
}, 10, 1 );
Chaque appel à switch_to_blog() et restore_current_blog() a un coût réel (rechargement du contexte de requêtes, changement de préfixe de table) : sur une boucle qui parcourrait les cinq cents sites du réseau pour une opération d’administration, ces appels répétés peuvent représenter une part significative du temps d’exécution total.
Segmenter le cache d’objet par site
Un cache d’objet persistant (Redis ou Memcached) partagé entre tous les sites du réseau doit isoler ses clés par identifiant de site, faute de quoi deux sites différents peuvent se retrouver à lire ou écraser la valeur en cache l’un de l’autre. WordPress gère cette isolation automatiquement pour les groupes de cache non déclarés comme globaux, mais une extension qui appelle wp_cache_set() avec un groupe personnalisé doit vérifier explicitement que ce groupe n’est pas enregistré par erreur via wp_cache_add_global_groups().
Arborescence type d’une extension réseau pensée pour l’échelle
mon-extension-reseau/
├── mon-extension.php
├── includes/
│ ├── class-reglages-reseau.php (wp_sitemeta, une seule fois)
│ ├── class-reglages-site.php (options par site, isolées)
│ ├── class-initialisation-site.php (hooks légers uniquement)
│ └── class-cache-segmente.php
└── admin/
└── ecran-reseau.php
Ce qui reste hors du périmètre de l’extension
Cette architecture concerne exclusivement la conception de l’extension elle-même. Les questions plus larges de performance générale d’un multisite à cette échelle — configuration serveur, répartition de charge, choix d’un cache d’objet persistant adapté — relèvent d’une réflexion d’infrastructure distincte, qui dépasse le périmètre du code d’une seule extension.
La question à se poser systématiquement avant d’écrire un hook réseau : « que se passe-t-il si ce code s’exécute cinq cents fois d’affilée en quelques secondes ? ». La réponse change souvent radicalement la conception initialement envisagée.
En résumé
Une extension réseau conçue pour un multisite de grande taille doit traiter différemment ce qui est réellement global (réglages réseau uniques) de ce qui est spécifique à chaque site, éviter les hooks globaux coûteux exécutés en boucle, et segmenter correctement son cache d’objet. Ces précautions, invisibles sur un multisite de test à dix sites, deviennent la différence entre une extension qui tient la charge et une extension qui ralentit visiblement l’ensemble du réseau une fois déployée à grande échelle.