WordPress «Invalid JSON response»: причини та виправлення, які справді працюють

Було корисно?

Редактор WordPress показує «Invalid JSON response», і раптом ваше «просте оновлення контенту» перетворюється на інцидент у продакшені.
Пости не публікуються. Налаштування не зберігаються. Блоковий редактор періодично відмовляє співпрацювати. А консоль браузера тихо кричить про те, що REST-запити не вдаються.

Ця помилка не є загадкою. Це симптом: WordPress очікував JSON від REST API, але отримав щось інше — HTML-сторінку входу,
403 від WAF, петлю перенаправлень, помилку TLS, закешований 404 або плагін, що «допомагає» переписувати заголовки.
Ми розглянемо це як проблему SRE: спостерігай, звужуй, доводь, лагодь, запобігай.

Що насправді означає «Invalid JSON response»

WordPress (особливо Блоковий редактор/Gutenberg) спілкується з вашим сайтом через REST API. Він робить HTTP-запити до кінцевих точок на кшталт
/wp-json/wp/v2/posts. Очікується, що тіло відповіді міститиме дійсний JSON, а HTTP-статус вказуватиме на успіх
(зазвичай 200/201).

Коли цього не відбувається — бо відповідь була HTML, порожня, обірвана, перенаправлена, заблокована або віддана з неправильного хоста — редактор
викидає загальне повідомлення «Invalid JSON response». Це фактично означає: WordPress запитав JSON, а реальність не погодилася.

Ваше завдання — з’ясувати, що саме повернула реальність. Це завжди видно в одному місці: мережевій відповіді на REST-запит
(код статусу, заголовки, тіло). Якщо ви гадаєте — ви витрачаєте час даремно.

Одне висловлювання варто пам’ятати під час відладки: парафразована ідея — Charity Majors: «Ви не можете покращити те, що не вимірюєте.»
Помилка редактора — це не вимір. HTTP-обмін — ось що вимірює.

Швидкий план діагностики (перші/другі/треті перевірки)

Спершу: підтвердіть невдалий запит і те, що повернулося

  1. Відкрийте інструменти розробника браузера → Network.
  2. Запустіть дію збереження/публікації, яка не вдається.
  3. Знайдіть запит до /wp-json/ (часто /wp-json/wp/v2/posts/<id> або /wp-json/wp/v2/settings).
  4. Перегляньте: код статусу, тіло відповіді та будь-які перенаправлення.

Рішення: якщо тіло відповіді — HTML (сторінка входу, сторінка помилки, сторінка блокування WAF), ви маєте справу не з «парсингом JSON».
Ви маєте справу з автентифікацією, маршрутизацією, фільтрацією безпеки, кешуванням або переписуванням зверху.

По-друге: зверніться до REST API безпосередньо зі своєї робочої станції

Використайте curl проти простої кінцевої точки, наприклад /wp-json/, і реальної кінцевої точки, наприклад /wp-json/wp/v2/types/post.
Виконайте з аутентифікацією і без неї (якщо потрібно). Це відокремлює «дивні речі в браузері/CORS» від «сервер не працює».

По-третє: обходьте шари

Сайти на WordPress рідко існують «лише як WordPress». У них є CDN, зворотний проксі, WAF, кеш і зоопарк плагінів.
Обходьте в такому порядку:

  1. Обійдіть CDN (зверніться напряму до origin через hosts файл або хост для origin).
  2. Обійдіть кеш (надсилайте Cache-Control: no-cache; тимчасово вимкніть кеш сторінок).
  3. Вимикайте плагіни (спочатку — безпекові, кешувальні та плагіни з заголовками).
  4. Переключіться на стандартну тему (так, теми можуть ламати REST).

Рішення: у момент, коли відповідь REST знову стає коректним JSON, ви виявили шар, який треба дослідити. Не вмикайте все одразу.
Робіть по одному зміненню за раз. Ви дебажите, а не виконуєте інтерпретаційний танець.

Цікаві факти та історичний контекст (чому це повторюється)

  • REST API не завжди був частиною ядра. Можливості REST API еволюціонували через плагіни, перш ніж стати частиною ядра, тож старі екосистеми мають «свої думки» про нього.
  • Gutenberg підвищив ставки. Блоковий редактор значно залежить від REST; класичні робочі процеси рідше зверталися до кінцевих точок і приховували серверні проблеми.
  • «Invalid JSON» часто означає «виник HTML». Форма входу, сторінка помилки 403 або документ WAF «доступ заборонено» — це валідний HTML і невалідний JSON — WordPress звітує про це однаково.
  • Налаштування постійних посилань мають значення. Правила перепису — це не лише SEO. Неправильні правила можуть перетворити API-маршрути на 404, і редактор втрачає зв’язок.
  • CORS став помітнішим з сучасними браузерами. Посилені політики браузерів зробили некоректні заголовки міждоменного доступу більш гучними, особливо для headless-налаштувань.
  • Плагіни безпеки люблять блокувати REST. Багато були створені, коли REST був «опціональним»; деякі досі вважають /wp-json/ підозрілим трафіком.
  • CDN кешують більше, ніж ви думаєте. Неправильна конфігурація кешу може зберегти 301/302/403/404 для API-маршрутів і охоче віддавати їх усім, включно з адміністраторами.
  • HTTP/2 і проксі змінили форми відмов. Деякі поєднання edge/proxy породжують поведінку заголовків і перенаправлень, що плутає клієнтів, які очікують стабільні кінцеві точки.
  • Змішаний контент ще не зник. Сайти, що частково мігрували на HTTPS, можуть все ще викликати REST-запити до HTTP у різних куточках (site URL vs home URL vs заголовки проксі).

Основні режими відмов: SSL, CORS, плагіни, проксі, кешування

1) SSL/TLS і «не та схема» (HTTP vs HTTPS)

Класика: ваша адмін-сторінка завантажується по HTTPS, але WordPress генерує REST-URL з HTTP (або навпаки).
Браузери можуть блокувати змішаний контент, або запит слідує за перенаправленнями й повертає HTML.

Типові корінні причини:

  • Несумісність Site URL/Home URL у налаштуваннях WordPress або в базі даних.
  • Зворотний проксі неправильно форвардить X-Forwarded-Proto; WordPress думає, що працює по HTTP.
  • HSTS та примусове HTTPS, що викликає додаткові перенаправлення або кешовані петлі перенаправлень.
  • Несумісність сертифіката для імені хоста, яке використовують для REST-запитів (www vs апекс).

2) Проблеми CORS (особливо для headless або нетипових адмін-оригінів)

Якщо ваш інтерфейс адміністрування розміщений на одному origin (домен/порт), а API WordPress — на іншому, браузер застосовує CORS.
Коли CORS не налаштовано, ви часто бачите, що UI WordPress повідомляє «Invalid JSON response», бо JS не може прочитати відповідь.

Типові тригери CORS:

  • Використання іншого домену для адмінки, ніж для API (наприклад, кастомний хост адмінки, staging-хости, нестандартні порти).
  • Відсутній заголовок Access-Control-Allow-Origin або неправильне значення.
  • Preflight OPTIONS блокується сервером/WAF.
  • Режим із обліковими даними (cookies) вимагає Access-Control-Allow-Credentials: true і конкретного origin (не wildcard).

3) Плагіни та теми: «допоміжне» саботаж

Значна кількість відмов REST є самосаботажем:

  • Плагіни безпеки блокують REST-ендпоінти через nonce або ліміти запитів.
  • Кешувальні плагіни кешують відповіді API або переписують заголовки.
  • Плагіни оптимізації/мініфікації ламають wp-api-fetch або інжекцію nonce.
  • Теми, які додають вивід до заголовків (PHP warnings/notices), що корумпує JSON-віходи.

Жарт №1: Найшвидший спосіб відтворити «Invalid JSON response» — встановити три «must-have» плагіни з блогу 2016 року.

4) Зворотні проксі, CDN і WAF: «middleboxes»

Зворотні проксі та CDN чудові, доки вони не вирішать, що ваш REST-запит потребує «покращення»:

  • 301/302 перенаправлення, застосовані до шляхів /wp-json/.
  • Правила WAF (ModSecurity або керований WAF), що блокують POST/PUT із JSON-тілом.
  • Ліміти розміру заголовків, тіла запиту або таймаути, що обрізають відповіді.
  • Ключі кешу, що ігнорують cookies; подача анонімних кешованих відповідей для адмін-запитів.

5) Переписування посилань і правила rewrites: нудно, але смертельно

Коли правила перепису неправильні, REST-маршрути можуть стати 404 або спрямовуватися в неправильний файл. WordPress тоді повертає HTML
(шаблон 404 або перенаправлення), а редактор називає це «Invalid JSON».

Проблеми з переписами трапляються після:

  • Перехід з Apache на Nginx без відповідних правил.
  • Зміни кореня документів або додавання інсталяції в підкаталог.
  • Увімкнення multisite або зміни налаштувань domain mapping.

6) Аутентифікація/nonce і «вас викинуло з сесії»

REST-ендпоінти WordPress часто вимагають дійсний nonce для адміністративних дій. Якщо cookies налаштовані неправильно (домен, secure-флаг),
або проксі видаляє заголовки, REST-запити можуть повертати 401/403. Іноді тіло відповіді — HTML (перенаправлення на сторінку входу).

Практичні завдання: команди, виводи, рішення (12+)

Сенс цих завдань — не просто друкувати команди заради розваги. Кожна з них дає конкретну інформацію і змушує прийняти рішення.
Виконуйте їх у шеллі з доступом до сервера, коли це можливо. Коли нема доступу — запускайте клієнтські варіанти зі своєї робочої станції.

Завдання 1: Підтвердьте, що коренева кінцева точка REST повертає 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,

Що це означає: 200 + application/json + JSON-тело в порядку на базовій кінцевій точці.
Рішення: Якщо це не так (не-200 або HTML), зосередьтеся на маршрутизації/WAF/SSL перед тим, як торкатися внутрішнього WordPress.

Завдання 2: Перевірте реальний REST-маршрут, який використовує 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

Що це означає: Базові кінцеві точки доступні й повертають парсабельний JSON.
Рішення: Якщо тут 401/403 — підозрюйте автентифікацію/nonce, WAF або плагіни безпеки. Якщо 404 — перевіряйте перепис/Permalinks/маршрути проксі.

Завдання 3: Виявіть петлі перенаправлень або плутанину зі схемою

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/

Що це означає: У вас є «ping-pong» перенаправлення між HTTP і HTTPS.
Рішення: Виправте заголовки проксі та налаштування URL WordPress передусім. Петлі перенаправлень — це не «дрібниця».

Завдання 4: Перевірте, чи сертифікат TLS відповідає хосту, який використовують 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

Що це означає: Сертифікат дійсний для імені хоста.
Рішення: Якщо CN/SAN не співпадає (наприклад, тільки www), вирівняйте канонічний хост або встановіть сертифікат, що покриває обидва.

Завдання 5: Перевірте значення «home» і «siteurl» у WordPress (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

Що це означає: Невідповідність. REST-URL може будуватися з siteurl у різних контекстах.
Рішення: Зробіть їх узгодженими (зазвичай обидва — HTTPS) і переконайтеся, що зворотний проксі повідомляє про HTTPS коректно.

Завдання 6: Безпечно виправте URL-адреси WordPress (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.

Що це означає: Канонічні URL тепер співпадають.
Рішення: Перепровірте /wp-json/ і збереження в Gutenberg. Якщо перенаправлення залишаються — шар проксі/CDN все ще переписує.

Завдання 7: Переконайтеся, що правила перепису присутні (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=/

Що це означає: WordPress знає про REST-rewrite правила.
Рішення: Якщо їх нема — скиньте permalink-правила. Якщо вони є, але запити все одно 404 — неправильні вебсерверні правила перепису.

Завдання 8: Підтвердіть, що Nginx маршрутизує /wp-json правильно

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;
        }
    }
}

Що це означає: Стандартний try_files fallback присутній.
Рішення: Якщо ви бачите конфліктний location-блок, що перехоплює /wp-json (або повертає статичний 404), виправте його.

Завдання 9: Перевірте правила .htaccess для Apache (якщо 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

Що це означає: Базові правила перепису WordPress на місці.
Рішення: Якщо RewriteEngine вимкнено або файл ігнорується (AllowOverride), маршрути REST можуть падати як 404. Виправте конфіг vhost відповідно.

Завдання 10: Виявлення блокувань WAF/ModSecurity в логах

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"]

Що це означає: Правило блокує вміст у REST-запиті.
Рішення: Виключіть REST-ендпоінти з набору правил або тонко налаштуйте правила для автентифікованих адміністративних шляхів. Не вимикайте безпеку глобально.

Завдання 11: Визначте, чи відповідь — HTML (сторінка входу) замість 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




Що це означає: WordPress очікував JSON, але отримав HTML — ймовірно відповідь входу/автентифікації або сторінку, згенеровану проксі.
Рішення: Виправте заголовки/кукі/nonce або правило проксі, яке переписує 401/403 у HTML-сторінку.

Завдання 12: Перевірте, чи не блокується preflight OPTIONS (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

Що це означає: Preflight блокується. Браузер відмовиться виконувати фактичний запит.
Рішення: Налаштуйте сервер/WAF так, щоб дозволити OPTIONS і повертати коректні CORS-заголовки для REST-шляхів.

Завдання 13: Перевірте, чи CDN кешує відповіді 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

Що це означає: Щось кешує корінь REST протягом годин.
Рішення: Виключіть /wp-json/* з кешування CDN/сторінок або встановіть Cache-Control: no-store для автентифікованих REST-ендпоінтів.

Завдання 14: Відтворіть запит так, як бачить його PHP-рантайм (локальний curl до origin)

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

Що це означає: Origin в порядку; щось спереду ламає це.
Рішення: Виправляйте правила проксі/CDN/WAF замість торкання налаштувань WordPress.

Завдання 15: Знайдіть PHP-попередження, що корумпують 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)"

Що це означає: Вивід відбувся перед заголовками; REST-відповідь може бути пошкоджена (JSON передують warnings).
Рішення: Виправте тему/плагін, що виводить зайве. У продакшені не покладайтеся на «сховати попередження» — їх треба усунути.

Завдання 16: Швидка ізоляція плагінів без видалення (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.

Що це означає: Ви можете тестувати поведінку REST з меншою кількістю рухомих частин.
Рішення: Якщо проблема зникає — вмикайте плагіни по одному. Якщо ні — не звинувачуйте плагіни за звичкою — переходьте до проксі/SSL/маршрутизації.

Жарт №2: «Invalid JSON response» — це спосіб WordPress сказати, що ваша інфраструктура має власні думки — і іноді вона в поганому настрої.

Типові помилки: симптом → корінна причина → виправлення

1) Симптом: Редактор не може опублікувати; у мережі видно 301/302, а потім HTML

Корінна причина: Канонізація схеми/хоста перенаправляє REST-ендпоінти (HTTP↔HTTPS, www↔apex), іноді в петлі.

Виправлення: Вирівняйте home і siteurl до канонічного HTTPS-хоста; виправте заголовки проксі (X-Forwarded-Proto) і припиніть спеціально переписувати /wp-json інакше, ніж звичайний трафік.

2) Симптом: REST-запит повертає 403 зі сторінкою «blocked» в HTML

Корінна причина: Правило WAF/ModSecurity спрацьовує через JSON-тіло, вміст поста або шаблони REST-маршрутів.

Виправлення: Налаштуйте WAF: дозволіть автентифіковані REST-шляхи, дозвольте OPTIONS і звузьте винятки до /wp-json/ та адміністраторів. Перевірте логи.

3) Симптом: REST-запит повертає 401; тіло нагадує сторінку входу

Корінна причина: Автентифікація/nonce не проходить через домен/secure-флаг cookie, кеш змішує анонімні/адмін-відповіді або проксі відтинає заголовки.

Виправлення: Переконайтеся, що адмін-cookie відправляються по HTTPS (secure), виключіть REST з кешування, і підтвердьте пересилання заголовка Authorization (особливо з Apache/Nginx + PHP-FPM).

4) Симптом: REST-ендпоінт повертає 404, але сторінки сайту працюють

Корінна причина: Правила перепису WordPress не застосовуються (помилка Nginx, .htaccess ігноруються), або конфліктний location-блок перехоплює /wp-json.

Виправлення: Виправте маршрутизацію вебсерверу, щоб невідомі шляхи передавалися в index.php; скиньте permalinks; перевірте, що /wp-json/ повертає JSON.

5) Симптом: Працює на origin, але через CDN падає

Корінна причина: CDN кешування або відмінності політики безпеки на edge. Іноді edge додає перенаправлення або блокує POST-запити.

Виправлення: Обходьте CDN, щоб підтвердити; потім налаштуйте правила edge, щоб не кешувати /wp-json/*, дозволяти REST-методи і форвардити необхідні заголовки/кукі.

6) Симптом: Випадки помилки випадкові; інколи «invalid JSON», інколи все ОК

Корінна причина: Переривчасті таймаути upstream, насичення PHP-FPM або умови гонки кешування, що повертають часткові/обрізані відповіді.

Виправлення: Перевірте таймаути upstream і стан PHP-FPM; збільшіть ліміти обережно; виправте повільні плагіни/БД; припиніть кешувати адмін і REST-відповіді.

7) Симптом: Відповідь — JSON, але редактор все одно показує помилку

Корінна причина: JSON пошкоджений (вставлено PHP warnings), або відповідь стиснута/обрізана проксі; іноді з’являються проблеми з кодуванням чи BOM через кастомний код.

Виправлення: Шукайте PHP warnings/notices, відключіть хакі з буферизацією виводу і підтвердіть, що сире тіло відповіді починається з { або [ і є повним.

8) Симптом: Лише один адміністратор баче це; інші — ні

Корінна причина: Розширення браузера, застарілі cookies, різний мережевий шлях (VPN) або персональні правила WAF/ліміти по IP.

Виправлення: Порівняйте заголовки й відповіді між користувачами; протестуйте в чистому профілі браузера; перевірте логи WAF за IP/юзер-агентом.

Три короткі історії з реальних операцій

Коротка історія 1: Інцидент через хибне припущення

Маркетингова команда перемістила блог з blog.example.com до www.example.com/blog.
План міграції був здебільшого про редиректи й SEO. Усі погодилися, що редактор працюватиме, бо «це той самий WordPress-інстанс».

Першим знаком проблеми не був 500 або відмова сайту. Редактори не могли публікувати. При збереженні поста з’являлося «Invalid JSON response»,
але фронтенд рендерився нормально. Припустили, що REST API піде за тим же редиректом, що браузер. Він пішов — прямо на сторінку входу з іншої області дії cookie.

REST-запити перенаправляли з /blog/wp-json/ на /wp-json/ на edge, а кукі для
blog.example.com не відправлялися до www.example.com. Тому WordPress вважав запити анонімними,
повертав HTML-сторінку входу, і Gutenberg повідомляв про невірний JSON.

Виправлення не було героїчним: встановили узгоджені канонічні URL (home/siteurl), перестали по-різному перенаправляти REST-ендпоінти,
та узгодили домени cookie. Боліло те, що годинами «відлагоджували WordPress», тоді як проблема була в базовій узгодженості origin/host.

Коротка історія 2: Оптимізація, що зіграла злий жарт

Платформена команда вирішила «прискорити WordPress», агресивно кешуючи на CDN. Правило було просте: кешувати все, що не виглядає як адмін.
Хтось додав виключення для /wp-admin і вважав справу зробленою.

Але Gutenberg не живе лише в /wp-admin. Він постійно спілкується з /wp-json/, і ці запити несуть кукі й nonce.
CDN, не розуміючи семантики WordPress, закешував 403-відповідь від раннього запиту, що вперся в ліміт. Потім той 403 діставали всі.
Помилка редактора з’явилася на кількох сайтах і середовищах. Фронтенд все ще був нормальний — кеши чудово ховають проблеми, поки не починають їх посилювати.

Відкат був миттєвим: очистили кеш, вимкнули кешування для /wp-json/* і перестали кешувати відповіді, коли є кукі.
Потім була неприємна постмортем-деталь: команда оптимізувала без списку «шляхів, які ніколи не кешувати».

Тривале виправлення було нудним: спільна політика кешування з явними виключеннями для REST і адміністративних потоків, плюс автоматичні перевірки,
що валідують /wp-json/ на предмет application/json і некешованої відповіді. Продуктивність прийшла пізніше, але заслужено.

Коротка історія 3: Нудна, але правильна практика, що врятувала ситуацію

Компанія з кількома WordPress-властивостями мала практику, що здавалась надмірною: невеликий синтетичний проб, що запускався кожні п’ять хвилин.
Він фетчив /wp-json/ та представницьку автентифіковану кінцеву точку, і тригерив тривогу, якщо content-type не був JSON або тіло містило <html.

Одного ранку проб спрацював відразу після рутинного оновлення правил безпеки. Редактори ще не поскаржилися, але система вже знала.
Операційна команда подивилася логи WAF і знайшла, що OPTIONS-запити блокуються для /wp-json, що в певних браузерах і мережах ламало редактор.

Оскільки проб зафіксував точний код статусу і заголовки відповіді, команда не дискутувала. Вони розгорнули вузький виняток:
дозволити OPTIONS і POST для /wp-json/ для автентифікованих сесій, лишивши решту правил незмінними.

Ніхто не писав драматичний Slack-тред. Редактор ніколи не впав для більшості користувачів. Найкраща операційна робота часто виглядає як «нічого не сталося»,
і це найвища похвала, яку ви, ймовірно, ніколи не отримаєте.

Чеклісти / покроковий план

Покрокова триажа (15–30 хвилин)

  1. Зафіксуйте невдалий REST-запит в DevTools: URL, код статусу, тіло відповіді (перші 200 байт) і всі перенаправлення.
  2. Протестуйте /wp-json/ за допомогою curl і підтвердьте application/json content-type та валідний JSON.
  3. Перевірте реальну кінцеву точку, як-от /wp-json/wp/v2/types/post. Якщо вона падає — не забивайтеся теоріями, специфічними для Gutenberg.
  4. Перевірте на перенаправлення через curl -I -L. Виріжте петлі перенаправлень у першу чергу.
  5. Обійдіть CDN (прямий origin) і порівняйте результати. Якщо origin працює — припиніть дебаг WordPress і почніть дебаг edge.
  6. Перевірте логи сервера/WAF на наявність блокувань 401/403 у час тесту.
  7. Тимчасово вимкніть «ризикові» плагіни: безпека, кеш, мініфікація, менеджери заголовків/CORS. Перетестуйте.
  8. Перегляньте PHP-логи на предмет попереджень, що можуть корумпувати JSON-відповіді.
  9. Підтвердіть правила перепису (Nginx try_files / Apache AllowOverride + .htaccess). Перетестуйте.

Чекліст для стабілізації (того самого дня)

  • Виключіть /wp-json/* з кешування сторінок/CDN, якщо ви не розумієте наслідків.
  • Дозвольте REST-методи: GET/POST/PATCH/PUT/DELETE і OPTIONS там, де це потрібно. Блокуйте за автентифікацією, а не за шляхом.
  • Уніфікуйте канонічний хост і схему (HTTPS). Налаштуйте home і siteurl узгоджено.
  • Переконайтеся, що зворотний проксі встановлює X-Forwarded-Proto і додаток йому довіряє (або завершуйте TLS на WordPress).
  • Виправте PHP warnings/notices у продакшн-коді. «Це лише попередження» — якраз те, що дає вам invalid JSON о 15:00.
  • Поставте простий probe: фетч /wp-json/ і перевірка JSON + content-type.

Чекліст запобігання (протягом місяця)

  • Затвердьте політику «не кешованих маршрутів» як документ (не як племінне знання): REST, адміністрація, вхід, корзина/оплата, якщо актуально.
  • Тестуйте зміни на edge/WAF проти REST-ендпоінтів перед розгортанням.
  • Тримайте мінімальний набір плагінів; надавайте перевагу небагатьом, добре підтримуваним плагінам над купою «оптимізаційних» шарів.
  • Версіонуйте конфіг проксі і налаштування середовища WordPress; поводьтеся з ними як з продакшн-кодом.
  • Інструментуйте: відстежуйте HTTP-коди для /wp-json/* і сповіщайте про сплески 401/403/5xx.

FAQ

1) Чи завжди «Invalid JSON response» — це помилка WordPress?

Ні. Зазвичай WordPress чесно каже про невдалий HTTP-запит. У більшості випадків це SSL-перенаправлення, блокування WAF, кешування або втручання плагінів.
Починайте з мережевої відповіді, а не з UI WordPress.

2) Чому фронтенд працює, а редактор падає?

Фронтенд-сторінки можуть рендеритись із кешованого HTML і толерувати перенаправлення. Редактор потребує REST-ендпоінтів, коректної автентифікації і JSON-відповідей.
Можна мати ідеально виглядаючий сайт з поламаною контрольною панеллю.

3) Який найшвидший тест?

Отримайте /wp-json/ і перевірте, що отримали 200 і Content-Type: application/json, плюс JSON-тело.
Якщо ви бачите HTML — у вас проблема маршрутизації/автентифікації/безпеки.

4) Чи може CORS спричинити це навіть на звичайному WordPress-сайті?

Так, якщо інтерфейс адмінки або API-запити походять з іншого домену/порту (кастомний хост адмінки, headless, staging). CORS-помилки можуть проявлятися як «invalid JSON»,
бо JS не може прочитати відповідь.

5) Чи часто кешувальні плагіни ламають REST?

Можуть. Хороші плагіни намагаються уникати цього, але неправильна конфігурація — звична річ. Якщо шар кешу кешує /wp-json або ігнорує кукі,
ви отримаєте некоректні відповіді для автентифікованих запитів. Виключайте REST-маршрути з кешу, якщо не впевнені.

6) Чому відключення плагіна безпеки іноді допомагає?

Деякі плагіни безпеки блокують REST-ендпоінти, щоб зменшити площу атаки. Це не завжди погано, але часто надто агресивно для Gutenberg.
Налаштуйте allowlist для автентифікованих користувачів і потрібних кінцевих точок замість тотального блокування.

7) Чи може це бути проблемою з диском або файловою системою?

Опосередковано — так. Якщо система страждає від I/O і PHP таймаутиться, REST-запити можуть падати або повертати часткові відповіді.
Але «Invalid JSON» рідко буде першим симптомом проблеми з диском; зазвичай ви бачите таймаути, 502/504 і загальну повільність адмінки.

8) Що робити, якщо REST працює через curl, але не в браузері?

Це вказує на CORS, кукі/nonce або браузерні шари (розширення, блокування змішаного контенту, строгі політики транспорту).
Порівняйте заголовки запиту між curl і браузером; перегляньте консоль DevTools на предмет CORS або помилок змішаного контенту.

9) Чи допомагає зміна налаштувань permalink?

Іноді. «Зберегти permalink-налаштування» примусово робить flush rewrite, що може виправити відсутні правила після міграцій.
Якщо ж вебсервер налаштований неправильно — жодна кількість скидань WordPress не виправить конфіг Nginx/Apache.

10) Який найбезпечніший підхід до дебагу в продакшені?

Уникайте хаотичного переключення. Зафіксуйте невдалий запит, протестуйте origin vs edge і ізолюйте одну зміну за раз.
Якщо вимикаєте плагіни — робіть це ненадовго й у вікно низького навантаження. Краще: відтворіть на staging з продакшн-подібними проксі-правилами.

Наступні кроки, які варто зробити

Якщо ви посеред інциденту — виконайте швидкий план: зафіксуйте невдалий REST-запит, зробіть curl /wp-json/ і обійдіть CDN.
Це підкаже, який шар винен за лічені хвилини.

Далі виправляйте те, що доведено як поламане:

  • Якщо ви бачите перенаправлення або зміну схеми: вирівняйте URL WordPress, виправте заголовки проксі і перестаньте спеціалізовано обробляти /wp-json.
  • Якщо бачите 403/401 з HTML-телом: налаштуйте WAF/плагіни безпеки, виключіть REST з кешування, переконайтеся, що заголовки/кукі для автентифікації працюють.
  • Якщо бачите 404: відновіть правила перепису в Nginx/Apache і скиньте permalinks.
  • Якщо бачите пошкоджений JSON: усуньте PHP warnings/notices і вивід перед заголовками від тем/плагінів.

Нарешті, щоб уникнути повторення: додайте невеликий синтетичний probe для моніторингу здоров’я REST, зафіксуйте виключення для кешу і ставте зміни проксі/WAF
так само ретельно, як розгортання коду. WordPress не крихкий. Він просто оточений шарами, які впевнені у собі і час від часу помиляються.

← Попередня
Docker “volume is in use”: видалити або замінити без втрати даних
Наступна →
AMD Adrenalin: коли програмні функції важливіші за кремній

Залишити коментар