Une boucle de redirection n’est jamais l’œuvre d’un seul acteur. Une réponse renvoie vers une adresse, et cette adresse renvoie vers la première. Le navigateur compte les sauts, atteint sa limite et abandonne. Les auteurs possibles sont peu nombreux : WordPress, une extension, une règle du serveur, un proxy TLS, un cache. Le diagnostic consiste à lire chaque en-tête Location et à reconnaître qui l’a écrit.

La réponse en trois lignes

Lancez curl -sI -L --max-redirs 5 https://votre-site.fr/ et lisez les lignes Location. Si elles alternent entre deux formes de la même adresse (avec et sans https, avec et sans www), l’adresse enregistrée dans WordPress ne correspond pas à celle que le serveur sert : cause 1, ou cause 2 derrière un proxy. Si le site public s’affiche et que seul /wp-admin/ tourne en rond avec wp-login.php, ce sont les cookies : cause 5.

Ce que le navigateur affiche, mot pour mot

Les libellés ci-dessous viennent des fichiers de traduction des navigateurs. Chrome : « Cette page ne fonctionne pas », « votre-site.fr vous a redirigé à de trop nombreuses reprises. », code ERR_TOO_MANY_REDIRECTS (chaîne IDS_ERRORPAGES_SUMMARY_TOO_MANY_REDIRECTS de Chromium). Firefox : « La page n’est pas redirigée correctement », suivi de « La cause de ce problème peut être la désactivation ou le refus des cookies. » (redirectLoop-title). Safari : « Safari ne peut ouvrir la page car il y a eu trop de redirections ». La phrase de Firefox ne vise que la cause 5 ; ailleurs, vider les cookies ne change rien.

Lire la boucle avant de toucher au site

Le navigateur cache la chaîne des réponses. curl la montre, sans cookie ni cache d’un essai à l’autre. -L suit les redirections, --max-redirs 5 arrête après cinq sauts :

curl -sI -L --max-redirs 5 https://votre-site.fr/

Chaque réponse porte un code et un Location. Deux détails de WordPress rendent la lecture précise :

  • La signature. Toute redirection émise par WordPress passe par wp_redirect(), dans wp-includes/pluggable.php, qui ajoute l’en-tête X-Redirect-By: WordPress. Un Location sans cet en-tête vient du serveur web, de l’hébergeur, du CDN ou du cache.
  • Le code. La redirection canonique répond 301. Celles de la connexion répondent 302, la valeur par défaut de wp_redirect().

Sans terminal, le testeur d’en-têtes lit la première réponse et son Location.

Le Location dit ceci, la cause est là

Ce que montrent les LocationCause probable
http:// puis https:// de la même adresse, en alternanceAdresse du site en http (1), ou proxy TLS (2)
La même adresse https:// répétée, à l’identiqueProxy ou CDN qui parle HTTP au serveur (2), règle %{HTTPS} (3)
Avec www, sans, avec, sansOption home contre règle serveur ou extension (1, 3, 4)
/wp-admin/ vers wp-login.php?redirect_to=…, et retour, site public intactCookie de connexion non posé ou non relu (5)
Aucun X-Redirect-By, en-têtes Age, X-Cache ou CF-Cache-StatusRedirection périmée servie par un cache (6)
Ancien domaine, nouveau domaine, ancien domaineChangement de domaine sans mise à jour de la base (7)

Ce que WordPress redirige de lui-même

Trois fonctions du cœur redirigent sans aucune extension.

La redirection canonique. redirect_canonical(), dans wp-includes/canonical.php, accrochée à template_redirect par wp-includes/default-filters.php, reconstruit l’adresse attendue puis compare hôte, chemin, port et paramètres avec la demande. L’hôte vient de home_url(), donc de l’option home, mais n’est imposé que pour la différence entre www et sans www: le commentaire dit « Only redirect no-www <=> yes-www ». Un domaine entièrement différent est laissé tel quel. Le slash final suit le réglage des permaliens, par user_trailingslashit(). Le protocole est celui de la requête, jamais celui de l’option : cette fonction ne transforme pas un http en https. Elle répond 301, seulement en GET et HEAD, jamais dans l’administration.

Les raccourcis d’administration. wp_redirect_admin_locations(), même fichier, envoie /admin, /dashboard et /login vers admin_url() et wp_login_url(), deux adresses construites à partir de l’option siteurl.

La connexion. Chaque écran d’administration commence par auth_redirect(), appelée dans wp-admin/admin.php et définie dans wp-includes/pluggable.php. Si le HTTPS est exigé (is_ssl() ou force_ssl_admin()) et que la requête n’est pas vue en HTTPS, elle redirige vers https://. Sinon elle cherche le cookie de connexion et, s’il manque, redirige vers wp-login.php?redirect_to=…. wp-login.php applique la même règle dès sa quinzième ligne : force_ssl_admin() && ! is_ssl() renvoie vers https://.

Tout repose donc sur is_ssl(), dans wp-includes/load.php. Elle ne lit que $_SERVER['HTTPS'] et le port 443. L’en-tête X-Forwarded-Proto d’un proxy n’apparaît nulle part dans wp-includes ni wp-admin. C’est le point commun des causes 2, 3 et 5.

Les causes, par ordre de fréquence

1. L’adresse du site ne correspond pas à ce que le serveur sert

Deux options en base : siteurl, qui construit les adresses de l’administration et de la connexion, et home, celles du site public. Si home porte www et qu’une règle du serveur retire www, la canonique renvoie vers www et le serveur renvoie sans. Si siteurl est en http alors que le serveur impose le HTTPS, c’est l’administration qui boucle.

Vérification. Lisez les deux options sans l’administration, dans phpMyAdmin ou avec WP-CLI (wp option get home) :

SELECT option_name, option_value FROM wp_options
WHERE option_name IN ('siteurl', 'home');

Réparation. Alignez les deux options sur l’adresse servie, protocole et www compris. Sans accès à l’administration, deux constantes de wp-config.php ont priorité sur la base : les filtres _config_wp_home() et _config_wp_siteurl(), dans wp-includes/functions.php, remplacent la valeur lue dès que WP_HOME ou WP_SITEURL est défini.

define( 'WP_HOME', 'https://www.votre-site.fr' );
define( 'WP_SITEURL', 'https://www.votre-site.fr' );

2. Un proxy TLS ou un CDN parle HTTP à votre serveur

Cloudflare en mode « Flexible », un proxy de l’hébergeur : le visiteur est en HTTPS, mais la connexion qui arrive à PHP est en HTTP. is_ssl() répond faux. Tout ce qui force le HTTPS côté WordPress, FORCE_SSL_ADMIN, une extension, une règle .htaccess, renvoie alors vers une adresse https:// que le proxy retransmet en HTTP. Signature : le même Location en https://, répété à l’identique.

Vérification. Un fichier PHP qui affiche $_SERVER['HTTPS'] et $_SERVER['HTTP_X_FORWARDED_PROTO'] tranche : le premier vide, le second à https, c’est ce cas. Réparation. Chez le proxy d’abord : Cloudflare en « Full (strict) », ou un TLS qui va jusqu’au serveur. Sinon, en tête de wp-config.php :

if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && 'https' === $_SERVER['HTTP_X_FORWARDED_PROTO'] ) {
	$_SERVER['HTTPS'] = 'on';
}

3. Une règle du serveur contredit WordPress

Le bloc # BEGIN WordPress du .htaccess, écrit par insert_with_markers() dans wp-admin/includes/misc.php à partir de WP_Rewrite::mod_rewrite_rules(), ne contient aucune redirection : il ne fait que passer les adresses inconnues à index.php. Toute ligne Redirect ou RewriteRule … [R=301] a donc été ajoutée à la main, par une extension ou par l’hébergeur. Le piège classique : une redirection HTTPS qui teste RewriteCond %{HTTPS} off derrière un proxy. Pour Apache, la connexion est toujours en clair, la condition toujours vraie, et la règle renvoie sans fin vers https://. Même aveuglement que is_ssl().

Vérification. Un Location sans X-Redirect-By. Lisez le .htaccess hors du bloc de WordPress, et les redirections du panneau de l’hébergeur. Réparation. Retirez la règle, ou faites-la tester l’en-tête du proxy : RewriteCond %{HTTP:X-Forwarded-Proto} !https. Le guide sur l’erreur 500 montre comment neutraliser le fichier sans le perdre.

4. Une extension de redirection ou de sécurité

Forçage du HTTPS, forçage du www, redirection par pays, règle de redirection qui pointe vers elle-même : l’extension passe par wp_redirect() et sa réponse est signée « WordPress ». Elle se distingue de la canonique par son code, souvent 302, et par des options home et siteurl correctes.

Vérification et réparation. Sans accès à l’administration, renommez le dossier de l’extension dans wp-content/plugins/. wp_get_active_and_valid_plugins(), dans wp-includes/load.php, ne charge que les fichiers qui existent : un dossier renommé est une extension désactivée.

5. Le cookie de connexion n’est pas posé, ou pas relu

Le site public fonctionne, seul le couple /wp-admin/ et wp-login.php tourne. Après un identifiant accepté, wp_set_auth_cookie() pose le cookie sur ADMIN_COOKIE_PATH et PLUGINS_COOKIE_PATH, pour le domaine COOKIE_DOMAIN, avec le drapeau secure égal à is_ssl(). Dans wp-includes/default-constants.php, ADMIN_COOKIE_PATH dérive du chemin de siteurl et COOKIE_DOMAIN vaut une chaîne vide. Puis auth_redirect() relit le cookie via wp_parse_auth_cookie() : en HTTPS elle cherche wordpress_sec_…, sinon wordpress_…. Trois façons de rompre la chaîne :

  • COOKIE_DOMAIN défini sur un autre domaine que celui de la barre d’adresse : le navigateur refuse le cookie.
  • siteurl avec un sous-dossier qui n’est pas celui de l’installation : le chemin du cookie est faux, il n’est jamais renvoyé sur /wp-admin/.
  • Cookie posé en secure à la connexion, puis administration vue en HTTP derrière un proxy : WordPress cherche l’autre nom de cookie. C’est la cause 2 sous un autre visage.

Vérification. curl n’a pas de cookies : c’est dans les outils du navigateur, onglet Stockage ou Application, que se lisent le nom, le domaine et le chemin du cookie. Réparation. Retirez COOKIE_DOMAIN de wp-config.php, alignez siteurl, appliquez le correctif de la cause 2.

6. Un cache sert une redirection périmée

Une redirection émise pendant la panne reste dans le cache de page, le CDN ou le navigateur, qui mémorise un 301. Le site est réparé, la boucle continue pour ceux qui l’ont vue. Vérification. curl ne boucle plus alors que le navigateur boucle encore, ou la redirection porte Age, X-Cache ou CF-Cache-Status: HIT. Réparation. Videz le cache de l’extension, purgez le CDN, testez dans une fenêtre privée.

7. Le domaine a changé, pas la base

Le serveur redirige l’ancien domaine vers le nouveau. Mais siteurl porte encore l’ancien : wp_login_url() et admin_url() renvoient l’administration vers l’ancien domaine, que le serveur renvoie vers le nouveau. Le site public tient, parce que la canonique ne touche pas à un hôte différent : le premier symptôme est une connexion impossible.

Vérification. Les Location alternent entre deux domaines. Réparation. Mettez home et siteurl sur le nouveau domaine, par la requête de la cause 1 ou par WP_HOME et WP_SITEURL. Les liens du contenu gardent l’ancien domaine : autre chantier, qui ne boucle pas.

Vérifier que c’est terminé

curl -sI -L --max-redirs 5 https://votre-site.fr/
curl -sI -L --max-redirs 5 https://votre-site.fr/wp-admin/

Attendu pour la première : un 200, précédé au plus d’une redirection vers la forme canonique. Pour la seconde : un seul 302 signé X-Redirect-By: WordPress vers wp-login.php, puis un 200. Terminez par une connexion dans une fenêtre privée.

Si la réparation doit durer

Une boucle ferme le site à tout le monde, moteurs compris, sans rien leur dire. Tant que WordPress s’exécute, mieux vaut passer volontairement en maintenance avec un statut 503 le temps des essais, puis rouvrir une fois les deux commandes ci-dessus revenues propres.