Когда сайт ускоряют кэшем, чаще всего забывают про два источника проблем: admin-ajax.php и REST API. Внешне всё выглядит нормально, но в админке не обновляются данные, фронтенд получает устаревший JSON, а формы и фильтры начинают вести себя непредсказуемо. Обычно причина не в самом WordPress, а в том, что серверный кэш, CDN или плагин кэширования одинаково обрабатывают статические и динамические запросы.
Ниже — рабочая схема, как точечно отключить кэш для динамических эндпоинтов, не выключая его на всём сайте.
Когда проблема действительно в кэше
Сначала стоит убедиться, что вы боретесь именно с кэшированием, а не с ошибкой в JavaScript, плагине или правами доступа. Для admin-ajax.php и REST API типичные симптомы похожи:
- запрос возвращает старые данные после сохранения записи или настроек;
- в консоли браузера виден успешный ответ, но содержимое не меняется;
- один и тот же URL REST API отдаёт разные результаты в приватном окне и в обычной сессии;
- после очистки кэша проблема исчезает, а потом возвращается;
- ответы AJAX-запросов начинают зависеть от CDN или reverse proxy.
Что проверить до правок
- Откройте DevTools → Network и посмотрите заголовки ответа:
cache-control,age,x-cache,cf-cache-statusили аналоги у вашего хостинга. - Сравните ответ напрямую и через домен с CDN, если он есть.
- Проверьте, не кэширует ли запрос сам плагин оптимизации, а не сервер.
- Убедитесь, что проблема воспроизводится на чистом браузере без расширений.
Какой подход выбрать: плагин, сервер или код
Если у вас один сайт и стандартный стек, иногда достаточно настроек плагина кэширования. Но для admin-ajax.php и REST API надёжнее иметь явные правила на уровне сервера или темы/плагина. Это особенно важно, если запросы идут через CDN или если сайт использует несколько слоёв кэша.
| Подход | Когда подходит | Минус |
|---|---|---|
| Настройка плагина кэширования | Если плагин умеет исключать URL и заголовки | Зависит от конкретного плагина и его интерфейса |
| Правила на сервере/CDN | Если кэшируется HTML и API на уровне прокси | Нужен доступ к конфигу или панели CDN |
| Код в WordPress | Если нужно задать заголовки точечно | Не отменяет уже настроенный внешний кэш |
Пошаговое решение для admin-ajax.php
Для AJAX-запросов важны два момента: правильные заголовки ответа и отсутствие кэширования на внешнем уровне. Если запрос должен всегда возвращать актуальные данные, лучше явно отправлять заголовки, запрещающие хранение ответа.
1. Добавьте заголовки для AJAX-ответов
Если у вас собственный обработчик AJAX, задайте заголовки до вывода данных. Пример для wp_ajax_ и wp_ajax_nopriv_:
add_action('wp_ajax_my_dynamic_action', 'my_dynamic_action_handler');
add_action('wp_ajax_nopriv_my_dynamic_action', 'my_dynamic_action_handler');
function my_dynamic_action_handler() {
nocache_headers();
header('Content-Type: application/json; charset=' . get_option('blog_charset'));
$data = array(
'time' => current_time('mysql'),
'user' => is_user_logged_in() ? get_current_user_id() : 0,
);
wp_send_json_success($data);
}Функция nocache_headers() добавляет стандартные заголовки WordPress для запрета кэширования. Это не магия, но для многих конфигураций уже достаточно, чтобы браузер и часть промежуточных слоёв перестали хранить ответ.
2. Не кэшируйте сам endpoint на уровне прокси
Если запросы идут через Nginx, Varnish, Cloudflare или другой reverse proxy, нужно исключить /wp-admin/admin-ajax.php из кэша. Иначе WordPress может отправлять правильные заголовки, но прокси всё равно будет отдавать старый ответ.
Для Nginx логика обычно выглядит так: не хранить и не отдавать из кэша запросы к admin-ajax.php и к REST API.
location = /wp-admin/admin-ajax.php {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass php-fpm;
fastcgi_no_cache 1;
fastcgi_cache_bypass 1;
}
location ~* ^/wp-json/ {
fastcgi_no_cache 1;
fastcgi_cache_bypass 1;
}Конкретный конфиг зависит от того, как у вас подключён PHP и какой кэш используется. Смысл один: динамические запросы не должны попадать в общий HTML-кэш.
Как отключить кэш для REST API без поломки фронтенда
REST API часто ломается не полностью, а выборочно: один маршрут отдаёт актуальные данные, другой — старые. Это особенно заметно в блоках редактора, кастомных фильтрах, поиске и интерфейсах, которые подгружают контент через /wp-json/.
3. Отдавайте правильные заголовки в своих REST-маршрутах
Если вы регистрируете собственный REST endpoint, можно явно указать заголовки в callback. Пример:
add_action('rest_api_init', function () {
register_rest_route('myplugin/v1', '/stats', array(
'methods' => 'GET',
'callback' => 'myplugin_get_stats',
'permission_callback' => '__return_true',
));
});
function myplugin_get_stats(WP_REST_Request $request) {
$response = new WP_REST_Response(array(
'updated_at' => current_time('mysql'),
'posts' => wp_count_posts('post')->publish,
));
$response->header('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0');
$response->header('Pragma', 'no-cache');
$response->header('Expires', 'Wed, 11 Jan 1984 05:00:00 GMT');
return $response;
}Если маршрут публичный, но данные должны обновляться сразу после изменений, такой подход помогает избежать случайного хранения ответа в браузере или промежуточном кэше.
4. Исключите REST API из кэша плагина
У большинства кэширующих плагинов есть список исключений по URL. Туда стоит добавить как минимум:
/wp-json/;/wp-admin/admin-ajax.php;- страницы, где фронтенд зависит от динамических запросов;
- маршруты, которые возвращают персонализированные данные.
Если плагин умеет исключать только шаблоны URL, проверьте, что правило покрывает подмаршруты, а не только корень /wp-json/.
Проверка результата после внедрения
После правок важно не ограничиваться очисткой кэша. Нужно проверить, что ответ действительно перестал кэшироваться на всех уровнях.
- Откройте проблемный AJAX или REST URL в браузере и обновите страницу несколько раз.
- Сравните заголовки ответа до и после изменения.
- Проверьте, меняется ли тело ответа после изменения данных в админке.
- Если есть CDN, проверьте ответ через его панель или временно отключите проксирование для теста.
- Посмотрите, не остались ли старые данные в локальном кэше браузера.
Удобный способ проверки — сделать тестовый endpoint, который возвращает текущее время. Если ответ меняется при каждом запросе, кэш на этом пути не вмешивается.
Частые ошибки и как их исправить
Отключили кэш только в WordPress, но не на сервере
Это самая частая ситуация. WordPress отправляет nocache_headers(), но Nginx, Varnish или CDN продолжают хранить ответ. Исправление: исключить endpoint на уровне внешнего кэша.
Слишком широкое исключение
Иногда в исключения добавляют весь /wp-json/ без разбора, а потом теряют производительность там, где кэш был полезен. Лучше исключать только те маршруты, которые реально динамические.
Кэшируют POST-запросы как обычные страницы
admin-ajax.php часто работает через POST, и некоторые прокси по ошибке обрабатывают его как обычный URL. Нужно проверить правила для методов запроса, а не только для пути.
Не учитывают авторизованных пользователей
Если REST API или AJAX возвращает персональные данные, кэш для авторизованных пользователей нужно отключать особенно аккуратно. Иначе можно получить утечку чужих данных через общий ответ.
Практические советы по безопасности и производительности
Отключать кэш точечно лучше, чем глобально. Но вместе с этим стоит проверить ещё несколько вещей:
- не передавайте в публичный REST API лишние поля, если они не нужны фронтенду;
- для динамических запросов используйте nonce там, где это требуется по логике доступа;
- не храните персональные данные в ответах, которые могут попасть в общий кэш;
- если endpoint вызывается часто, оптимизируйте сам callback, а не только кэш вокруг него;
- проверяйте, не создаёт ли плагин лишние AJAX-запросы на каждой странице.
Если на сайте много технических дублей, лишних архивов и мусорных URL, имеет смысл параллельно почистить индексируемые страницы и мета-данные. Для этого иногда удобнее использовать специализированные инструменты вроде Clearfy Pro, но только если они реально закрывают вашу задачу по дублям и технической чистке, а не подменяют собой настройку кэша.
Короткий чек-лист перед выкладкой на прод
- Проверены заголовки
Cache-ControlиAgeу проблемного запроса. /wp-admin/admin-ajax.phpисключён из серверного и CDN-кэша./wp-json/исключён только там, где это действительно нужно.- Тестовый endpoint возвращает актуальные данные после изменений.
- Авторизованные и гостевые ответы не смешиваются.
- После очистки кэша проблема не возвращается при повторном запросе.
Если после всех правок ответ всё ещё кэшируется, проблема почти всегда находится вне WordPress: в конфиге прокси, CDN или в настройках хостинга. В такой ситуации быстрее всего идти от заголовков ответа и цепочки кэширования, а не от повторной установки плагинов.