Если внешний сервис, кастомная тема или плагин внезапно перестали получать данные из REST API WordPress, чаще всего проблема не в самом API, а в авторизации, кэше, защите на сервере или в плагине безопасности. Ошибка может выглядеть как 401 Unauthorized, 403 Forbidden или даже как пустой ответ, если запрос режется до PHP.
Ниже — практический разбор: как быстро локализовать источник блокировки, что менять в настройках и коде, и как проверить, что после правки API действительно работает, а не просто “ошибка исчезла в админке”.
Когда проблема точно в REST API, а не в теме или JS
Сначала нужно понять, где ломается цепочка. REST API WordPress обычно отвечает по адресу /wp-json/. Если этот URL открывается в браузере, но конкретный запрос возвращает 401/403, значит базовый маршрут жив, а блокировка происходит на уровне прав доступа, nonce, заголовков или фильтров.
Типичные симптомы
- в консоли браузера запрос к
/wp-json/wp/v2/postsвозвращает 401 или 403; - внешний сервис не может получить данные по Basic Auth, Application Passwords или OAuth-обвязке;
- после установки плагина безопасности перестали работать AJAX-формы и headless-интеграции;
- на одном хостинге API работает, на другом — нет, хотя код одинаковый;
- запросы проходят в админке, но падают с фронтенда из-за отсутствия nonce.
Что проверить первым делом
- Откройте
/wp-json/в браузере без авторизации. - Проверьте конкретный маршрут, например
/wp-json/wp/v2/posts?per_page=1. - Посмотрите ответ в DevTools: статус, заголовки, тело ошибки.
- Временно отключите плагины безопасности и кэширования на тестовой копии сайта.
- Проверьте, не режет ли запрос серверный WAF, ModSecurity или Cloudflare.
Почему WordPress REST API отвечает 401 или 403
У этих статусов разные причины, и лечатся они по-разному. 401 обычно означает, что запрос не авторизован или авторизация не дошла до WordPress. 403 чаще связан с запретом доступа: по правам пользователя, nonce, правилам безопасности или серверной фильтрации.
| Сценарий | Что видите | Что обычно делать |
|---|---|---|
| Нет авторизации | 401 Unauthorized | Проверить заголовок Authorization, Application Passwords, cookies и nonce |
| Плагин безопасности | 403 Forbidden | Найти правило блокировки, добавить исключение для маршрута |
| Серверный WAF | 403 или пустой ответ | Смотреть логи ModSecurity/Cloudflare, менять правило на стороне хостинга |
| Неверный capability | 401/403 на кастомном endpoint | Исправить callback проверки прав в permission_callback |
Пошаговое решение: от проверки заголовков до прав доступа
1. Проверьте, доходит ли заголовок Authorization
Если вы используете Application Passwords или внешнюю авторизацию, сервер должен передавать заголовок Authorization в PHP. На части конфигураций Nginx/Apache он теряется, и WordPress видит запрос как анонимный.
// functions.php или mu-plugin: диагностический лог для REST-запросов
add_action('rest_api_init', function () {
if (defined('WP_DEBUG') && WP_DEBUG) {
error_log('REST Authorization: ' . (isset($_SERVER['HTTP_AUTHORIZATION']) ? 'present' : 'missing'));
}
});Если в логе заголовка нет, сначала чините серверную конфигурацию. На Nginx часто нужно явно пробросить заголовок в PHP-FPM. На Apache проблема может быть в правилах прокси или модуле авторизации.
2. Убедитесь, что endpoint не требует лишних прав
Для кастомных маршрутов в register_rest_route() часто ставят слишком строгий permission_callback. В результате запросы от фронтенда или внешнего сервиса получают 403, хотя данные не секретные.
add_action('rest_api_init', function () {
register_rest_route('site/v1', '/public-data', [
'methods' => 'GET',
'callback' => function () {
return [
'status' => 'ok',
'time' => current_time('mysql'),
];
},
'permission_callback' => '__return_true',
]);
});Если данные публичные, не проверяйте там current_user_can() без необходимости. Если данные приватные, проверяйте конкретную capability, а не просто факт входа в систему.
3. Проверьте nonce для запросов из админки
Для запросов из wp-admin и некоторых фронтенд-скриптов WordPress ожидает nonce. Если тема или плагин отправляет устаревший nonce, API вернёт 403 с сообщением о проверке безопасности.
wp_localize_script('my-admin-script', 'MyApi', [
'root' => esc_url_raw(rest_url()),
'nonce' => wp_create_nonce('wp_rest'),
]);На стороне JavaScript заголовок должен уходить в запросе:
fetch(MyApi.root + 'wp/v2/posts?per_page=1', {
method: 'GET',
headers: {
'X-WP-Nonce': MyApi.nonce
},
credentials: 'same-origin'
});Если nonce создаётся правильно, но запрос всё равно падает, проверьте, не кэшируется ли HTML-страница с устаревшим токеном.
4. Исключите плагины безопасности и кэш
Частая история: REST API блокирует не WordPress, а плагин, который считает запрос подозрительным. Это особенно заметно, если на сайте включены ограничения по /wp-json/, защита от брутфорса, скрытие версии или фильтрация заголовков.
На тестовой копии отключайте плагины по одному и повторяйте запрос. Если проблема исчезает после деактивации конкретного плагина, ищите в его настройках исключение для REST API или whitelist для маршрута.
- проверьте правила, связанные с
wp-json; - посмотрите, не блокируется ли
Authorization; - отключите агрессивный кэш для страниц, где формируется nonce;
- убедитесь, что CDN не кэширует ответ API как статический.
Если ошибка появляется только на кастомном endpoint
Тогда проблема почти всегда в коде маршрута. WordPress не даст выполнить callback, если permission_callback возвращает false или если в нём есть ошибка. Иногда разработчик случайно использует is_user_logged_in() там, где нужен более точный контроль прав.
Ниже пример безопасной проверки доступа для endpoint, который должен быть доступен только редакторам и администраторам:
add_action('rest_api_init', function () {
register_rest_route('site/v1', '/reports', [
'methods' => 'GET',
'callback' => 'site_get_reports',
'permission_callback' => function () {
return current_user_can('edit_others_posts');
},
]);
});
function site_get_reports(WP_REST_Request $request) {
return rest_ensure_response([
'items' => [],
]);
}Если endpoint должен работать для внешнего сервиса, не завязывайте его на текущую сессию WordPress. Лучше использовать отдельный механизм авторизации или хотя бы проверку токена в заголовке.
Как проверить, что исправление сработало
После правок важно не ограничиваться открытием страницы в браузере. REST API нужно проверять тем же способом, которым его использует реальный клиент: из консоли, из curl или из приложения.
Проверка через curl
curl -i https://example.com/wp-json/wp/v2/posts?per_page=1Если запрос авторизованный, добавьте заголовки, которые использует ваш сценарий:
curl -i \
-H 'Authorization: Basic base64loginpassword' \
-H 'X-WP-Nonce: your-nonce' \
https://example.com/wp-json/wp/v2/users/meСмотрите не только на код ответа, но и на тело. WordPress обычно возвращает полезное сообщение, по которому можно понять, что именно сломано: nonce, права, маршрут или авторизация.
Проверка в браузере
- ответ
200на нужный маршрут; - нет редиректа на страницу логина;
- нет сообщений о невалидном nonce;
- в DevTools виден корректный заголовок
AuthorizationилиX-WP-Nonce; - данные приходят именно с того сайта, а не из старого кэша CDN.
Частые ошибки и как их исправить
Ставят __return_true на приватный endpoint
Это удобно на старте, но опасно в продакшене. Если маршрут отдаёт чувствительные данные, оставлять его открытым нельзя. Исправление простое: ограничьте доступ через capability или отдельную проверку токена.
Проверяют только is_user_logged_in()
Пользователь может быть залогинен, но не иметь нужных прав. Для REST API лучше проверять конкретную capability, например edit_posts, manage_options или более узкую, если она есть в вашей роли.
Не учитывают кэш страницы с nonce
Если HTML кэшируется, nonce в нём быстро устаревает. В итоге фронтенд отправляет валидный на вид, но уже нерабочий токен. Для таких страниц нужно исключение из кэша или отдельная подгрузка nonce через AJAX.
Блокируют API на уровне WAF
Иногда хостинг или CDN режет запросы к /wp-json/ по сигнатурам. В WordPress это выглядит как “непонятный 403”, но в логах сервера видно конкретное правило. Без логов здесь легко потратить время на правку PHP, хотя проблема находится выше.
Практика: как не сломать безопасность и производительность
Открывать REST API шире, чем нужно, не стоит. Но и закрывать всё подряд — плохая идея: ломаются редактор, мобильные клиенты, интеграции и собственные скрипты. Рабочий подход — минимально необходимый доступ и точечные исключения.
- не отключайте REST API целиком, если не понимаете, какие части сайта его используют;
- для публичных данных делайте отдельный маршрут с понятным
permission_callback; - для приватных данных проверяйте capability, а не только факт авторизации;
- не кэшируйте ответы, которые зависят от пользователя;
- проверяйте логи сервера до правки PHP, если ошибка возникает только на проде.
Если на сайте уже есть плагин для SEO и чистки дублей, например Clearfy Pro, его настройки стоит проверять отдельно: иногда именно там включены ограничения, которые затрагивают wp-json или заголовки авторизации. Но любые такие изменения лучше тестировать на staging, а не на живом сайте.
Когда REST API снова отвечает стабильно, у вас должны совпасть три вещи: запрос проходит без ручных обходов, права доступа соответствуют задаче, а кэш и защита не ломают легитимные обращения. Если хотя бы один из этих пунктов не выполнен, ошибка вернётся при следующем обновлении плагина, темы или конфигурации сервера.