Si vous avez déjà vu un site “fantôme” qui renvoie une 404 alors que le tableau de bord Multisite l’affiche bien, vous avez touché du doigt le vrai sujet : Multisite, ce n’est pas juste un toggle, c’est une architecture.

Ce qu’on va construire

Vous allez mettre en place un réseau WordPress Multisite stable sous WordPress 6.9.4 (avril 2026) et PHP 8.1+, avec :

  • un réseau en sous-domaines ou en sous-répertoires, correctement réécrit côté serveur ;
  • le domain mapping natif (sans plugin) avec HTTPS ;
  • une stratégie claire plugins/thèmes : activation réseau, MU-plugins, limitations par site ;
  • un provisionnement automatisé des nouveaux sites (WP-CLI + hooks) ;
  • des garde-fous : sécurité, perf, maintenance, et un plan de dépannage réaliste.

À la fin, vous saurez diagnostiquer les 404, les redirections de login, les médias introuvables, les conflits de cache et les pièges de configuration que je croise le plus souvent sur des réseaux “vite faits” en production.

Résumé rapide

  • Choisissez sous-domaines si vous avez besoin de domaines par site, d’isolement SEO, ou d’un futur mapping ; sous-répertoires si vous voulez une structure simple et peu de DNS.
  • Activez Multisite via WP_ALLOW_MULTISITE, puis laissez l’écran Réseau générer les constantes (ne les tapez pas “de mémoire”).
  • Le 80% des bugs viennent des règles Nginx/Apache ou d’un proxy/CDN qui ne relaie pas Host / X-Forwarded-Proto.
  • Utilisez le domain mapping natif + certificats valides ; évitez les redirections “maison” dans wp-config.php.
  • Automatisez : WP-CLI pour créer les sites, hook wpmu_new_blog (ou wp_initialize_site) pour configurer.
  • Testez avec un site “neuf”, un site “mappé”, un site avec builder, et un site avec cache activé.

Quand utiliser cette solution

  • Vous gérez plusieurs sites avec une base technique commune (mêmes plugins, même thème, même stack).
  • Vous voulez une gouvernance centralisée : mises à jour, politiques de plugins, rôles, capacités.
  • Vous avez un cas “franchise” / “réseau de blogs” / “sites par client” où l’isolation par installation serait trop coûteuse.
  • Vous avez besoin de domain mapping à grande échelle (site-a.com, site-b.com) tout en gardant un core unique.

Quand ne PAS utiliser cette solution

  • Vos sites doivent avoir des stacks très différentes (plugins incompatibles entre eux, thèmes très divergents, exigences PHP différentes).
  • Vous devez donner un accès “super-admin” à des tiers : Multisite rend ce rôle extrêmement puissant.
  • Vous avez des exigences fortes d’isolation (conformité, cloisonnement client) : une faille plugin sur un site peut impacter l’ensemble du réseau.
  • Vous avez besoin de déploiements indépendants (cadence de release différente par site). Dans ce cas, plusieurs installations + automatisation (Ansible, GitHub Actions, etc.) est souvent plus sain.

Avant de commencer (prérequis)

Avant toute bascule, faites-le sur un clone. J’ai souvent vu des réseaux “cassés” parce que Multisite a été activé directement en prod, puis désactivé à la va-vite : on se retrouve avec des tables et des options incohérentes.

Pré-requis techniques

  • WordPress 6.9.4 (ou plus récent) et PHP 8.1+.
  • Accès au serveur (au minimum : éditer wp-config.php et les règles Nginx/Apache).
  • Accès DNS si vous choisissez les sous-domaines (wildcard recommandé).
  • WP-CLI conseillé : Commandes WP-CLI (developer.wordpress.org).

Sauvegarde et environnement

  • Sauvegarde fichiers + base (et test de restauration). Si vous êtes sur MySQL/MariaDB, gardez un dump compressé et horodaté.
  • Si possible, un environnement de staging avec le même reverse proxy/CDN (Cloudflare, Fastly, etc.).

Sécurité

  • Vérifiez que l’accès à /wp-admin/network/ sera limité aux comptes nécessaires.
  • Évitez de coller des snippets trouvés sur des vieux posts : beaucoup de “recettes” Multisite datent d’avant le domain mapping natif.

Docs officielles utiles


Étape 1 : Préparer un environnement Multisite propre (DNS, SSL, sauvegarde)

1) Choisir sous-domaines ou sous-répertoires

Le choix impacte le DNS, les cookies, et parfois des plugins.

  • Sous-domaines : site1.exemple.com, site2.exemple.com. Recommandé si vous prévoyez du domain mapping, ou si vous voulez une séparation nette.
  • Sous-répertoires : exemple.com/site1, exemple.com/site2. Plus simple côté DNS, mais certains cas (site existant depuis longtemps, structures d’URL) peuvent être contraignants.

2) DNS (si sous-domaines)

Créez un wildcard :

  • Enregistrement A : *.exemple.com → IP du serveur
  • ou CNAME : *.exemple.comexemple.com

Résultat attendu : foo.exemple.com et bar.exemple.com pointent vers votre WordPress (même si ça renvoie encore une 404 côté WP, c’est normal à ce stade).

3) SSL

Pour sous-domaines, utilisez un certificat wildcard (Let’s Encrypt DNS-01 est le plus propre). Pour domain mapping multi-domaines, prévoyez une stratégie (SAN multi-domaines, ou certificats par vhost si vous terminez TLS au niveau du serveur).

4) Vérifier la stack serveur

Deux points qui cassent Multisite plus souvent qu’on ne l’admet :

  • Un reverse proxy qui ne transmet pas correctement Host et le schéma HTTPS (typiquement X-Forwarded-Proto), ce qui provoque des redirections de login infinies.
  • Un cache full-page qui met en cache des pages d’admin ou des redirections 301/302.

Étape 2 : Activer le mode Multisite dans wp-config.php

Vous allez activer l’option, puis passer par l’UI réseau pour générer les constantes correctes.

1) Éditer wp-config.php

Ouvrez wp-config.php à la racine de l’installation. Ajoutez ceci au-dessus de la ligne “That’s all, stop editing!” (ou équivalent) :

<?php
// Active l'écran d'installation Multisite dans l'admin.
// À ajouter dans wp-config.php, au-dessus de "That's all, stop editing!".
define( 'WP_ALLOW_MULTISITE', true );

2) Activer via l’admin

  1. Connectez-vous à wp-admin en admin.
  2. Allez dans Outils → Création du réseau (ou “Network Setup”).
  3. Choisissez Sous-domaines ou Sous-répertoires.
  4. Renseignez le titre du réseau et l’email admin.
  5. Validez.

Résultat attendu : WordPress vous affiche deux blocs à copier : un bloc pour wp-config.php et un bloc de règles pour le serveur (.htaccess ou indications Nginx).

Piège classique : recopier un snippet “générique” trouvé sur un forum. L’écran réseau génère des constantes adaptées à votre DOMAIN_CURRENT_SITE, PATH_CURRENT_SITE et au mode (subdomain/subdir). Copiez-collez, puis relisez.


Étape 3 : Installer le réseau (sous-domaines vs sous-répertoires) et finaliser la config

1) Copier les constantes Multisite dans wp-config.php

L’écran vous fournit quelque chose de proche de ceci (exemple). Collez-le au-dessus de “That’s all, stop editing!” :

<?php
// --- Configuration Multisite (exemple) ---
// Attention : adaptez aux valeurs fournies par votre écran "Création du réseau".

define( 'MULTISITE', true );
define( 'SUBDOMAIN_INSTALL', true ); // true = sous-domaines, false = sous-répertoires
define( 'DOMAIN_CURRENT_SITE', 'exemple.com' );
define( 'PATH_CURRENT_SITE', '/' );
define( 'SITE_ID_CURRENT_SITE', 1 );
define( 'BLOG_ID_CURRENT_SITE', 1 );

// Recommandation pratique : désactiver l'édition de fichiers via l'admin sur un réseau.
define( 'DISALLOW_FILE_EDIT', true );

Résultat attendu : après reconnexion, vous voyez le menu Mes sites dans la barre d’admin, et l’entrée Administration du réseau.

2) Se reconnecter

WordPress vous déconnecte souvent après activation. C’est normal : cookies et chemins changent. Reconnectez-vous, puis allez dans :

  • Mes sites → Administration du réseau → Tableau de bord

3) Créer un premier site

  1. Administration du réseau → Sites → Ajouter
  2. Créez site-test (sous-domaine) ou /site-test/ (sous-répertoire).
  3. Ouvrez le site en front.

Résultat attendu : le site s’affiche, même si le thème est basique. Si vous obtenez une 404, passez directement à l’étape 4 (réécriture serveur).


Étape 4 : Règles serveur (Apache/Nginx) et pièges de réécriture

Le Multisite “marche” quand WordPress reçoit des requêtes cohérentes (host + path) et que la réécriture redirige vers index.php correctement. Tout le reste est secondaire.

Apache (.htaccess)

Si vous êtes sur Apache avec AllowOverride, remplacez vos règles WordPress par celles fournies par l’écran réseau. Exemple typique :

# Exemple .htaccess Multisite (à copier depuis l'écran réseau)
# Placez-le à la racine WordPress, en remplaçant les anciennes règles.

Je ne recopie pas volontairement un bloc “universel” ici : il varie selon votre mode (subdomain/subdir) et votre installation (répertoire racine ou sous-dossier). Copiez celui de votre admin réseau, sinon vous allez courir après des 404 pendant une heure.

Nginx (server block)

Sur Nginx, vous devez router les fichiers existants, puis tout le reste vers index.php. Exemple de base (à adapter à votre conf PHP-FPM) :

# Extrait Nginx (exemple) pour WordPress Multisite.
# À intégrer dans votre server { }.

location / {
  try_files $uri $uri/ /index.php?$args;
}

# Éviter d'exposer des fichiers sensibles
location ~* /(wp-config.php|readme.html|license.txt) {
  deny all;
}

Cas fréquent : vous avez un CDN/proxy devant Nginx. Si WordPress croit être en HTTP, il génère des URLs HTTP et des cookies non sécurisés. Assurez-vous que votre stack relaie le schéma. Selon votre proxy, vous aurez besoin de :

<?php
// Dans wp-config.php, uniquement si vous terminez TLS sur un proxy
// et que WordPress ne détecte pas HTTPS correctement.
// Risque : si mal configuré, vous pouvez forcer HTTPS même sur des requêtes internes.
if ( ! empty( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https' ) {
	$_SERVER['HTTPS'] = 'on';
}

Je l’ajoute seulement quand c’est nécessaire. Si votre hébergeur gère déjà correctement $_SERVER['HTTPS'], ce snippet peut créer des effets de bord (redirections, mixed content).


Étape 5 : Configurer le réseau (settings, inscriptions, uploads, mails)

1) Réglages réseau

Allez dans Administration du réseau → Réglages et configurez :

  • Inscription : qui peut créer des sites/utilisateurs. Sur un réseau pro, je désactive souvent la création libre de sites.
  • Notifications : vérifiez l’adresse expéditeur et le comportement SMTP (sinon vous perdez des mails d’activation).
  • Limite d’upload : définissez une limite réaliste par site. Attention : c’est un plafond applicatif, pas le plafond PHP (upload_max_filesize).

2) Paramètres d’upload et chemins

Multisite gère les uploads par site. Évitez de bricoler UPLOADS ou des chemins custom sans raison. La plupart des “médias cassés” que j’ai vus venaient d’un plugin de migration qui réécrit les URLs sans comprendre le contexte Multisite.

3) SMTP / délivrabilité

Si vous faites du self-hosted, configurez un SMTP transactionnel. Multisite amplifie le problème : un seul mauvais réglage et tous les sites perdent leurs emails (reset password, notifications, etc.).


Étape 6 : Domain mapping (natif) + HTTPS sans surprises

Depuis plusieurs années, WordPress gère le domain mapping nativement en Multisite. En WordPress 6.9.4, la voie recommandée reste : associer un domaine à un site via l’admin réseau, sans plugin tiers “historique”.

1) Préparer le DNS des domaines mappés

  • site-a.com → IP serveur (A) ou vers votre LB (CNAME)
  • www.site-a.com → idem

2) Associer le domaine au site

  1. Administration du réseau → Sites
  2. Modifier le site cible
  3. Renseignez le Domaine (ex. site-a.com) et le chemin si nécessaire
  4. Enregistrez

Résultat attendu : le front du site répond sur le domaine mappé, et wp-admin vous redirige correctement sur le bon host.

3) HTTPS et cookies

Le bug typique : login qui boucle ou déconnexion immédiate. Cause : cookies posés sur un domaine, requêtes sur un autre, ou schéma HTTP/HTTPS incohérent.

  • Assurez-vous que tous les domaines mappés ont un certificat valide.
  • Si vous forcez HTTPS, faites-le au niveau serveur (ou via un plugin réseau fiable), pas via une redirection PHP improvisée.

Étape 7 : Stratégie plugins/thèmes (network-activate, MU-plugins, blocage de l’éditeur)

Sur Multisite, le vrai sujet n’est pas “installer un plugin”, c’est “qui a le droit d’activer quoi, et où”.

1) Activation réseau vs activation par site

  • Network Activate : plugin chargé pour tous les sites. À réserver aux plugins d’infra (cache, sécurité, SSO, SMTP, monitoring).
  • Par site : pour des fonctionnalités optionnelles.

2) Utiliser un MU-plugin pour imposer des règles réseau

Créez un fichier : wp-content/mu-plugins/bpcab-network-guard.php. Les MU-plugins sont chargés automatiquement (sans activation), parfait pour les garde-fous.

<?php
/**
 * Plugin Name: BPCAB - Network Guard (MU)
 * Description: Garde-fous Multisite : restrictions, réglages, sécurité.
 * Author: Votre équipe
 * Version: 1.0.0
 *
 * Ce fichier doit être placé dans wp-content/mu-plugins/.
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Empêche les admins de site (non super-admin) d'accéder à certains écrans.
 * Exemple : limiter l'installation de plugins/thèmes.
 */
add_action( 'admin_init', function () {
	if ( ! is_multisite() ) {
		return;
	}

	// Super-admin : accès total.
	if ( is_super_admin() ) {
		return;
	}

	// Bloque l'accès aux pages d'installation de plugins/thèmes.
	$blocked = array(
		'plugin-install.php',
		'theme-install.php',
	);

	global $pagenow;
	if ( in_array( $pagenow, $blocked, true ) ) {
		wp_die( esc_html__( 'Accès restreint sur ce réseau.', 'default' ), 403 );
	}
}, 20 );

/**
 * Force quelques options "safe defaults" par site lors du chargement.
 * Attention : on ne fait pas update_option() à chaque requête (coût + risques).
 */
add_action( 'init', function () {
	if ( ! is_multisite() ) {
		return;
	}

	// Exemple : désactiver l'inscription publique si vous ne l'utilisez pas.
	// À gérer plutôt via "Administration du réseau → Réglages", mais utile en garde-fou.
}, 5 );

Résultat attendu : un admin de site ne peut plus installer des plugins/thèmes via l’UI, mais peut gérer le contenu.

3) Pattern “service” léger (DI sans framework)

Sur des réseaux gros volume, je structure souvent les MU-plugins en petits services. WordPress n’impose pas de container, mais vous pouvez garder un bootstrap minimal.

<?php
// wp-content/mu-plugins/bpcab-bootstrap.php
// Bootstrap MU-plugin : charge des services de façon déterministe.

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

require_once __DIR__ . '/bpcab-services/class-site-provisioner.php';

add_action( 'plugins_loaded', function () {
	if ( ! is_multisite() ) {
		return;
	}

	$provisioner = new BPCAB_Site_Provisioner();
	$provisioner->register_hooks();
}, 1 );
<?php
// wp-content/mu-plugins/bpcab-services/class-site-provisioner.php

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

final class BPCAB_Site_Provisioner {

	public function register_hooks(): void {
		// Hook historique. Toujours très utilisé.
		add_action( 'wpmu_new_blog', array( $this, 'on_new_blog' ), 10, 6 );

		// Hook plus récent pour l'initialisation de site (selon versions et contexte).
		// On garde wpmu_new_blog pour la compatibilité et parce que beaucoup d'outils s'appuient dessus.
	}

	/**
	 * Configure un nouveau site à la création.
	 *
	 * @param int    $blog_id ID du site créé.
	 * @param int    $user_id ID du user propriétaire.
	 * @param string $domain  Domaine.
	 * @param string $path    Chemin.
	 * @param int    $site_id ID du network.
	 * @param array  $meta    Meta.
	 */
	public function on_new_blog( int $blog_id, int $user_id, string $domain, string $path, int $site_id, array $meta ): void {
		// Important : basculer de blog pour écrire les options au bon endroit.
		switch_to_blog( $blog_id );

		// Exemple : définir une page d'accueil statique si elle existe.
		// Ici, on ne crée pas de contenu automatiquement (à vous de décider).
		update_option( 'blogdescription', 'Site du réseau - configuré automatiquement' );

		// Exemple : désactiver les commentaires par défaut.
		update_option( 'default_comment_status', 'closed' );
		update_option( 'default_ping_status', 'closed' );

		restore_current_blog();
	}
}

Piège : oublier restore_current_blog(). Sur un réseau, ça finit en effets de bord bizarres (options écrites sur le mauvais site, emails envoyés avec le mauvais “from”).


Étape 8 : Gestion avancée du contenu et des médias entre sites

Multisite n’est pas un “multi-tenant media library” par défaut. Chaque site a ses médias, ses options, ses menus.

1) Partager des contenus : ce qui marche vraiment

  • Réseau de thèmes : un thème parent + child themes par site, cohérent.
  • Patterns / blocs synchronisés : utile si vous standardisez une mise en page, sans partager une base de médias.
  • Contenu “global” via un site source : vous pouvez exposer via REST API et consommer côté autres sites.

2) Exemple : récupérer un menu “global” depuis le site principal

Cas réel : un header corporate identique partout, géré sur le site principal. Vous pouvez lire les items de menu depuis le blog 1.

<?php
/**
 * Exemple : injecter un menu global (site principal) dans un site enfant via un shortcode.
 * À placer dans un plugin réseau ou MU-plugin.
 */

add_shortcode( 'menu_global', function ( $atts ) {
	if ( ! is_multisite() ) {
		return '';
	}

	$atts = shortcode_atts(
		array(
			'menu_slug' => 'menu-principal',
		),
		$atts,
		'menu_global'
	);

	// On lit le menu depuis le site principal (blog_id = 1 par défaut).
	switch_to_blog( 1 );

	$menu = wp_nav_menu(
		array(
			'menu'            => $atts['menu_slug'],
			'container'       => 'nav',
			'container_class' => 'menu-global',
			'echo'            => false,
			'fallback_cb'     => '__return_empty_string',
		)
	);

	restore_current_blog();

	return $menu;
} );

Résultat attendu : sur un site enfant, ajoutez [menu_global menu_slug="menu-principal"] dans un bloc Shortcode et le menu du site principal s’affiche.


Étape 9 : Automatiser la création/config de nouveaux sites (WP-CLI + hooks)

Si vous créez plus de 5 sites, faites-le en CLI. Vous gagnerez du temps et vous éviterez les erreurs humaines (mauvais domaine, mauvais admin, mauvais template).

1) Créer un site via WP-CLI

Commande (exemple) :

# Crée un site en sous-domaine
wp site create --slug=site-client-42 --title="Client 42" [email protected]

# Liste des sites
wp site list

Résultat attendu : le site apparaît dans Administration du réseau → Sites.

2) Appliquer une configuration standard automatiquement

Votre hook wpmu_new_blog (étape 7) fait le gros du travail. Pour aller plus loin, vous pouvez :

  • activer un set de plugins sur le nouveau site ;
  • assigner un thème ;
  • créer des pages de base ;
  • définir la page d’accueil.

Exemple : activer un plugin (par site) à la création :

<?php
// À ajouter dans la méthode on_new_blog() de votre provisioner.

$plugin_to_activate = 'classic-editor/classic-editor.php'; // Exemple, adaptez.
if ( file_exists( WP_PLUGIN_DIR . '/' . $plugin_to_activate ) ) {
	// active_plugin() est disponible dans l'admin ; on charge la lib si nécessaire.
	if ( ! function_exists( 'activate_plugin' ) ) {
		require_once ABSPATH . 'wp-admin/includes/plugin.php';
	}
	activate_plugin( $plugin_to_activate, '', false, true ); // true = silencieux (pas de redirection)
}

Piège : appeler activate_plugin() sans inclure wp-admin/includes/plugin.php dans un contexte non-admin. Vous aurez un fatal “undefined function”.


Le résultat complet

Si vous préférez tout copier d’un bloc, voici une version “assemblée” minimaliste : un MU-plugin de garde-fous + provisionnement, et des snippets de config. Adaptez les valeurs à votre réseau.

1) wp-config.php (extraits)

<?php
// 1) Autorise l'écran Multisite (à garder si vous voulez pouvoir relancer l'assistant)
define( 'WP_ALLOW_MULTISITE', true );

// 2) Constantes Multisite (à copier depuis l'écran réseau)
define( 'MULTISITE', true );
define( 'SUBDOMAIN_INSTALL', true );
define( 'DOMAIN_CURRENT_SITE', 'exemple.com' );
define( 'PATH_CURRENT_SITE', '/' );
define( 'SITE_ID_CURRENT_SITE', 1 );
define( 'BLOG_ID_CURRENT_SITE', 1 );

// 3) Durcissement simple
define( 'DISALLOW_FILE_EDIT', true );

// 4) Proxy HTTPS (uniquement si nécessaire)
if ( ! empty( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https' ) {
	$_SERVER['HTTPS'] = 'on';
}

2) MU-plugin unique (garde-fous + provisionnement)

Créez wp-content/mu-plugins/bpcab-network.php :

<?php
/**
 * Plugin Name: BPCAB - Multisite Network Kit (MU)
 * Description: Garde-fous + provisionnement de sites Multisite.
 * Version: 1.0.0
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Restreint l'accès à certaines pages pour les admins de site.
 */
add_action( 'admin_init', function () {
	if ( ! is_multisite() || is_super_admin() ) {
		return;
	}

	global $pagenow;

	$blocked = array(
		'plugin-install.php',
		'theme-install.php',
	);

	if ( in_array( $pagenow, $blocked, true ) ) {
		wp_die( esc_html__( 'Accès restreint sur ce réseau.', 'default' ), 403 );
	}
}, 20 );

/**
 * Provisionne un nouveau site à la création.
 */
add_action( 'wpmu_new_blog', function ( $blog_id ) {
	if ( ! is_multisite() ) {
		return;
	}

	$blog_id = (int) $blog_id;

	switch_to_blog( $blog_id );

	// Réglages standards
	update_option( 'blogdescription', 'Site du réseau - configuré automatiquement' );
	update_option( 'default_comment_status', 'closed' );
	update_option( 'default_ping_status', 'closed' );

	// Exemple : activer un plugin si présent
	$plugin_to_activate = 'classic-editor/classic-editor.php'; // Exemple
	if ( file_exists( WP_PLUGIN_DIR . '/' . $plugin_to_activate ) ) {
		if ( ! function_exists( 'activate_plugin' ) ) {
			require_once ABSPATH . 'wp-admin/includes/plugin.php';
		}
		activate_plugin( $plugin_to_activate, '', false, true );
	}

	restore_current_blog();
}, 10, 1 );

/**
 * Shortcode : afficher un menu du site principal sur un site enfant.
 */
add_shortcode( 'menu_global', function ( $atts ) {
	if ( ! is_multisite() ) {
		return '';
	}

	$atts = shortcode_atts(
		array(
			'menu_slug' => 'menu-principal',
		),
		$atts,
		'menu_global'
	);

	switch_to_blog( 1 );

	$html = wp_nav_menu(
		array(
			'menu'            => $atts['menu_slug'],
			'container'       => 'nav',
			'container_class' => 'menu-global',
			'echo'            => false,
			'fallback_cb'     => '__return_empty_string',
		)
	);

	restore_current_blog();

	return $html;
} );

Personnalisation

  • Remplacez l’activation du plugin exemple par votre stack réelle.
  • Ajoutez une logique par “template” (par slug, par domaine, par meta WP-CLI) si vous avez plusieurs profils de sites.
  • Si vous devez créer des pages, faites-le dans switch_to_blog() puis wp_insert_post() avec un contrôle d’idempotence (ne pas dupliquer à chaque hook).

Adapter pour Divi 5 / Elementor / Avada

Les builders marchent en Multisite, mais les problèmes viennent des licences, des bibliothèques globales et des caches.

Divi 5

  • Décidez si Divi est network-activated (souvent oui sur un réseau homogène) ou activé par site.
  • Si vous partagez des layouts/modèles, évitez de “copier-coller” entre sites en base : préférez des exports/imports contrôlés, ou une bibliothèque centralisée si votre workflow le permet.
  • Test typique : édition visuelle + sauvegarde + purge cache. Si la sauvegarde échoue sur un site mais pas un autre, cherchez un WAF/ModSecurity ou une limite PHP différente.

Elementor

  • Sur Multisite, les templates sont par site. Si vous voulez un set commun, mettez en place un site “design system” et un process d’export.
  • Vérifiez l’accès REST API sur chaque domaine mappé. Les erreurs d’édition Elementor sont souvent des erreurs CORS/REST liées au host.

Avada (Fusion Builder)

  • Avada est sensible aux caches et minifications. Sur Multisite, je recommande de standardiser un seul plugin de cache/minify réseau (sinon vous déboguez 10 configurations différentes).
  • Testez l’éditeur sur un site mappé + un site non mappé : les mixed content apparaissent souvent uniquement sur les domaines secondaires.

Vérification finale

  1. Création de site : créez un nouveau site, vérifiez front + admin.
  2. Réécriture : testez une page inexistante, vérifiez que WordPress gère bien la 404 (pas une 404 Nginx brute).
  3. Uploads : uploadez une image sur 2 sites différents, vérifiez que les URLs sont correctes et ne se croisent pas.
  4. Domain mapping : mappez un domaine, vérifiez login, logout, reset password.
  5. Plugins : activez un plugin par site, vérifiez qu’il n’impacte pas les autres.
  6. Cache : activez votre cache réseau (si prévu), purge, re-test.

Si le résultat n’est pas celui attendu

Symptôme Cause probable Vérification Solution
Les sites enfants renvoient 404 Règles Nginx/Apache incorrectes, ou mauvais try_files Tester une URL de page existante + regarder les logs Nginx/Apache Remettre les règles générées par l’écran réseau, vérifier location / et la racine
Login en boucle / déconnexion immédiate HTTPS mal détecté (proxy), cookies sur mauvais domaine Inspecter les headers, vérifier Set-Cookie, vérifier schéma dans l’URL Corriger la terminaison TLS, transmettre X-Forwarded-Proto, éviter les redirections PHP “maison”
Media “cassés” après migration Réécriture d’URL incomplète, plugin de migration non compatible Multisite Comparer URL en base vs URL générée, vérifier upload_path Re-migrer avec un outil compatible, ou corriger en base par site (avec prudence)
Un plugin fonctionne sur un site mais casse un autre Conflit JS/CSS, hooks globaux mal conditionnés Console navigateur + logs PHP, désactiver plugin sur site fautif Isoler par site, corriger le plugin (conditionner par get_current_blog_id())
Les permaliens ne prennent pas Règles réécriture non régénérées ou cache agressif Aller dans Réglages → Permaliens sur un site, sauvegarder Purger cache, recharger règles serveur, vérifier droits d’écriture

Checklist de dépannage rapide

  • Désactivez temporairement le cache (plugin + cache serveur + CDN) et retestez.
  • Vérifiez la version PHP réelle (CLI vs FPM). Une PHP trop ancienne déclenche des erreurs silencieuses sur certains plugins.
  • Activez WP_DEBUG_LOG sur staging et reproduisez.
  • Confirmez que vos snippets sont dans le bon fichier : wp-config.php vs MU-plugin vs plugin classique.

Pièges et erreurs courantes

Erreur Cause Solution
Code collé dans functions.php du thème au lieu d’un MU-plugin Le thème change, le réseau casse Mettre les règles réseau dans wp-content/mu-plugins/
Oubli d’un point-virgule dans wp-config.php Fatal error, écran blanc Valider la syntaxe, restaurer via SSH/FTP, surveiller les logs PHP
Utiliser un hook trop tôt pour activate_plugin() Fonction non chargée Inclure wp-admin/includes/plugin.php ou exécuter en contexte admin
Confusion actions / filtres Retour de valeur ignoré ou action qui “return” Relire la signature du hook, tester avec un log
Permaliens non régénérés Règles serveur pas à jour Sauvegarder les permaliens + purger les caches
Snippet cassé par un plugin de snippets Ordre de chargement, erreurs fatales non isolées Préférer MU-plugin + contrôle de version
Tester sur production sans sauvegarde Rollback difficile Staging + plan de retour + dump DB

Variante / alternative

Alternative 1 : plusieurs installations WordPress + automatisation

Si vos sites sont très différents, je recommande souvent :

  • une installation par site (ou par groupe de sites),
  • un déploiement automatisé (Git + CI/CD),
  • un “golden set” de plugins géré par Composer (si votre orga le permet).

Vous perdez la centralisation native Multisite, mais vous gagnez en isolation et en maîtrise des releases.

Alternative 2 : Multisite + “réseau minimal” (plus avancé)

Vous pouvez aussi garder Multisite, mais réduire drastiquement les plugins network-activated, et pousser le reste par site. C’est un bon compromis quand vous avez 80% de commun et 20% de spécifique.


Conseils sécurité, performance et maintenance

Sécurité

  • Limitez le nombre de super-admins. Sur Multisite, ce rôle est un “root”.
  • Activez un WAF raisonnable, mais testez les builders (Divi/Elementor/Avada) : ils déclenchent souvent des faux positifs.
  • Évitez d’exposer des endpoints inutiles sur tous les sites. Un plugin vulnérable sur un site = surface d’attaque réseau.

Performance

  • OPcache activé et dimensionné : Configuration OPcache.
  • Object cache persistant (Redis/Memcached) si vous avez beaucoup de sites et de trafic. Multisite multiplie les options et transients.
  • Surveillez les requêtes cross-site via switch_to_blog() : c’est pratique, mais ça peut exploser le temps de réponse si vous le faites sur chaque requête front.

Maintenance

  • Mises à jour : testez sur staging, puis déployez en fenêtre courte. Un plugin réseau cassé casse tout.
  • Journalisation : centralisez les logs PHP/NGINX/Apache et les erreurs WordPress.
  • Backups : base + fichiers, et gardez des backups “froids” hors serveur.

Pour aller plus loin

  • Créer des “profils” de sites : un meta WP-CLI (ex. --meta_input) puis provisionnement conditionnel.
  • Mettre en place un catalogue de plugins autorisés par site (UI custom en admin réseau + enforcement MU-plugin).
  • Exposer un “site registry” interne (table custom) pour tracer domaine, propriétaire, plan, quotas.
  • Superviser les tâches cron par site (et éviter le WP-Cron web si vous avez du volume).

Ressources


FAQ

Peut-on activer Multisite sur un site existant en production ?

Oui, mais faites-le sur un clone d’abord. Le risque n’est pas l’activation en elle-même, c’est la réécriture serveur, le cache et les plugins qui supposent un single-site.

Sous-domaines ou sous-répertoires : lequel est le plus “pro” ?

Les sous-domaines sont plus flexibles (domain mapping, séparation), mais demandent DNS + certificats. Les sous-répertoires sont plus simples, mais peuvent être limitants si vous changez d’architecture plus tard.

Est-ce que je peux “désactiver” Multisite après coup ?

Techniquement oui (en retirant les constantes), mais vous laissez des tables/options et des contenus multi-sites. En pratique, c’est une migration, pas un toggle. Prévoyez un plan de rollback (snapshot) plutôt qu’un “undo”.

Pourquoi j’ai des redirections de login infinies sur un domaine mappé ?

Dans mon expérience, c’est presque toujours un problème de HTTPS détecté différemment entre proxy/CDN et WordPress, ou un cookie posé sur un host différent. Vérifiez headers, schéma, et évitez les redirections PHP artisanales.

Un admin de site peut-il installer des plugins ?

Par défaut, non : l’installation de plugins est au niveau réseau. Un super-admin peut installer, puis autoriser l’activation par site. Vous pouvez renforcer ça via MU-plugin.

Comment partager un thème sur tous les sites ?

Installez le thème une fois, puis activez-le par site (ou définissez un thème par défaut). Pour standardiser, utilisez un thème parent + child themes par site.

Les médias sont-ils partagés entre sites ?

Non, chaque site a sa bibliothèque. Partager les médias demande une stratégie (site “assets”, REST, ou plugin spécialisé), et ça a des implications de perf et de droits.

WP-CLI est-il indispensable ?

Non, mais dès que vous industrialisez (création en masse, scripts, provisioning), c’est l’outil le plus fiable et le plus reproductible.

Quel est le meilleur endroit pour mettre du code réseau ?

MU-plugins pour les règles d’infra (chargement automatique, pas dépendant du thème). Plugins classiques pour des features optionnelles, activables par site.

Est-ce compatible avec Divi 5 / Elementor / Avada ?

Oui, mais testez systématiquement sur un domaine mappé et avec cache. Les problèmes sont rarement “Multisite”, ils sont presque toujours “REST/HTTPS/cookies/cache”.

Comment diagnostiquer rapidement une 404 Multisite ?

Regardez si la 404 vient du serveur (Nginx/Apache) ou de WordPress. Si c’est serveur, corrigez la réécriture. Si c’est WordPress, vérifiez site/domain/path dans l’admin réseau et régénérez les permaliens.