Почему скорость WordPress важна
Google использует скорость загрузки как фактор ранжирования. Каждые 100 мс задержки снижают конверсию на 1%. Ниже — 10 конкретных шагов.
10 способов ускорить WordPress
| # | Метод | Прирост скорости | Сложность |
|---|---|---|---|
| 1 | Кэш страниц (LiteSpeed/WP Rocket) | ★★★★★ | Низкая |
| 2 | CDN (Cloudflare / BunnyCDN) | ★★★★☆ | Низкая |
| 3 | WebP-изображения | ★★★★☆ | Низкая |
| 4 | Lazy Loading изображений | ★★★☆☆ | Низкая |
| 5 | Redis Object Cache | ★★★★★ | Средняя |
| 6 | Минификация CSS/JS | ★★★☆☆ | Низкая |
| 7 | Отложенный JS (defer) | ★★★☆☆ | Низкая |
| 8 | Оптимизация БД (WP-Sweep) | ★★☆☆☆ | Низкая |
| 9 | PHP 8.2 + OPcache | ★★★★☆ | Средняя |
| 10 | GZIP/Brotli сжатие | ★★★☆☆ | Низкая |
Включение OPcache в php.ini
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.revalidate_freq=0
opcache.validate_timestamps=0 ; только для production!
GZIP в Nginx
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml;
gzip_min_length 256;
gzip_comp_level 6;
Разбор типичных ошибок при ускорении
При включении агрессивного кэша и оптимизации PHP сайт иногда не ускоряется, а падает. Разберём, что означают конкретные тексты ошибок и как их устранить.
| Текст ошибки или симптом | Причина | Что делать |
|---|---|---|
Белый экран после смены opcache.validate_timestamps=0 | OPcache держит в памяти байт-код старой версии файлов и не видит новый деплой | После каждого деплоя вызывать opcache_reset() или перезапускать php-fpm |
| There has been a critical error on this website | Минификатор JS склеил несовместимые между собой скрипты темы и кэш-плагина | Отключить минификацию JS точечно для конфликтующего файла и проверить debug.log |
| Error establishing a database connection после включения объектного кэша | Расширение Redis или Memcached недоступно на PHP-FPM, а не сама база данных упала | Проверить php -m | grep redis и статус systemctl status redis-server |
| Вёрстка «прыгает» после Lazy Loading | Браузер не резервирует место под изображение без атрибутов width и height | Задать реальные width и height у тегов img, а не только CSS-размеры |
Подробнее о настройке самого Redis для WordPress — в статье про объектный кэш Redis.
Ограничения: когда кэш и CDN не помогут
Ускорение через кэш работает не для всех типов страниц и не на любом тарифе хостинга.
- Страницы с персональным контентом — личный кабинет, корзина, форма заказа — нельзя кэшировать целиком: каждый пользователь увидит чужие данные
- На тарифах с жёстким лимитом CPU (большинство shared-хостингов) объектный кэш Redis подключить нельзя — там нет доступа к systemd и собственным сервисам
- Если сайт получает меньше 100 посетителей в сутки, настройка CDN не окупает потраченное время — узкое место обычно в самом коде, а не в доставке статики
- Сайты с активными WebSocket-соединениями или long-polling через AJAX не ускоряются кэшем страниц, потому что каждый запрос уникален
- Тяжёлые PDF-каталоги и генераторы отчётов на лету всё равно упрутся в CPU при первом обращении, кэш лишь скрывает проблему для повторных визитов
Прежде чем включать сразу все десять способов, замерьте baseline: без базовой метрики TTFB и Core Web Vitals невозможно доказать, что конкретное изменение действительно дало эффект, а не совпало с менее загруженным временем суток на хостинге.
Приоритет ресурсов и Critical CSS
После базовых 10 шагов следующий уровень — вынести критические стили в head, а остальной CSS загружать асинхронно. Это напрямую влияет на Largest Contentful Paint.
<!-- В head: инлайн критических стилей -->
<style>/* только стили для первого экрана */</style>
<!-- Остальной CSS — асинхронно -->
<link rel="preload" href="/wp-content/themes/mytheme/style.css" as="style" onload="this.rel='stylesheet'">
Как проверить, что оптимизация сработала
Числа в PageSpeed Insights колеблются от прогона к прогону, поэтому проверяйте сразу несколькими способами.
# Проверить время до первого байта
curl -o /dev/null -s -w 'TTFB: %{time_starttransfer}s\nTotal: %{time_total}s\n' https://example.com/
# Проверить, что отдаётся сжатие
curl -sI -H 'Accept-Encoding: gzip, br' https://example.com/ | grep -i content-encoding
- Content-Encoding в ответе — br или gzip, иначе сжатие не применилось
- Заголовок X-Cache: HIT или аналог плагина кэша на втором запросе к той же странице
- PageSpeed Insights: Largest Contentful Paint ниже 2.5 секунды на мобильном
- GTmetrix: TTFB ниже 200 мс на хостинге с NVMe и PHP OPcache
Если после всех шагов PHP всё ещё узкое место — проверьте настройки OPcache для PHP, а сжатие на уровне веб-сервера — в статье про GZIP и Brotli.
Частые вопросы
Можно ли кэшировать страницы корзины и личного кабинета в WooCommerce?
Нет, страницы с персональным содержимым — корзину, личный кабинет, оформление заказа — нельзя кэшировать как обычные статичные страницы: один пользователь увидит данные другого. Плагины кэширования обычно исключают такие URL автоматически по умолчанию, но стоит проверить настройки вручную и убедиться, что динамические разделы магазина действительно помечены как исключения в правилах кэша.
Почему сайт может показать белый экран именно после отключения opcache.validate_timestamps?
При выключенном validate_timestamps OPcache перестаёт сверять файлы с диском и держит в памяти байт-код старой версии кода даже после деплоя новых файлов. Если новый код не совместим со старым закэшированным состоянием, сервер отдаёт ошибку вместо страницы. Решение — вызывать сброс кэша или перезапускать PHP-FPM сразу после каждого обновления файлов на продакшене.
Стоит ли настраивать CDN или Redis для сайта с очень небольшим количеством посетителей?
Для сайта с совсем небольшим количеством посетителей в сутки настройка CDN обычно не окупает потраченное время — узкое место чаще находится в самом коде, а не в доставке статики по сети. Redis тоже не всегда доступен: на тарифах с жёстким лимитом процессора объектный кэш просто негде развернуть, поскольку нет доступа к собственным фоновым сервисам.
Почему вёрстка может «прыгать» после включения Lazy Loading у изображений?
Браузер резервирует место под картинку заранее только если у тега img заданы явные атрибуты width и height. Если указаны лишь CSS-размеры или атрибуты вовсе отсутствуют, до момента фактической загрузки изображения браузер не знает его пропорций, и соседний контент сдвигается сразу после подгрузки — это и ощущается как внезапный «прыжок» вёрстки.