REST API в WordPress часто оставляют открытым по умолчанию, а потом удивляются лишним запросам, утечке служебных данных или конфликтам с плагинами безопасности. Полностью отключать API обычно не нужно: это ломает редактор блоков, мобильные приложения, интеграции и часть фронтенд-логики. На практике задача почти всегда звучит иначе: как ограничить доступ к REST API для гостей, но не сломать рабочие сценарии.
Ниже — рабочий подход: сначала понять, что именно у вас сейчас открыто, затем закрыть лишнее точечно, проверить результат и не наступить на типовые ошибки.
Когда REST API действительно нужно ограничивать
Не каждый сайт нуждается в жестком закрытии API. Но если у вас есть хотя бы один из этих сценариев, проверка точно не будет лишней:
- в логах видны частые запросы к
/wp-json/от ботов; - плагин безопасности ругается на публичные эндпоинты;
- на сайте есть кастомные endpoints, которые отдают лишние данные;
- нужно скрыть служебные маршруты от неавторизованных посетителей;
- есть риск, что сторонний код использует REST API без проверки прав.
Важно не путать защиту REST API с закрытием всего сайта. Если вы просто запретите все запросы, редактор блоков, AJAX-интеграции и некоторые плагины начнут вести себя непредсказуемо. Поэтому сначала нужна диагностика.
Диагностика: что именно открыто сейчас
Начните с проверки базового ответа API. Откройте в браузере или через curl адрес /wp-json/. Если сайт публичный, вы увидите список маршрутов и namespace'ов. Это нормально для стандартного WordPress, но именно здесь видно, какие плагины добавили свои endpoints.
curl -I https://example.com/wp-json/Если вы хотите понять, как API отвечает для гостей и для авторизованных пользователей, проверьте оба сценария отдельно. Для гостя достаточно обычного запроса. Для авторизованного пользователя тестируйте через браузер с активной сессией или через инструмент, который умеет передавать cookies.
Что смотреть в ответе:
- код ответа:
200,401,403или404; - есть ли в JSON маршруты, которые не должны быть публичными;
- не отдает ли endpoint персональные или технические данные;
- не ломается ли редактор блоков после ограничений.
Какие маршруты обычно нельзя закрывать полностью
Если у вас используется Gutenberg, часть REST API нужна редактору для работы с постами, блоками, автосохранением и медиа. Также многие плагины используют API для своих настроек, форм, фильтров и интеграций. Поэтому задача не в том, чтобы «убить» /wp-json/, а в том, чтобы ограничить доступ к нежелательным маршрутам.
Рабочие способы ограничить REST API
Есть три практических подхода: плагин, код в теме или mu-plugin, и серверный уровень. Для большинства сайтов самый предсказуемый вариант — небольшой кодовый фильтр. Он проще в сопровождении и не зависит от лишней логики стороннего плагина.
| Способ | Плюсы | Минусы | Когда выбирать |
|---|---|---|---|
| Плагин безопасности | Быстро, без кода | Может закрыть лишнее или конфликтовать | Если нужен быстрый старт и есть понятные настройки |
Код через rest_authentication_errors | Точно контролируете логику | Нужно тестировать | Если нужен точечный доступ для гостей |
| Серверные правила | Снимают нагрузку до PHP | Сложнее поддерживать, легко ошибиться | Если есть опыт с nginx/apache и понятный набор маршрутов |
Вариант 1. Ограничить REST API для гостей через код
Самый практичный способ — разрешить API только авторизованным пользователям, но оставить исключения для нужных маршрутов. Например, можно не трогать публичные endpoints, которые реально нужны фронтенду, и закрыть все остальное.
<?php
add_filter('rest_authentication_errors', function ($result) {
if (!empty($result)) {
return $result;
}
if (is_user_logged_in()) {
return $result;
}
$request_uri = isset($_SERVER['REQUEST_URI']) ? wp_unslash($_SERVER['REQUEST_URI']) : '';
// Разрешаем только нужные публичные маршруты.
$allowed_prefixes = array(
'/wp-json/wp/v2/posts',
'/wp-json/wp/v2/pages',
'/wp-json/oembed/1.0',
);
foreach ($allowed_prefixes as $prefix) {
if (strpos($request_uri, $prefix) === 0) {
return $result;
}
}
return new WP_Error(
'rest_forbidden',
__('REST API доступен только авторизованным пользователям.', 'textdomain'),
array('status' => 401)
);
});Этот вариант подходит, если вам нужно закрыть API для гостей, но оставить отдельные публичные маршруты. Важно: проверяйте не только главную страницу API, но и конкретные endpoints, которые используют плагины.
Вариант 2. Закрыть только служебные маршруты
Иногда не нужно ограничивать весь API. Достаточно убрать доступ к конкретным namespace'ам, которые добавляет плагин или кастомная тема. Тогда можно фильтровать запросы по префиксу и возвращать 403 только для нежелательных путей.
<?php
add_filter('rest_pre_dispatch', function ($result, $server, $request) {
if (is_user_logged_in()) {
return $result;
}
$route = $request->get_route();
if (strpos($route, '/my-plugin/v1/') === 0) {
return new WP_Error(
'rest_forbidden_route',
__('Этот endpoint недоступен для гостей.', 'textdomain'),
array('status' => 403)
);
}
return $result;
}, 10, 3);Такой подход удобен, когда вы знаете, какой именно endpoint надо спрятать. Он не ломает весь API и позволяет сохранить рабочие интеграции.
Вариант 3. Скрыть REST API на уровне сервера
Если задача — снизить нагрузку от ботов, можно отрезать часть запросов на уровне nginx или Apache. Но это уже не универсальное решение: серверные правила легко задеть редактор, мобильное приложение или интеграцию, если не учесть исключения. Поэтому такой способ имеет смысл только при четком понимании, какие маршруты реально нужны.
Для большинства сайтов код в WordPress безопаснее и проще в сопровождении, чем жесткая блокировка на сервере.
Пошаговая настройка без лишнего риска
- Сделайте резервную копию файлов и базы.
- Проверьте, какие плагины используют REST API.
- Решите, что именно нужно оставить публичным: записи, страницы, oEmbed, формы, поиск.
- Добавьте ограничение в mu-plugin или в дочернюю тему, а не в основной плагин, который может обновляться.
- Протестируйте сайт в режиме гостя и под администратором.
- Проверьте редактор блоков, формы, поиск, фильтры и любые виджеты, которые тянут данные через API.
Если вы не хотите править тему, удобнее сделать маленький mu-plugin. Он не зависит от активации темы и не потеряется после обновления.
<?php
/**
* Plugin Name: REST API Access Control
*/
add_filter('rest_authentication_errors', function ($result) {
if (!empty($result) || is_user_logged_in()) {
return $result;
}
$uri = isset($_SERVER['REQUEST_URI']) ? wp_unslash($_SERVER['REQUEST_URI']) : '';
if (strpos($uri, '/wp-json/wp/v2/posts') === 0) {
return $result;
}
return new WP_Error('rest_forbidden', 'REST API закрыт для гостей.', array('status' => 401));
});Как проверить, что ограничение сработало
Проверка должна быть не формальной, а по сценариям. Сначала откройте API в приватном окне браузера. Затем проверьте тот же endpoint под администратором. Если вы закрывали только часть маршрутов, убедитесь, что разрешенные адреса продолжают отвечать нормально.