Если в WordPress сайт обновляется, а браузер у части пользователей продолжает тянуть старые CSS или JS, проблема часто не в теме и не в плагине кеша, а в заголовках ответа. Для статических файлов важны два механизма: Cache-Control и ETag. Первый задаёт срок и правила кеширования, второй помогает браузеру понять, изменился ли файл на сервере.
На практике задача обычно звучит так: после правок в стилях изменения видны только после принудительной перезагрузки, а на мобильных устройствах или через CDN старые файлы держатся дольше, чем нужно. Ниже разберём, как это диагностировать и как настроить заголовки без лишнего риска.
Когда проблема действительно в Cache-Control и ETag
Не каждый «не обновился сайт» связан с кешем браузера. Сначала стоит проверить, что именно отдаёт сервер. Если HTML уже новый, а style.css или app.js — старые, тогда заголовки имеют значение. Если же не меняется сам HTML, искать нужно в плагине кеша, серверном кеше или CDN.
Быстрая диагностика в браузере и через curl
Откройте DevTools → Network, выберите CSS или JS-файл и посмотрите заголовки ответа. Вас интересуют:
Cache-Control— как долго и где можно кешировать файл;ETag— идентификатор версии ресурса;Last-Modified— дата последнего изменения;Age— сколько объект уже живёт в кеше;CF-Cache-Statusили аналогичный заголовок CDN, если он используется.
Проверка через консоль обычно быстрее:
curl -I https://example.com/wp-content/themes/your-theme/style.cssЕсли ответ содержит слишком короткий срок кеширования для статических файлов или, наоборот, агрессивный кеш без версии файла, это и есть источник проблемы.
Что лучше: править сервер, плагин или тему
Для WordPress есть три рабочих пути. Выбор зависит от того, есть ли у вас доступ к конфигу сервера и как устроен хостинг.
| Подход | Когда подходит | Плюсы | Минусы |
|---|---|---|---|
| Конфиг сервера | Есть доступ к Apache/Nginx | Надёжно, быстро, без лишнего PHP | Нужны права на сервер |
| Плагин кеша | Нет доступа к конфигу | Можно настроить из админки | Не всегда даёт точный контроль |
| Код в теме/му-плагине | Нужна точечная логика | Гибко, можно учесть типы файлов | Нужно аккуратно тестировать |
Если есть доступ к серверу, лучше настраивать заголовки там. Если нет — используйте плагин кеша или небольшой mu-plugin. В саму тему лезть не стоит, если настройка должна жить дольше одного редизайна.
Пошаговая настройка Cache-Control для статических файлов
Для CSS, JS, шрифтов и изображений обычно нужен длительный кеш, но с учётом версии файла в URL. WordPress как раз умеет добавлять версию к стилям и скриптам, а для медиафайлов это часто делает CDN или сам сервер.
Вариант для Apache через .htaccess
Если сайт работает на Apache и модуль mod_headers включён, можно задать заголовки для статических ресурсов прямо в .htaccess:
<IfModule mod_headers.c>
<FilesMatch "\.(css|js|jpg|jpeg|png|gif|webp|svg|woff|woff2)$">
Header set Cache-Control "public, max-age=31536000, immutable"
</FilesMatch>
</IfModule>Здесь immutable уместен только если вы действительно меняете имя файла или версию при каждом обновлении. Для CSS и JS в WordPress это обычно безопасно, если вы не отключали версионирование.
Вариант для Nginx
На Nginx настройка делается в конфиге сайта:
location ~* \.(css|js|jpg|jpeg|png|gif|webp|svg|woff|woff2)$ {
expires 365d;
add_header Cache-Control "public, max-age=31536000, immutable" always;
}Если у вас уже есть CDN, не дублируйте слишком агрессивные правила на всех уровнях сразу. Иначе можно получить ситуацию, когда CDN держит старую версию дольше, чем браузер.
Как работать с ETag в WordPress и на сервере
ETag полезен, когда сервер должен быстро понять, изменился ли файл. Но в связке с CDN и несколькими веб-серверами он иногда создаёт лишние проверки или конфликтует с другими механизмами кеширования. Поэтому ETag не всегда нужен.
Когда ETag стоит оставить
- сайт обслуживается одним сервером;
- нет сложной CDN-цепочки;
- нужна точная валидация изменений без лишней логики;
- вы не хотите полагаться только на
Last-Modified.
Когда ETag лучше отключить
- фронт отдается через несколько серверов или балансировщик;
- используется CDN, который сам управляет кешем;
- ETag меняется из-за inode или внутренней структуры сервера, хотя файл не менялся;
- вы видите постоянные 200 вместо 304 без понятной причины.
На Apache ETag обычно отключают на уровне конфигурации сервера, а не WordPress. На Nginx поведение зависит от сборки и общей конфигурации, поэтому здесь лучше смотреть именно серверные настройки, а не пытаться лечить это PHP-кодом.
Если доступа к серверу нет: настройка через код
Иногда хостинг не даёт трогать конфиги, а плагин кеша не решает задачу точечно. Тогда можно добавить заголовки через mu-plugin. Это удобнее, чем править тему, потому что код не пропадёт после обновления шаблона.
<?php
/**
* Plugin Name: Static Cache Headers
*/
add_action('send_headers', function () {
if (is_admin()) {
return;
}
if (!isset($_SERVER['REQUEST_URI'])) {
return;
}
$uri = wp_unslash($_SERVER['REQUEST_URI']);
if (preg_match('~\.(css|js|jpg|jpeg|png|gif|webp|svg|woff|woff2)$~i', $uri)) {
header('Cache-Control: public, max-age=31536000, immutable');
}
});Этот вариант полезен только как запасной. Он не заменяет серверную настройку, потому что WordPress подключается уже после веб-сервера, а значит не всегда может повлиять на все ответы одинаково. Но для части хостингов этого достаточно.
Проверка результата после внедрения
После настройки не ограничивайтесь визуальной проверкой страницы. Нужно убедиться, что заголовки реально изменились и браузер начал использовать кеш правильно.
- Откройте CSS или JS-файл в Network и посмотрите
Cache-Control. - Обновите страницу обычной перезагрузкой и затем
Hard Reload. - Сравните ответ до и после изменения файла.
- Проверьте, что при повторном запросе сервер отдаёт
304 Not Modified, если ресурс не менялся. - Если есть CDN, проверьте заголовки и на уровне CDN, и на уровне origin-сервера.
Полезная проверка через curl выглядит так:
curl -I https://example.com/wp-content/themes/your-theme/style.css
curl -I -H "If-None-Match: \"test\"" https://example.com/wp-content/themes/your-theme/style.cssЕсли после изменения файла URL остаётся тем же, а браузер продолжает показывать старую версию, значит проблема не в заголовках, а в отсутствии версионирования файла или в слишком агрессивном кеше промежуточного слоя.
Частые ошибки и как их исправить
Ставят длинный кеш на HTML вместо статических файлов
Это самая неприятная ошибка. HTML должен обновляться быстро, а вот CSS и JS можно кешировать дольше. Если вы зададите одинаковые правила для всего сайта, пользователи будут видеть старые страницы даже после публикации изменений.
Отключают ETag, но не меняют версию файлов
Если вы убрали ETag, но CSS и JS подключаются без версии, браузеру не на что ориентироваться. В таком случае после обновления темы старый файл может остаться в кеше до истечения срока max-age.
Дублируют правила в плагине, .htaccess и CDN
Когда одна и та же логика прописана в трёх местах, отладка превращается в угадайку. Сначала определите главный уровень управления кешем: сервер, CDN или плагин. Остальные уровни должны только дополнять, а не спорить друг с другом.
Используют immutable без версионирования
Это рабочая практика только тогда, когда URL файла меняется при каждом изменении. Если URL постоянный, браузер может слишком долго держать старую версию.
Практические советы по безопасности и производительности
Не храните логику кеширования в теме, если сайт поддерживается несколькими людьми. Лучше вынести её в mu-plugin или на серверный уровень. Так вы не потеряете настройки при обновлении шаблона и не забудете, где именно лежит правило.
Если используете плагин оптимизации, проверьте, не переписывает ли он заголовки сам. Некоторые плагины умеют ставить собственные правила кеша для статики, и это нормально, пока они не конфликтуют с CDN и сервером.
Если нужен более широкий контроль над техническими дублями, кешем и чисткой лишних скриптов, иногда удобнее собрать это в одном инструменте, чем держать набор разрозненных решений. Для WordPress это как раз тот случай, где полезно смотреть на комплексные плагины вроде Clearfy Pro: https://wpshop.ru/plugins/clearfy.
Но даже с плагином принцип остаётся тем же: сначала понять, где именно ломается кеширование, потом менять только тот уровень, который реально отвечает за ответ файла.