Как отключить REST API для гостей в WordPress без поломки админки и плагинов

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

Когда это действительно нужно

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

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

Диагностика: что именно использует REST API

Перед изменениями откройте сайт в браузере и посмотрите, какие запросы идут к /wp-json/ в DevTools. На обычной теме часто всплывают запросы от редактора, формы комментариев, плагинов аналитики и блоков с динамическим контентом. Отдельно проверьте, нет ли интеграций, которые обращаются к REST с фронтенда без авторизации.

Что проверить вручную

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

Если вы не уверены, где именно ломается запрос, временно откройте страницу с проблемным блоком и посмотрите ответы сети. Ошибка 401, 403 или пустой JSON обычно сразу показывает, что ограничение слишком жёсткое.

Пошаговое решение через PHP

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

<?php
add_filter( 'rest_authentication_errors', function( $result ) {
    if ( ! empty( $result ) ) {
        return $result;
    }

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

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

Этот код лучше добавлять в мини-плагин или в functions.php дочерней темы, а не в родительскую тему. Тогда ограничение не пропадёт после обновления оформления.

Если нужно оставить часть маршрутов открытой

Иногда полностью закрывать REST для гостей нельзя: например, публичный API нужен для списка записей, а закрыть хочется только служебные маршруты. Тогда вместо общего запрета можно проверять конкретный маршрут через rest_pre_dispatch или разрешать только нужные namespace. Это уже более тонкая настройка и требует тестирования на вашем наборе плагинов.

<?php
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' ) !== false ) {
        return $result;
    }

    return new WP_Error(
        'rest_forbidden',
        __( 'REST API закрыт для гостей.', 'textdomain' ),
        array( 'status' => 403 )
    );
} );

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

Сравнение подходов: плагин, код, сервер

ПодходПлюсыМинусыКогда выбирать
Плагин безопасностиБыстро, без кодаМожет конфликтовать с интеграциями, лишняя нагрузкаЕсли нужен быстрый старт и есть опыт тестирования плагинов
PHP-фильтрТочно, прозрачно, без внешней зависимостиНужно тестировать маршруты вручнуюЕсли нужен контроль и понятное поведение
.htaccess / nginxРежет запросы раньше WordPressЛегко сломать админку и легитимные запросыТолько если вы уверены в инфраструктуре и маршрутах

Для большинства сайтов PHP-ограничение — самый безопасный компромисс. Оно не требует трогать веб-сервер и при этом оставляет WordPress возможность вернуть 403 осмысленно, а не просто отдать пустую страницу.

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

После правки откройте /wp-json/ в режиме инкогнито. Для гостя должен вернуться отказ, а не список маршрутов. Затем войдите в админку и проверьте редактор записей: загрузку блоков, сохранение черновика, предпросмотр и работу метабоксов, если они завязаны на REST.

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

Мини-чек-лист проверки

  • гость получает 403 на /wp-json/;
  • авторизованный пользователь видит админку без ошибок;
  • редактор блоков открывается и сохраняет записи;
  • нет ошибок JavaScript на страницах с динамическими блоками;
  • внешние интеграции не потеряли доступ к нужным маршрутам.

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

Закрыли REST через .htaccess и сломали всё подряд

Жёсткая блокировка по URL часто задевает не только публичные запросы, но и внутренние вызовы WordPress. Если после правки админка начала вести себя странно, уберите серверное правило и перенесите ограничение в PHP-фильтр.

Не проверили плагины, которые используют REST

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

Оставили код в родительской теме

После обновления темы ограничение исчезнет. Для таких правок лучше использовать дочернюю тему или небольшой must-use плагин.

Сразу закрыли всё без теста в инкогнито

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

Что делать, если REST нужен только частично

Если задача не в полном закрытии, а в снижении публичности, можно оставить доступ только к конкретным маршрутам, которые реально нужны сайту. Это лучше, чем пытаться «угадать» все исключения на уровне сервера. Для сложных сайтов полезно сначала составить список используемых namespace, а уже потом решать, что закрывать.

Когда на сайте много технических плагинов, иногда проще не писать собственные исключения, а использовать проверенный инструмент для чистки и отключения лишнего. Например, Clearfy Pro у WPShop закрывает часть типовых технических хвостов и помогает убрать лишнее без ручного расползания кода: https://wpshop.ru/plugins/clearfy. Но даже в этом случае логику доступа к REST лучше проверить отдельно.

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

Ограничение REST API само по себе не заменяет защиту от брутфорса, WAF или нормальную настройку ролей. Зато оно уменьшает поверхность атаки и убирает лишние публичные ответы, которые не нужны гостям. Если сайт активно использует динамические блоки, сначала замерьте поведение на staging, а уже потом переносите правку на боевой сервер.

И ещё один момент: не храните такие изменения в случайном сниппет-плагине без контроля версий. Для технических правок на WordPress лучше иметь либо мини-плагин в репозитории, либо хотя бы отдельный файл с понятной историей изменений. Тогда при конфликте с обновлением плагина вы быстро поймёте, где искать причину.

⭐⭐⭐⭐⭐