Как настроить Cache-Control и ETag в WordPress для статических файлов

Если сайт на WordPress грузит одни и те же CSS, JS и изображения на каждом просмотре, проблема часто не в «тяжелой теме», а в том, как сервер отдает заголовки кэша. На практике это видно по повторным запросам к статике, лишним 304/200 в DevTools и жалобам на медленную повторную загрузку страниц у постоянных посетителей.

Задача здесь не в том, чтобы «включить кэш вообще», а в том, чтобы правильно разделить поведение для версионируемых файлов и для тех, что меняются редко. Для WordPress это особенно важно, потому что стили и скрипты часто подключаются через wp_enqueue_style() и wp_enqueue_script(), а изображения лежат в /wp-content/uploads/ и могут кэшироваться слишком агрессивно.

Как понять, что проблема именно в заголовках кэша

Сначала проверьте не абстрактную «скорость», а конкретные признаки. Откройте страницу в Chrome DevTools, вкладку Network, обновите страницу и посмотрите на колонку Size и заголовки ответа. Если CSS и JS каждый раз приходят как 200 OK с полным телом ответа, а не как 304 Not Modified, браузер не может нормально использовать кэш. Если наоборот файлы меняются, но у них слишком длинный max-age, посетитель может видеть старые стили после обновления темы или плагина.

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

curl -I https://example.com/wp-content/themes/your-theme/style.css

Смотрите на такие поля:

  • Cache-Control — сколько и как можно кэшировать;
  • ETag — идентификатор версии ресурса;
  • Last-Modified — дата последнего изменения;
  • Expires — устаревший, но иногда еще встречается;
  • Vary — может ли ответ зависеть от типа клиента или сжатия.

Если у вас уже стоит CDN или плагин кэширования, не спешите править все на сервере. Сначала выясните, кто именно выставляет заголовки: веб-сервер, PHP, плагин или прокси. Иначе можно получить конфликт правил, когда один слой говорит браузеру кэшировать год, а другой — сбрасывать кэш при каждом запросе.

Что настраивать: Cache-Control, ETag или оба сразу

Для WordPress обычно хватает двух сценариев. Первый — для версионируемых файлов, где имя меняется при обновлении: CSS и JS лучше отдавать с длинным сроком жизни, но с версией в URL. Второй — для файлов, которые могут меняться без смены имени, например некоторые изображения или файлы из загрузок, если вы их перезаписываете.

ПодходКогда подходитПлюсыМинусы
Только Cache-ControlСтатика с версией в URLПросто, предсказуемоЕсли файл меняется без смены URL, возможен устаревший кэш
Cache-Control + ETagФайлы, которые могут обновляться на том же URLБраузер может корректно перепроверять ресурсETag иногда конфликтует на кластерах и CDN
Только ETagРедко, для узких случаевРаботает как проверка версииОбычно хуже управляется, чем явный Cache-Control

Если сайт обслуживается через несколько серверов или CDN, ETag может быть источником проблем: разные узлы генерируют разные значения, и браузер перестает получать стабильный 304. В такой схеме часто разумнее полагаться на Cache-Control и версионирование файлов, а ETag отключить на уровне сервера.

Пошаговая настройка в WordPress

1. Версионируйте CSS и JS в теме и плагинах

Самый надежный способ не ловить «залипший» кэш после обновления — добавлять версию файла в URL через аргумент версии. В WordPress это штатный механизм, и он работает лучше, чем попытки вручную чистить кэш у всех посетителей.

add_action('wp_enqueue_scripts', function () {
    $theme = wp_get_theme();

    wp_enqueue_style(
        'theme-main',
        get_stylesheet_directory_uri() . '/assets/css/main.css',
        array(),
        $theme->get('Version')
    );

    wp_enqueue_script(
        'theme-main',
        get_stylesheet_directory_uri() . '/assets/js/main.js',
        array('jquery'),
        $theme->get('Version'),
        true
    );
});

Такой подход не заменяет серверный кэш, но делает обновления безопаснее: при смене версии темы браузер увидит новый URL и загрузит свежий файл.

2. Задайте Cache-Control для статических файлов на уровне сервера

Если у вас Apache, чаще всего правят .htaccess. Для Nginx логика будет в конфиге виртуального хоста, но принцип тот же: для статики — длинный срок жизни, для HTML — короткий или без агрессивного кэширования.

<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType text/css "access plus 1 month"
    ExpiresByType application/javascript "access plus 1 month"
    ExpiresByType image/jpeg "access plus 1 year"
    ExpiresByType image/png "access plus 1 year"
    ExpiresByType image/webp "access plus 1 year"
    ExpiresByType image/svg+xml "access plus 1 month"
    ExpiresByType font/woff2 "access plus 1 year"
</IfModule>

<IfModule mod_headers.c>
    <FilesMatch "\.(css|js|jpg|jpeg|png|gif|webp|svg|woff|woff2)$">
        Header set Cache-Control "public, max-age=2592000"
    </FilesMatch>
</IfModule>

Число в max-age должно соответствовать вашей схеме обновлений. Для CSS и JS месяц часто безопаснее, чем год, если вы не уверены, что всегда меняете версию файла при деплое. Для изображений можно ставить дольше, если они действительно не перезаписываются.

3. Решите, нужен ли ETag

Если сайт один, без сложной балансировки и без CDN, ETag можно оставить. Если у вас несколько серверов, прокси или CDN, проверьте, не ломает ли он кэширование. На Apache ETag иногда отключают, чтобы не было расхождений между узлами.

FileETag None

Это не универсальная рекомендация для всех, а рабочая мера, когда вы видите нестабильные 304 или разные ETag на одинаковых файлах в разных ответах. После изменения обязательно сравните заголовки с нескольких запросов и, если есть CDN, с разных точек доступа.

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

После настройки не ограничивайтесь «страница открывается». Проверьте именно поведение кэша.

  • Откройте страницу в инкогнито и посмотрите Network.
  • Обновите страницу дважды и сравните, какие ресурсы идут как 200, а какие как 304.
  • Проверьте заголовки через curl -I до и после очистки кэша.
  • Измените один CSS-файл и убедитесь, что браузер получает новый URL или новую версию ответа.
  • Если есть CDN, проверьте не только origin, но и ответ через CDN-домен.

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

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

Слишком длинный Cache-Control для файлов без версии

Если вы ставите max-age=31536000 на CSS, но не меняете URL при обновлении, старые стили будут жить у пользователей очень долго. Исправление простое: либо добавляйте версию в URL, либо уменьшайте срок кэширования.

ETag конфликтует с CDN или несколькими серверами

На одном сервере ETag может работать нормально, а на кластере — давать нестабильные ответы. Если видите, что браузер не получает ожидаемые 304, временно отключите ETag и проверьте поведение снова.

Кэшируется HTML вместо статики

Иногда правило написано слишком широко и затрагивает не только CSS/JS, но и страницы сайта. Это приводит к устаревшему контенту, проблемам с авторизацией и странному поведению форм. Ограничивайте правила расширениями файлов или отдельными путями.

Плагин кэша и серверные заголовки спорят друг с другом

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

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

Не кэшируйте вслепую все подряд. Для админки, страницы входа и пользовательских сессий кэш должен быть аккуратным или отсутствовать. Для публичной статики — наоборот, кэш нужен, но только если вы контролируете обновление файлов.

Если вы часто правите тему вручную, заведите привычку увеличивать версию ассетов при каждом деплое. Это можно делать через версию темы, хэш сборки или параметр в wp_enqueue_style(). Главное — не оставлять один и тот же URL для меняющегося файла.

Если на сайте много технических проблем с дублями, мусорными скриптами и лишними запросами, иногда проще сначала привести базовую оптимизацию в порядок, а уже потом тонко настраивать заголовки. В таких случаях полезно использовать инструменты, которые помогают чистить лишнее и управлять SEO-настройками на уровне сайта, например Clearfy Pro: https://wpshop.ru/plugins/clearfy.

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

Как настроить Redis Object Cache в WordPress и проверить, что он реально ускоряет сайт
21.09.2026
Как настроить Cache-Control и ETag в WordPress для статических файлов
24.09.2026
Как убрать дубли страниц в WordPress: canonical, noindex и пагинация без потери индексации
15.08.2026
Как отключить WP-Cron и заменить его системным cron в WordPress
07.09.2026
Как отключить emoji в WordPress и убрать лишние скрипты из head
19.08.2026