WordPress « Réponse JSON invalide » : causes et solutions qui fonctionnent vraiment

Cet article vous a aidé ?

L’éditeur WordPress affiche « Réponse JSON invalide » et soudain votre « simple mise à jour de contenu » devient un incident en production.
Les articles ne se publient plus. Les réglages ne se sauvegardent pas. L’éditeur de blocs boude. Et la console de votre navigateur hurle discrètement à propos d’appels REST qui échouent.

Cette erreur n’est pas un mystère. C’est un symptôme : WordPress s’attendait à du JSON de l’API REST, mais a reçu autre chose — une page de connexion HTML,
un 403 provenant d’un WAF, une boucle de redirection, une défaillance TLS, un 404 mis en cache, ou un plugin qui « réécrit » les en-têtes de façon “utile”.
Nous allons l’aborder comme un problème SRE : observer, restreindre, prouver, réparer, prévenir.

Ce que signifie réellement « Réponse JSON invalide »

WordPress (en particulier l’éditeur de blocs / Gutenberg) communique avec votre propre site via l’API REST. Il envoie des requêtes HTTP vers des endpoints comme
/wp-json/wp/v2/posts. Il attend que le corps de la réponse soit du JSON valide et que le code de statut HTTP indique un succès
(généralement 200/201).

Lorsqu’il n’obtient pas cela — parce que la réponse est du HTML, vide, tronquée, redirigée, bloquée ou servie depuis le mauvais hôte — il affiche
le message générique « Réponse JSON invalide ». Ce message revient à dire : « J’ai demandé du JSON, et la réalité a répondu autre chose. »

Votre tâche est de déterminer ce que la réalité a renvoyé à la place. C’est toujours visible en un seul endroit : la réponse réseau pour l’appel REST
(code de statut, en-têtes, corps). Si vous devinez, vous perdez du temps.

Une citation utile à garder quand vous déboguez : idée paraphrasée — Charity Majors : « Vous ne pouvez pas améliorer ce que vous ne mesurez pas. »
L’erreur de l’éditeur n’est pas une mesure. L’échange HTTP l’est.

Playbook de diagnostic rapide (premières/deuxièmes/troisièmes vérifications)

Première étape : confirmer la requête qui échoue et ce qui est revenu

  1. Ouvrez les DevTools du navigateur → Réseau.
  2. Déclenchez l’action de sauvegarde/publication qui échoue.
  3. Trouvez la requête vers /wp-json/ (souvent /wp-json/wp/v2/posts/<id> ou /wp-json/wp/v2/settings).
  4. Lisez : code de statut, corps de la réponse, et toutes les redirections.

Décision : si le corps de la réponse est du HTML (page de connexion, page d’erreur, page de blocage WAF), vous n’avez pas affaire à un « problème de parsing JSON ».
Vous avez affaire à l’authentification, au routage, au filtrage de sécurité, au cache ou à une réécriture en amont.

Deuxième étape : interroger l’API REST directement depuis votre poste

Utilisez curl contre un endpoint simple comme /wp-json/ et un endpoint réel comme /wp-json/wp/v2/types/post.
Faites-le avec et sans authentification (si nécessaire). Cela sépare le « côté navigateur/CORS bizarre » du « serveur cassé ».

Troisième étape : contourner les couches

Les sites WordPress n’ont rarement « juste WordPress ». Ils ont un CDN, un reverse proxy, un WAF, du caching et une ménagerie de plugins.
Contournez dans cet ordre :

  1. Contournez le CDN (toucher l’origine directement via le fichier hosts ou un nom d’hôte d’origine).
  2. Contournez le cache (envoyez Cache-Control: no-cache ; désactivez temporairement le cache de page).
  3. Désactivez les plugins (commencez par sécurité, cache et plugins d’en-têtes).
  4. Basculer vers un thème par défaut (oui, les thèmes peuvent casser le REST).

Décision : dès que la réponse REST redevient un JSON correct, vous avez identifié la couche à investiguer. Ne tout réactivez pas d’un coup.
Faites un changement à la fois. Vous déboguez, vous ne dansez pas.

Faits intéressants et contexte historique (pourquoi cela revient sans cesse)

  • L’API REST n’a pas toujours été dans le cœur. Les capacités de l’API REST de WordPress ont évolué via des plugins avant d’entrer dans le core, donc les anciens écosystèmes ont des « avis » sur le sujet.
  • Gutenberg a monté les enjeux. L’éditeur de blocs dépend fortement du REST ; les workflows de l’éditeur classique sollicitaient moins d’endpoints et masquaient bien des problèmes serveur.
  • « Réponse JSON invalide » signifie souvent « du HTML est apparu ». Un formulaire de connexion, une page d’erreur 403, ou un document « Accès refusé » du WAF est du HTML valide et du JSON invalide — WordPress le rapporte de la même façon.
  • Les réglages de permaliens sont opérationnels. Les règles de réécriture ne sont pas « juste SEO ». Un réglage de réécriture cassé peut transformer des routes API en 404, et l’éditeur perd la tête.
  • CORS est devenu plus visible avec les navigateurs modernes. Le durcissement des politiques des navigateurs fait échouer bruyamment des en-têtes cross-origin mal configurés, surtout pour des configurations headless.
  • Les plugins de sécurité adorent bloquer le REST. Beaucoup ont été conçus quand le REST était « optionnel » ; certains considèrent encore /wp-json/ comme du trafic suspect.
  • Les CDN mettent en cache plus que vous ne pensez. Un caching mal configuré peut stocker un 301/302/403/404 pour des routes API et le servir à tout le monde, y compris aux administrateurs.
  • HTTP/2 et les proxies ont changé la forme des échecs. Certaines combinaisons edge/proxy produisent des comportements d’en-têtes et de redirection qui déconcertent les clients s’attendant à des endpoints stables.
  • Le contenu mixte n’est pas mort. Les sites partiellement migrés vers HTTPS peuvent encore déclencher des requêtes REST sur HTTP dans des coins étranges (site URL vs home URL vs en-têtes du reverse proxy).

Les grands modes de défaillance : SSL, CORS, plugins, proxies, cache

1) SSL/TLS et « mauvais schéma » (HTTP vs HTTPS)

Classique : votre page d’administration se charge en HTTPS, mais WordPress génère des URL REST en HTTP (ou inversement).
Les navigateurs peuvent bloquer le contenu mixte, ou la requête suit des redirections et retourne du HTML.

Causes racines communes :

  • Désalignement Site URL/Home URL dans les réglages WordPress ou la base de données.
  • Reverse proxy ne transmet pas correctement X-Forwarded-Proto ; WordPress pense être en HTTP.
  • HSTS et forçage HTTPS provoquant des redirections supplémentaires ou des boucles de redirection en cache.
  • Incompatibilité de certificat pour le nom d’hôte utilisé par les appels REST (www vs apex).

2) Problèmes CORS (particulièrement en headless ou origines admin atypiques)

Si votre UI d’administration est hébergée sur une origine (domaine/port) et que l’API WordPress est sur une autre, le navigateur applique CORS.
Quand CORS échoue, vous voyez souvent l’UI WordPress rapporter « Réponse JSON invalide » car l’appel API ne retourne jamais un JSON exploitable par le JS.

Déclencheurs typiques de CORS :

  • Utiliser un domaine différent pour l’admin que pour l’API (ex. hôte admin personnalisé, hôtes de staging, ports non standards).
  • Absence de Access-Control-Allow-Origin ou valeur incorrecte.
  • OPTIONS de prévol bloqué par le serveur/WAF.
  • Mode credentials (cookies) nécessitant Access-Control-Allow-Credentials: true et une origine non wildcard.

3) Plugins et thèmes : le sabotage « utile »

Une quantité déprimante d’échecs REST est auto-infligée :

  • Plugins de sécurité bloquant des endpoints REST pour des nonces ou des limites de taux.
  • Plugins de cache mettant en cache des réponses API ou réécrivant les en-têtes.
  • Plugins d’optimisation/minification cassant wp-api-fetch ou l’injection de nonce.
  • Thèmes qui ajoutent de la sortie avant les en-têtes (warnings/notices PHP) corrompant la sortie JSON.

Blague #1 : La façon la plus rapide de reproduire une « Réponse JSON invalide » est d’installer trois plugins « indispensables » d’un article de blog écrit en 2016.

4) Reverse proxies, CDNs et WAFs : les middleboxes

Les reverse proxies et CDNs sont formidables jusqu’au moment où ils décident que votre requête REST a besoin d’une « amélioration » :

  • Redirections 301/302 appliquées aux chemins /wp-json/.
  • Règles WAF (ModSecurity ou WAF managé) bloquant les POST/PUT avec des corps JSON.
  • Limites de taille d’en-tête, limites de corps de requête, ou timeouts coupant les réponses.
  • Clés de cache ignorant les cookies ; servant des réponses en cache anonymes aux appels admin.

5) Permaliens et réécritures : ennuyants mais mortels

Quand les règles de réécriture sont incorrectes, les routes REST peuvent devenir 404 ou être routées vers le mauvais fichier. WordPress renvoie alors du HTML
(un template 404, ou une redirection), et l’éditeur appelle ça « Réponse JSON invalide ».

Les problèmes de réécriture sont fréquents après :

  • Migration d’Apache vers Nginx sans règles équivalentes.
  • Changement de document root ou installation dans un sous-répertoire.
  • Activation du multisite, ou changement de mapping de domaine.

6) Authentification/nonces et « vous avez été déconnecté »

Les endpoints REST de WordPress exigent souvent un nonce valide pour les actions admin. Si les cookies ne sont pas correctement réglés (domaine, drapeau secure),
ou si un proxy supprime des en-têtes, les appels REST peuvent retourner 401/403. Parfois le corps est du HTML (redirection vers la page de connexion).

Tâches pratiques : commandes, sorties, décisions (12+)

Le but de ces tâches n’est pas de taper des commandes pour le plaisir. Chacune vous informe spécifiquement et force une décision.
Exécutez-les depuis un shell ayant accès au serveur quand c’est possible. Sinon, exécutez les variantes côté client depuis votre poste.

Tâche 1 : Confirmer que l’endpoint racine REST retourne du JSON

cr0x@server:~$ curl -sS -D- https://example.com/wp-json/ -o /tmp/wpjson.body | head -n 20
HTTP/2 200
content-type: application/json; charset=UTF-8
x-robots-tag: noindex
vary: Origin
date: Fri, 27 Dec 2025 10:12:05 GMT
cr0x@server:~$ head -c 180 /tmp/wpjson.body
{"name":"Example Site","description":"Just another WordPress site","url":"https:\/\/example.com","home":"https:\/\/example.com","gmt_offset":0,

Ce que ça signifie : 200 + application/json + corps JSON est sain à l’endpoint racine.
Décision : Si cela échoue (non-200 ou HTML), concentrez-vous sur le routage/WAF/SSL avant de toucher aux paramètres internes de WordPress.

Tâche 2 : Vérifier un endpoint REST réel utilisé par Gutenberg

cr0x@server:~$ curl -sS -D- https://example.com/wp-json/wp/v2/types/post -o /tmp/types.body | head -n 20
HTTP/2 200
content-type: application/json; charset=UTF-8
cache-control: no-cache, must-revalidate, max-age=0
date: Fri, 27 Dec 2025 10:12:10 GMT
cr0x@server:~$ jq -r '.slug,.rest_base' /tmp/types.body
post
posts

Ce que ça signifie : Les endpoints core sont accessibles et retournent du JSON analysable.
Décision : Si vous recevez 401/403 ici, soupçonnez l’auth/nonces, le WAF ou un plugin de sécurité. Si 404, soupçonnez réécritures/permalinks/routage proxy.

Tâche 3 : Détecter les boucles de redirection ou la confusion de schéma

cr0x@server:~$ curl -sS -I -L https://example.com/wp-json/ | egrep -i 'HTTP/|location:'
HTTP/2 301
location: http://example.com/wp-json/
HTTP/1.1 301 Moved Permanently
location: https://example.com/wp-json/

Ce que ça signifie : Vous avez une redirection ping-pong entre HTTP et HTTPS.
Décision : Corrigez les en-têtes proxy et les réglages d’URL WordPress avant toute autre chose. Les boucles de redirection ne sont pas « mineures ».

Tâche 4 : Vérifier que le certificat TLS correspond à l’hôte utilisé par les appels REST

cr0x@server:~$ echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -subject -issuer -dates
subject=CN = example.com
issuer=CN = R3, O = Let's Encrypt, C = US
notBefore=Dec  1 00:00:00 2025 GMT
notAfter=Feb 29 23:59:59 2026 GMT

Ce que ça signifie : Le certificat est valide pour le nom d’hôte.
Décision : Si CN/SAN ne correspond pas (ex. seulement www), alignez l’hôte canonique ou installez un certificat couvrant les deux.

Tâche 5 : Vérifier les valeurs WordPress « home » et « siteurl » (CLI)

cr0x@server:~$ cd /var/www/html
cr0x@server:~$ wp option get home
https://example.com
cr0x@server:~$ wp option get siteurl
http://example.com

Ce que ça signifie : Incohérence. Les URL REST peuvent être construites à partir de siteurl dans certains contextes.
Décision : Rendez-les cohérentes (généralement les deux en HTTPS) et assurez-vous que le reverse proxy rapporte correctement HTTPS.

Tâche 6 : Corriger les URL WordPress en toute sécurité (CLI)

cr0x@server:~$ wp option update home 'https://example.com'
Success: Updated 'home' option.
cr0x@server:~$ wp option update siteurl 'https://example.com'
Success: Updated 'siteurl' option.

Ce que ça signifie : Les URL canoniques correspondent maintenant.
Décision : Re-testez /wp-json/ et une sauvegarde Gutenberg. Si les redirections persistent, la couche proxy/CDN réécrit encore.

Tâche 7 : Vérifier que les règles de réécriture sont présentes (flush WordPress)

cr0x@server:~$ wp rewrite list --fields=match,query | head
^wp-json/?$	index.php?rest_route=/
^wp-json/(.*)?	index.php?rest_route=/$matches[1]
^index\.php/wp-json/?$	index.php?rest_route=/

Ce que ça signifie : WordPress connaît les réécritures REST.
Décision : Si elles manquent, videz les permaliens. Si présentes mais les requêtes 404 quand même, les règles du serveur web sont incorrectes.

Tâche 8 : Confirmer qu’Nginx route /wp-json correctement

cr0x@server:~$ sudo nginx -T 2>/dev/null | sed -n '1,120p'
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
user www-data;
worker_processes auto;
http {
    server {
        listen 443 ssl http2;
        server_name example.com;
        root /var/www/html;

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

Ce que ça signifie : Le fallback standard try_files est présent.
Décision : Si vous voyez un bloc location en conflit qui intercepte /wp-json (ou renvoie un 404 statique), corrigez-le.

Tâche 9 : Vérifier les règles de réécriture Apache .htaccess (si Apache)

cr0x@server:~$ sudo sed -n '1,120p' /var/www/html/.htaccess
# BEGIN WordPress
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# END WordPress

Ce que ça signifie : Les réécritures de base WordPress sont intactes.
Décision : Si RewriteEngine est désactivé ou que le fichier est ignoré (AllowOverride), les routes REST peuvent échouer en 404. Corrigez la config du vhost en conséquence.

Tâche 10 : Repérer les blocages WAF/ModSecurity dans les logs

cr0x@server:~$ sudo egrep -R "ModSecurity|Access denied|403" /var/log/apache2/ | tail -n 8
/var/log/apache2/error.log:[Wed Dec 25 09:41:12.123456 2025] [security2:error] [pid 1822] [client 203.0.113.10] ModSecurity: Access denied with code 403 (phase 2). Match of "rx (?i:select.+from)" against "ARGS:content" required. [id "942100"]

Ce que ça signifie : Une règle bloque du contenu dans une requête REST.
Décision : Excluez les endpoints REST de ce jeu de règles ou ajustez les règles pour les chemins admin authentifiés. Ne « désactivez pas la sécurité » globalement.

Tâche 11 : Identifier si la réponse est du HTML (page de connexion) au lieu du JSON

cr0x@server:~$ curl -sS -D- https://example.com/wp-json/wp/v2/posts -o /tmp/posts.body | head -n 15
HTTP/2 401
content-type: text/html; charset=UTF-8
date: Fri, 27 Dec 2025 10:12:55 GMT
cr0x@server:~$ head -n 5 /tmp/posts.body




Ce que ça signifie : WordPress attendait du JSON mais a reçu du HTML, probablement une réponse de login/auth ou une page générée par un proxy.
Décision : Corrigez les en-têtes/cookies/nonces d’authentification ou la règle de proxy qui réécrit les 401/403 en page HTML.

Tâche 12 : Valider que l’OPTIONS de preflight n’est pas bloqué (CORS)

cr0x@server:~$ curl -sS -D- -X OPTIONS https://example.com/wp-json/wp/v2/posts \
  -H 'Origin: https://admin.example.com' \
  -H 'Access-Control-Request-Method: POST' \
  -H 'Access-Control-Request-Headers: content-type,x-wp-nonce' \
  -o /dev/null | head -n 25
HTTP/2 403
content-type: text/html; charset=UTF-8
date: Fri, 27 Dec 2025 10:13:20 GMT

Ce que ça signifie : Le prévol est bloqué. Le navigateur refusera la requête réelle.
Décision : Ajustez le serveur/WAF pour autoriser OPTIONS et retourner les en-têtes CORS corrects pour les routes REST.

Tâche 13 : Vérifier si un CDN met en cache les réponses API

cr0x@server:~$ curl -sS -D- https://example.com/wp-json/ -o /dev/null | egrep -i 'cache|age|cf-|x-cache'
cache-control: max-age=14400
age: 8732
x-cache: HIT

Ce que ça signifie : Quelque chose met en cache la racine REST pendant des heures.
Décision : Excluez /wp-json/* du cache CDN/page ou définissez Cache-Control: no-store pour les endpoints REST authentifiés.

Tâche 14 : Reproduire comme le runtime PHP le voit (curl local vers l’origine)

cr0x@server:~$ curl -sS -D- http://127.0.0.1/wp-json/ -H 'Host: example.com' -o /tmp/origin.body | head -n 20
HTTP/1.1 200 OK
Content-Type: application/json; charset=UTF-8

Ce que ça signifie : L’origine est saine ; quelque chose devant la protège la casse.
Décision : Corrigez les règles proxy/CDN/WAF au lieu de toucher aux paramètres WordPress.

Tâche 15 : Trouver des warnings PHP qui corrompent la sortie JSON

cr0x@server:~$ sudo tail -n 30 /var/log/php8.2-fpm.log
[27-Dec-2025 10:11:41] WARNING: [pool www] child 2199 said into stderr: "PHP Warning:  Undefined array key "foo" in /var/www/html/wp-content/themes/custom/functions.php on line 412"
[27-Dec-2025 10:11:41] WARNING: [pool www] child 2199 said into stderr: "PHP Warning:  Cannot modify header information - headers already sent by (output started at /var/www/html/wp-content/themes/custom/functions.php:412)"

Ce que ça signifie : Une sortie est survenue avant les en-têtes ; la réponse REST peut être corrompue (JSON précédé de warnings).
Décision : Corrigez le thème/plugin qui émet cette sortie. En production, ne comptez pas sur le « masquer les warnings » ; éliminez-les.

Tâche 16 : Isolation rapide des plugins sans désinstallation (CLI)

cr0x@server:~$ wp plugin list --status=active
+----------------------+----------+-----------+---------+
| name                 | status   | update    | version |
+----------------------+----------+-----------+---------+
| wordfence            | active   | none      | 7.11.0  |
| wp-rocket            | active   | none      | 3.16.0  |
| redis-cache          | active   | none      | 2.5.3   |
| custom-mu-plugin     | active   | none      | 1.0.0   |
+----------------------+----------+-----------+---------+
cr0x@server:~$ wp plugin deactivate wordfence wp-rocket
Plugin 'wordfence' deactivated.
Plugin 'wp-rocket' deactivated.

Ce que ça signifie : Vous pouvez tester le comportement REST avec moins d’éléments en mouvement.
Décision : Si le problème disparaît, réactivez un par un. Si cela ne change rien, ne blâmez pas les plugins par habitude — passez au proxy/SSL/routage.

Blague #2 : « Réponse JSON invalide » est la façon dont WordPress vous dit que votre infrastructure a des opinions — et qu’elle est de mauvaise humeur.

Erreurs fréquentes : symptôme → cause racine → correction

1) Symptomatique : l’éditeur ne publie pas ; le réseau montre 301/302 puis du HTML

Cause racine : Canonicalisation de schéma/hôte redirigeant les endpoints REST (HTTP↔HTTPS, www↔apex), parfois en boucle.

Correction : Alignez home et siteurl sur l’hôte canonique HTTPS ; corrigez les en-têtes proxy (X-Forwarded-Proto) et arrêtez de traiter /wp-json différemment du trafic de page normal.

2) Symptomatique : la requête REST retourne 403 avec une page HTML « bloquée »

Cause racine : Règle WAF/ModSecurity déclenchée par le payload JSON, le contenu du post, ou les patterns de route REST.

Correction : Ajustez le WAF : autorisez les routes REST authentifiées, permettez OPTIONS, et scopez les exceptions étroitement à /wp-json/ et aux utilisateurs admin. Vérifiez dans les logs.

3) Symptomatique : la requête REST retourne 401 ; le corps ressemble à une page de connexion

Cause racine : Authentification/nonces échouant à cause du domaine/des flags secure des cookies, du cache mélangeant anonyme/admin, ou d’un proxy qui supprime des en-têtes.

Correction : Assurez-vous que les cookies admin sont sécurisés en HTTPS, excluez le REST du cache de page, et confirmez le forwarding de l’en-tête Authorization (surtout avec Apache/Nginx + PHP-FPM).

4) Symptomatique : l’endpoint REST retourne 404, mais les pages du site fonctionnent

Cause racine : Les règles de réécriture WordPress ne sont pas appliquées (mauvaise config Nginx, .htaccess ignoré), ou une règle location en conflit intercepte /wp-json.

Correction : Corrigez le routage du serveur web pour passer les chemins inconnus vers index.php ; videz les permaliens ; vérifiez que /wp-json/ retourne du JSON.

5) Symptomatique : fonctionne sur l’origine, échoue via le CDN

Cause racine : Cache CDN ou différences de politique de sécurité à la périphérie. Parfois l’edge injecte des redirections ou bloque des POST.

Correction : Contournez le CDN pour confirmer ; puis configurez les règles edge pour ne pas mettre en cache /wp-json/*, autoriser les méthodes REST, et forwarder les en-têtes/cookies nécessaires.

6) Symptomatique : échecs aléatoires ; parfois « réponse JSON invalide », parfois OK

Cause racine : Timeouts upstream intermittents, saturation PHP-FPM, ou conditions de course de cache renvoyant des réponses partielles/tronquées.

Correction : Vérifiez les timeouts upstream et la santé de PHP-FPM ; augmentez les limites prudemment ; corrigez les plugins/DB lents ; n’exposez pas le cache aux flows admin et REST.

7) Symptomatique : la réponse est JSON mais l’éditeur plante toujours

Cause racine : Le JSON est mal formé (warnings PHP injectés), ou la réponse est compressée/tronquée par un proxy ; parfois des problèmes d’encodage ou BOM apparaissent depuis du code personnalisé.

Correction : Cherchez les warnings/notices PHP, désactivez les hacks de buffering de sortie, et confirmez que le corps brut commence par { ou [ et est complet.

8) Symptomatique : un seul utilisateur admin le voit ; les autres non

Cause racine : Extensions de navigateur, cookies obsolètes, chemin réseau différent (VPN), ou déclencheur de WAF/limite de taux par utilisateur.

Correction : Comparez les en-têtes et réponses entre utilisateurs ; testez dans un profil de navigateur propre ; vérifiez les logs WAF indexés par IP/user-agent.

Trois mini-récits d’entreprise tirés de la vie opérationnelle

Mini-récit 1 : L’incident causé par une mauvaise hypothèse

Une équipe marketing a déployé un « petit » changement de domaine : déplacer le blog de blog.example.com vers www.example.com/blog.
Le plan de migration portait surtout sur les redirections et le SEO. Tout le monde s’accordait à dire que l’éditeur continuerait de fonctionner parce que « c’est la même instance WordPress ».

Le premier signe de problème n’a pas été une erreur 500 ni une indisponibilité. Ce fut des éditeurs incapables de publier. « Réponse JSON invalide » est apparu
lors de la sauvegarde des articles, alors que le frontend s’affichait correctement. L’hypothèse était que l’API REST suivrait les mêmes redirections que le navigateur.
Elle les a suivies — droit vers une page de connexion provenant d’un autre scope de cookie.

Les appels REST étaient redirigés de /blog/wp-json/ vers /wp-json/ à la périphérie, et les cookies définis pour
blog.example.com n’étaient pas envoyés à www.example.com. WordPress a donc traité les requêtes authentifiées comme anonymes,
a renvoyé du HTML de connexion, et Gutenberg a signalé JSON invalide.

La correction n’a rien d’héroïque : définir des URLs canoniques cohérentes (home/siteurl), arrêter de rediriger les endpoints REST différemment des chemins normaux,
et aligner les domaines de cookie. Ce qui a coûté du temps, ce sont les heures passées à « déboguer WordPress » alors que le problème était une simple incohérence d’origine/hôte.

Mini-récit 2 : L’optimisation qui a mal tourné

Une équipe plate-forme a voulu « accélérer WordPress » en cachant plus agressivement au niveau du CDN. La règle était simple : mettre en cache tout ce qui ne ressemble pas à de l’admin.
Quelqu’un a ajouté une exception pour /wp-admin et a considéré le travail terminé.

Sauf que Gutenberg ne vit pas uniquement dans /wp-admin. Il parle constamment à /wp-json/, et ces requêtes portent des cookies et des nonces.
Le CDN, qui ne comprend pas la sémantique WordPress, a mis en cache une réponse 403 d’une requête initiale qui avait déclenché une règle de rate-limit. Puis il a servi ce 403 à tout le monde.
L’erreur de l’éditeur est apparue sur plusieurs sites et environnements. Le frontend fonctionnait toujours — les caches sont formidables pour masquer des problèmes jusqu’à les amplifier.

Le rollback a été immédiat : purge du cache, désactivation du caching pour /wp-json/*, et arrêt du cache des réponses quand des cookies sont présents.
Ensuite est venue la post-mortem gênante : l’équipe avait optimisé sans liste explicite de chemins « à ne jamais cacher ».

La correction durable fut ennuyeuse : une politique de cache partagée avec exclusions explicites pour les endpoints REST et les flows admin, plus des checks automatisés
qui valident que /wp-json/ retourne application/json et une réponse non mise en cache. Les gains de performance sont venus plus tard, obtenus prudemment.

Mini-récit 3 : La pratique ennuyeuse mais correcte qui a sauvé la journée

Une entreprise possédant plusieurs propriétés WordPress avait l’habitude — qui semblait excessive — d’un petit probe synthétique toutes les cinq minutes.
Il récupérait /wp-json/ et un endpoint authentifié représentatif, et échouait bruyamment si le content-type n’était pas JSON ou si le corps contenait <html.

Un matin, le probe a déclenché juste après une mise à jour routinière des règles de sécurité. Les éditeurs n’avaient pas encore râlé, mais le système l’avait déjà détecté.
L’équipe opérations a regardé les logs WAF et a trouvé des requêtes OPTIONS bloquées pour /wp-json, ce qui casserait l’éditeur dans certains navigateurs et réseaux.

Parce que le probe enregistrait le code de statut exact et les en-têtes de réponse, l’équipe n’a pas tergiversé. Ils ont déployé une exception étroite :
autoriser OPTIONS et POST vers /wp-json/ pour les sessions authentifiées, en gardant le reste des règles intact.

Personne n’a écrit de thread Slack dramatique. L’éditeur n’est jamais tombé pour la plupart des utilisateurs. Le meilleur travail opérationnel ressemble souvent à rien,
ce qui est le compliment le plus élevé que vous ne recevrez jamais.

Listes de contrôle / plan étape par étape

Triage étape par étape (15–30 minutes)

  1. Capturez l’appel REST qui échoue dans DevTools : URL, code de statut, corps de réponse (200 premiers octets), et toutes les redirections.
  2. Testez /wp-json/ avec curl et confirmez application/json en content-type et un JSON valide.
  3. Testez un endpoint réel comme /wp-json/wp/v2/types/post. Si celui-ci échoue, ne perdez pas de temps avec des théories spécifiques à Gutenberg.
  4. Vérifiez les redirections avec curl -I -L. Éliminez les boucles de redirection en premier.
  5. Contournez le CDN (accès direct à l’origine) et comparez les résultats. Si l’origine fonctionne, arrêtez de déboguer WordPress et commencez à déboguer la périphérie.
  6. Consultez les logs serveur/WAF pour des blocages 401/403 autour du moment de votre test.
  7. Désactivez temporairement les plugins « à risque » : sécurité, cache, minify, gestionnaires d’en-têtes/CORS. Retestez.
  8. Vérifiez les logs PHP pour des warnings qui pourraient corrompre les réponses JSON.
  9. Confirmez les règles de réécriture (Nginx try_files / Apache AllowOverride + .htaccess). Retestez.

Checklist de stabilisation (même jour)

  • Exclure /wp-json/* du cache de page/CDN sauf si vous maîtrisez parfaitement les implications.
  • Autoriser les méthodes REST : GET/POST/PATCH/PUT/DELETE et OPTIONS quand approprié. Bloquer par authentification, pas uniquement par chemin.
  • Standardiser l’hôte et le schéma canoniques (HTTPS). Définir home et siteurl de façon cohérente.
  • Assurer que le reverse proxy définit X-Forwarded-Proto et que l’application lui fait confiance (ou terminer TLS au niveau de WordPress).
  • Corriger les warnings/notices PHP dans le code de production. « Ce n’est qu’un warning » est la façon d’obtenir un JSON invalide à 15h.
  • Mettre en place un probe basique : récupérer /wp-json/ et valider JSON + content-type.

Checklist de prévention (ce mois)

  • Définir une politique de « routes non cachables » (pas un savoir tacite) : REST, admin, login, panier/checkout si applicable.
  • Tester les changements edge/WAF contre les endpoints REST avant déploiement.
  • Maintenir un set minimal de plugins ; préférer peu de plugins bien maintenus plutôt que des couches « d’optimisation » empilées.
  • Versionner la config proxy et les réglages d’environnement WordPress ; traitez-les comme du code de production.
  • Instrumenter : suivre les codes HTTP pour /wp-json/*, et alerter sur des pics de 401/403/5xx.

FAQ

1) « Réponse JSON invalide » est-ce toujours un bug WordPress ?

Non. C’est généralement WordPress qui dit la vérité sur une requête HTTP échouée. La plupart des cas viennent de redirections SSL, blocages WAF, cache, ou interférence de plugins.
Commencez par la réponse réseau, pas par l’interface WordPress.

2) Pourquoi le frontend fonctionne-t-il alors que l’éditeur échoue ?

Les pages frontend peuvent être rendues depuis du HTML mis en cache et tolérer des redirections. L’éditeur nécessite des endpoints REST, la bonne auth, et des réponses JSON.
Vous pouvez avoir un site qui semble parfait alors que son plan de contrôle est cassé.

3) Quel est le test le plus rapide ?

Récupérez /wp-json/ et vérifiez que vous obtenez 200 et Content-Type: application/json, plus un corps JSON.
Si vous obtenez du HTML, vous avez un problème de routage/auth/sécurité.

4) Le CORS peut-il causer cela même sur un WordPress « normal » ?

Oui, si l’interface admin ou les requêtes API proviennent d’un domaine/port différent (hôtes admin personnalisés, headless, staging derrière une origine différente).
Les échecs CORS peuvent se manifester comme « réponse JSON invalide » car le JS ne peut pas lire la réponse.

5) Les plugins de cache cassent-ils souvent le REST ?

Ils le peuvent. Les bons essaient de ne pas le faire, mais la mauvaise configuration est fréquente. Si une couche de cache met en cache /wp-json ou ignore les cookies, vous obtiendrez des réponses erronées
servies aux requêtes authentifiées. Excluez les routes REST du cache de page sauf si vous êtes très délibéré.

6) Pourquoi désactiver un plugin de sécurité le corrige parfois ?

Certains plugins de sécurité bloquent les endpoints REST pour réduire la surface d’attaque. Ce n’est pas intrinsèquement faux, mais c’est souvent trop agressif pour Gutenberg.
Configurez des listes blanches pour les utilisateurs authentifiés et les endpoints requis au lieu de blocages globaux.

7) Cela pourrait-il venir d’un problème de stockage ou système de fichiers ?

Indirectement. Si le système est sous pression d’I/O et que PHP timeoute, les requêtes REST peuvent échouer ou retourner des réponses partielles.
Mais « Réponse JSON invalide » n’est rarement le premier symptôme d’un souci disque ; vous verrez en général des timeouts, 502/504, et un admin lent.

8) Et si REST fonctionne avec curl mais échoue dans le navigateur ?

Cela pointe vers CORS, cookies/nonces, ou couches spécifiques au navigateur (extensions, blocage de contenu mixte, politiques de transport strictes).
Comparez les en-têtes de requête entre curl et le navigateur ; vérifiez la console DevTools pour les erreurs CORS ou de contenu mixte.

9) Changer les réglages de permaliens aide-t-il ?

Parfois. « Enregistrer les permaliens » force un flush des réécritures, ce qui peut réparer des règles manquantes après des migrations.
Si le routage du serveur web est mauvais, aucun flush WordPress ne réparera la config Nginx/Apache.

10) Quelle est l’approche la plus sûre en production pour déboguer ?

Évitez les basculements aléatoires. Capturez la requête qui échoue, testez origine vs périphérie, et isolez un changement à la fois.
Si vous désactivez des plugins, faites-le brièvement et pendant des fenêtres à faible impact. Mieux : reproduisez sur un staging qui reflète la configuration proxy de production.

Prochaines étapes à suivre réellement

Si vous êtes en plein incident, appliquez le playbook rapide : inspectez la requête REST qui échoue, faites un curl sur /wp-json/, et contournez le CDN.
Cela vous indiquera en quelques minutes quelle couche est fautive.

Ensuite, corrigez ce qui est prouvé cassé :

  • Si vous voyez des redirections ou des basculements de schéma : alignez les URL WordPress, corrigez les en-têtes proxy, arrêtez de special-caser /wp-json.
  • Si vous voyez 403/401 avec des corps HTML : ajustez WAF/plugins de sécurité, excluez REST du cache, assurez la validité des en-têtes/cookies d’auth.
  • Si vous voyez 404 : réparez les réécritures dans Nginx/Apache et videz les permaliens ensuite.
  • Si vous voyez du JSON malformé : éliminez les warnings/notices PHP et la sortie avant les en-têtes depuis thèmes/plugins.

Enfin, prévenez la répétition : ajoutez un petit probe synthétique pour la santé REST, codifiez les exclusions de cache, et traitez les changements proxy/WAF comme des déploiements.
WordPress n’est pas fragile. Il est simplement entouré de couches qui sont très confiantes et occasionnellement dans l’erreur.

← Précédent
Docker « le volume est utilisé » : supprimer ou remplacer sans perte de données
Suivant →
AMD Adrenalin : quand les fonctionnalités logicielles comptent plus que le silicium

Laisser un commentaire