Как ограничить REST API WordPress для неавторизованных запросов

REST API в WordPress часто оставляют открытым «как есть», а потом удивляются лишним запросам к /wp-json/, утечке служебных данных и шуму в логах. Полностью отключать API обычно плохая идея: редактор блоков, мобильные клиенты, некоторые плагины и интеграции на нём завязаны. Рабочий подход другой — ограничить доступ для гостей и оставить только то, что реально нужно.

Когда проблема уже видна в логах и в поведении сайта

Симптомы обычно повторяются:

  • в логах веб-сервера много запросов к /wp-json/wp/v2/users и похожим маршрутам;
  • боты собирают список пользователей и структуры контента;
  • плагины кэширования или защиты начинают конфликтовать с REST-запросами;
  • часть публичных эндпоинтов нужна, но доступ к служебным маршрутам лучше закрыть.

Перед правками полезно понять, что именно открыто. Проверьте несколько адресов вручную или через curl:

curl -i https://example.com/wp-json/wp/v2/users
curl -i https://example.com/wp-json/wp/v2/posts
curl -i https://example.com/wp-json/

Если первый запрос отдает список пользователей или хотя бы метаданные, это уже повод ограничить доступ. Если в ответе есть 200 OK там, где вы ожидали запрет для гостей, значит фильтр пока не настроен.

Что именно ограничивать, а что оставить

Не стоит рубить весь REST API целиком. Для обычного сайта чаще всего достаточно закрыть только запросы без авторизации и оставить публичные маршруты, которые нужны теме, плагинам или фронтенду.

ПодходЧто делаетПлюсыМинусы
Плагин безопасностиОграничивает API через настройкиБыстро, без кодаМеньше контроля, возможны лишние блокировки
Код в теме или mu-pluginФильтрует маршруты точечноГибко, прозрачноНужно аккуратно тестировать
Полное отключение APIЛомает доступ к REST почти вездеПростоЧасто ломает редактор и интеграции

Если нужен именно точечный контроль, лучше идти через код. Так вы сами решаете, какие маршруты доступны гостям, а какие — только авторизованным пользователям.

Пошаговое решение через фильтр rest_authentication_errors

Самый практичный вариант — добавить проверку в rest_authentication_errors. Этот фильтр вызывается до выполнения маршрута, и через него можно вернуть ошибку для неавторизованных запросов.

Ниже пример, который блокирует REST API для гостей, но оставляет доступ к базовому индексу /wp-json/ и к маршрутам, которые вы явно разрешите позже. Код лучше положить в mu-plugin или в отдельный мини-плагин, а не в functions.php активной темы.

<?php
/**
 * Plugin Name: Restrict REST API for guests
 */

add_filter( 'rest_authentication_errors', function( $result ) {
    if ( true === $result || is_wp_error( $result ) ) {
        return $result;
    }

    if ( is_user_logged_in() ) {
        return $result;
    }

    $request_uri = isset( $_SERVER['REQUEST_URI'] ) ? wp_unslash( $_SERVER['REQUEST_URI'] ) : '';

    // Разрешаем только индекс REST API и публичные маршруты, если они нужны.
    $allowed_prefixes = array(
        '/wp-json/',
    );

    foreach ( $allowed_prefixes as $prefix ) {
        if ( str_starts_with( $request_uri, $prefix ) ) {
            return $result;
        }
    }

    return new WP_Error(
        'rest_forbidden',
        __( 'REST API доступен только авторизованным пользователям.', 'textdomain' ),
        array( 'status' => 401 )
    );
} );

Этот вариант грубый, но понятный. На практике его часто дорабатывают: разрешают отдельные публичные маршруты, например для формы обратной связи, поиска или фронтенд-виджета.

Как разрешить только нужные маршруты

Если у вас есть публичный эндпоинт, который должен работать без логина, добавьте его в список разрешений. Лучше проверять не весь URI, а конкретный namespace или маршрут.

<?php
add_filter( 'rest_authentication_errors', function( $result ) {
    if ( true === $result || is_wp_error( $result ) ) {
        return $result;
    }

    if ( is_user_logged_in() ) {
        return $result;
    }

    $route = isset( $_SERVER['REQUEST_URI'] ) ? wp_unslash( $_SERVER['REQUEST_URI'] ) : '';

    $public_routes = array(
        '/wp-json/',
        '/wp-json/myplugin/v1/public-form',
    );

    foreach ( $public_routes as $allowed ) {
        if ( str_starts_with( $route, $allowed ) ) {
            return $result;
        }
    }

    return new WP_Error( 'rest_forbidden', 'Forbidden', array( 'status' => 401 ) );
} );

Если нужен более строгий контроль, можно идти не через URI, а через список namespace в отдельной проверке маршрутов. Но для большинства сайтов этого уже достаточно.

Более безопасный вариант: блокировать только чувствительные маршруты

Если вам не нравится идея закрывать весь REST API для гостей, ограничьте только конкретные маршруты. Это полезно, когда сайт активно использует публичные REST-запросы, но вы хотите убрать утечку пользователей и служебных данных.

<?php
add_filter( 'rest_endpoints', function( $endpoints ) {
    if ( is_user_logged_in() ) {
        return $endpoints;
    }

    $blocked = array(
        '/wp/v2/users',
        '/wp/v2/users/(?P<id>[\d]+)',
    );

    foreach ( $blocked as $route ) {
        if ( isset( $endpoints[ $route ] ) ) {
            unset( $endpoints[ $route ] );
        }
    }

    return $endpoints;
} );

Этот способ точечный, но у него есть минус: если плагин или тема используют тот же маршрут для фронтенд-функции, вы получите побочный эффект. Поэтому после внедрения обязательно проверяйте реальные сценарии сайта, а не только главную страницу.

Проверка результата после внедрения

После правки проверьте три вещи: доступ гостя, доступ авторизованного пользователя и работу нужных интеграций.

  • Откройте /wp-json/wp/v2/users в браузере в режиме инкогнито — должен быть отказ или пустой ответ, если вы так задумали.
  • Войдите в админку и повторите запрос — для администратора маршрут может оставаться доступным, если это нужно.
  • Проверьте редактор блоков, отправку форм, поиск, AJAX-виджеты и другие места, где REST API используется косвенно.
  • Посмотрите логи сервера и убедитесь, что массовые запросы к запрещённым маршрутам больше не проходят дальше WordPress.

Для быстрой проверки статуса удобно использовать curl:

curl -I https://example.com/wp-json/wp/v2/users
curl -I https://example.com/wp-json/myplugin/v1/public-form

Если первый маршрут закрыт, а второй работает как задумано, настройка выполнена правильно.

Частые ошибки и как их исправить

Сломали редактор блоков

Причина обычно в слишком жёстком запрете всего REST API. Gutenberg и часть админских интерфейсов используют REST-запросы для загрузки данных. Решение — не отключать API целиком, а ограничивать только гостевые запросы или отдельные маршруты.

Проверяете не тот уровень доступа

Иногда код смотрит только на is_user_logged_in(), а на сайте есть внешняя интеграция с application passwords, OAuth или отдельным сервисным пользователем. В таком случае логика должна учитывать реальную схему авторизации, а не только обычную сессию WordPress.

Используете functions.php и теряете защиту после смены темы

Для такой настройки лучше использовать mu-plugin или отдельный плагин. Тогда правило не исчезнет после обновления или замены темы.

Блокируете маршруты по слишком общему совпадению

Если вы сравниваете URI слишком грубо, можно случайно задеть нужный endpoint. Лучше проверять точный префикс или конкретный маршрут и держать список разрешений коротким и понятным.

Чек-лист перед публикацией на боевом сайте

  • Сделали резервную копию файлов и базы.
  • Проверили, какие REST-маршруты реально используются темой и плагинами.
  • Добавили код в mu-plugin или отдельный плагин.
  • Протестировали гостевой и авторизованный доступ.
  • Проверили редактор, формы, поиск и другие фронтенд-интеграции.
  • Убедились, что в логах нет новых ошибок после изменения.

Что ещё можно усилить без лишнего риска

Если задача не только в REST API, но и в общей технической гигиене сайта, полезно дополнительно закрыть лишние точки входа, настроить кэширование и убрать дубли в индексации. Для сайтов, где много технического мусора и SEO-дублей, иногда удобнее часть задач закрывать через специализированные плагины вроде Clearfy Pro, но только если вы понимаете, какие опции включаете и зачем.

Главная идея простая: не отключать REST API наугад, а ограничивать его по сценарию. Тогда сайт остаётся рабочим, а лишние запросы и утечки данных уходят без побочных поломок.

Как синхронизировать заказы WooCommerce со сторонними складскими системами
22.04.2026
Синхронизация и отслеживание изменений в постах WordPress с помощью hooks и webhook
13.01.2026
Как использовать REST API для синхронизации пользователей WooCommerce между сайтами
28.07.2026
Использование REST API для синхронизации пользователей и ролей WooCommerce между сайтами WordPress
23.05.2026
WooCommerce: как реализовать отмену и возврат заказов с собственной логикой
15.07.2026