Кэш Kadence Performance: htaccess, слэши, прогрев по крону — как настроить идеально на хостинге и облачном сервере
Почему прогрев кэша в Solid Performance (Kadence) часто останавливается на одной странице, чем он отличается от WP Rocket и LiteSpeed, и какие команды поставить в крон хостинга, чтобы кэш обновлялся каждую ночь и первый посетитель не ждал сборку страницы.

Вы включили кэш в Kadence Performance (бывший Solid Performance), сбросили его — и следующий посетитель ждёт страницу 2–3 секунды вместо 0,3. Потом включили режим htaccess, чтобы стало ещё быстрее, — и вдруг адреса без слэша на конце перестали перебрасывать на правильный адрес, а после неудачной правки .htaccess сайт вообще ушёл в бесконечную переадресацию. Всё это мы прошли на трёх реальных сайтах: одном на облачном сервере с nginx и двух на обычном хостинге Beget с Apache. Ниже — актуальная рабочая схема и все подводные камни.
Как должен работать кэш: эталон
Проверять лучше не ощущения «вроде быстро», а конкретные ответы сервера. Идеальное состояние выглядит так:
| Запрос | Правильный ответ |
|---|---|
/uslugi | 301 — переадресация на /uslugi/ |
/uslugi/ | 200, x-cache: HIT, content-encoding: gzip, 0,2–0,5 с с первого захода |
sitemap_index.xml, картинки, CSS, JS | отдаются как обычно, правила кэша и слэшей их не трогают |
| Карта сайта и canonical | только адреса со слэшем |
| В кэше | только версии страниц со слэшем, по одной сжатой копии на страницу |
Если хотя бы один пункт не совпадает — настройка не завершена, даже если сайт «вроде летает».
Три вещи, которые нельзя путать
Большая часть путаницы возникает, когда в одну кучу сваливают три независимых механизма:
- Метод отдачи кэша (php или htaccess) — кто отдаёт уже готовую страницу: PHP-скрипт плагина или сам веб-сервер Apache. Влияет на скорость отдачи и на то, кто обрабатывает переадресации.
- Прогрев (preload) — кто заранее открывает страницы, чтобы они легли в кэш. Без прогрева кэш наполняется только посетителями, и первый из них ждёт.
- Переадресация со слэшем — правило «адрес без слэша → на адрес со слэшем». В режиме php его делает WordPress, в режиме htaccess — его нужно явно прописать в
.htaccess.
Переключение метода php ↔ htaccess очищает кэш. Поэтому после переключения кажется, что «всё сломалось»: на самом деле кэш просто пуст и его надо прогреть заново.
Облачный сервер (nginx) и обычный хостинг (Apache): в чём разница
| Облачный сервер с nginx (FASTPANEL и т. п.) | Обычный хостинг Beget (Apache) | |
|---|---|---|
| Метод кэша | php — единственный вариант | htaccess — рекомендуется |
| Почему | .htaccess nginx не читает вообще | Apache выполняет .htaccess и отдаёт кэш без запуска PHP |
| Переадресация без слэша | делает WordPress сам, ничего добавлять не надо | нужен свой блок в .htaccess (ниже) |
| WP-CLI | часто нет | есть |
| Прогрев | curl по вложенным картам из крона (или кнопка Preload с расширением) | curl по вложенным картам из крона |
Важный нюанс Beget: перед Apache там стоит nginx, который первым принимает запросы. Но кэш-правила плагина и ваши правила в .htaccess всё равно выполняет Apache — это видно по заголовку x-cached-by: Kadence Performance (htaccess).
Режим htaccess: главная ловушка со слэшем
В режиме php каждый запрос проходит через плагин: он видит, что адрес /uslugi без слэша, и отдаёт управление WordPress, а тот делает штатный 301 на /uslugi/.
В режиме htaccess всё иначе. Плагин прописывает в .htaccess правила, по которым Apache сам ищет готовый файл страницы в папке кэша. Для /uslugi и /uslugi/ он находит один и тот же файл и отдаёт его с кодом 200. WordPress не запускается — значит, и 301 никто не делает. Исключение [^/]$ в Cache Exclusions тут не помогает: оно работает только внутри PHP, до которого запрос уже не доходит.
Дублей в кэше при этом нет, а при правильном canonical поисковики видят только адрес со слэшем. Но идеально — когда адрес без слэша отдаёт 301. Для этого нужен свой блок в .htaccess, который срабатывает раньше правил кэша.
Правильный блок для .htaccess
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_METHOD} GET
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !/$
RewriteCond %{REQUEST_URI} !\.[a-zA-Z0-9]{1,5}$
RewriteCond %{REQUEST_URI} !^/(wp-admin|wp-json|wp-content|wp-includes)
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1/ [R=301,L]
</IfModule> Что делает каждая строка:
REQUEST_METHOD GET— трогаем только обычные открытия страниц, формы и POST-запросы не ломаем;!-fи!-d— не трогаем реальные файлы и папки;!/$— самая важная строка: адрес уже кончается слэшем — ничего не делаем;!\.[a-zA-Z0-9]{1,5}$— не трогаем адреса с расширением:.xml,.css,.jpg,.php;wp-admin|wp-json|wp-content|wp-includes— не трогаем админку, REST API и служебные папки;R=301,L— постоянная переадресация, дальше правила не обрабатываются.
Ошибка, которая кладёт сайт: бесконечная переадресация
Если при вставке потерять строку RewriteCond %{REQUEST_URI} !/$, правило начинает добавлять слэш ко всем адресам подряд: / → //, /statya/ → /statya// и так по кругу. Браузер показывает «слишком много переадресаций», в кэше — 0 страниц, потому что WordPress до страниц не доходит. Ровно так у нас и было: плагин показывал «0 pages cached», хотя кэш был включён.
Лечение — вернуть недостающую строку или временно удалить блок целиком, сайт оживает мгновенно.
Куда вставлять и как не потерять изменения
- Сначала сделайте копию:
.htaccess→.htaccess_исходник. - Вставляйте блок в самый верх файла, выше
# BEGIN KadencePerformance(или# BEGIN Solid Performance) и выше# BEGIN WordPress. Rewrite-правила выполняются сверху вниз, и переадресация должна успеть раньше, чем Apache найдёт файл в кэше. - Не вставляйте блок внутрь блоков
# BEGIN … # END: плагины переписывают их при сохранении настроек, и ваши строки пропадут. Всё, что снаружи, они не трогают. - Если файловый менеджер не даёт сохранить — посмотрите владельца и права. Права
744и чужой владелец — только чтение. Временно поставьте766, сохраните и верните644. - Сохранение проверяйте по статусу в редакторе: «ИЗМЕНЁН» внизу означает, что файл ещё не записан.
Прогрев: почему кнопка Preload и wp solid perf preload находят 3–4 адреса
Плагин берёт адреса из карты сайта. Если карта — «оглавление» (SEOPress, Yoast, Rank Math отдают sitemaps.xml со ссылками на post-sitemap1.xml, page-sitemap1.xml и т. д.), плагин видит только эти 3–4 ссылки на вложенные карты и прогревает их, а не страницы. В логе это выглядит так:
Preparing to preload uncached pages: Found 4 crawled sitemap URLs. Прогресс честно доходит до 100%, но в кэше пусто. Команда WP-CLI wp solid perf preload start ведёт себя так же — она тот же механизм, только из консоли. Поэтому на сайтах с картой-оглавлением надёжнее прогревать напрямую через curl.
Вторая ловушка: две копии кэша и заголовки curl
Плагин хранит для каждой страницы отдельные копии: сжатую (gzip) и несжатую. Браузеры всегда просят сжатую. Если прогревать голым curl без заголовка Accept-Encoding: gzip, прогреются несжатые копии, которые людям не отдаются, — и вы получите классическое «первый раз медленно, второй быстро», хотя крон вроде бы отработал. Второй обязательный заголовок — нормальный User-Agent: запросы «от робота» некоторые защитные правила режут или не кэшируют.
Рабочая команда прогрева для крона
Раз в сутки ночью (например, в 01:04). Команда сама обходит вложенные карты сайта, открывает каждую страницу так, как это делает браузер, и пишет короткий лог. Замените домен, логин и список карт на свои:
cd /home/l/ЛОГИН/example.com && { date; for m in post-sitemap1.xml page-sitemap1.xml category-sitemap1.xml; do curl -s -A "Mozilla/5.0" "https://example.com/$m" | grep -o '<loc>[^<]*' | sed 's/<loc>//'; done | while read u; do curl -s -o /dev/null -H "Accept-Encoding: gzip" -A "Mozilla/5.0 (preload)" -w "$u: %{http_code} %{time_total}s\n" "$u"; done; } > preload.log 2>&1 - Список вложенных карт возьмите из своего
sitemaps.xml: на блоге их три (записи, страницы, рубрики), на сайте с кейсами — четыре (case-sitemap1.xml). - Путь на Beget:
/home/<первая буква логина>/<логин>/<домен>. Путь чужого аккаунта в крон не подставляйте — он просто не выполнится. >перезаписывает лог при каждом запуске, он не разрастается. В файле всегда одна свежая порция: дата и по строке на страницу.- В логе у каждой строки должен быть код 200. Время 1–2 с в логе — нормально: это как раз сборка страницы в кэш, которую прогрев берёт на себя вместо посетителя.
Нужен ли сниппет-расширение для кнопки Preload
Есть фильтр solidwp/performance/preload/urls, через который можно «раскрыть» карту-оглавление, чтобы кнопка Preload видела все страницы. Правило простое: есть рабочий curl-крон — сниппет не нужен. Он имеет смысл там, где прогрев запускают кнопкой вручную: например, на облачном сервере без WP-CLI его удобно держать как страховку.
Настройки плагина: что где включить
- Basic → Enable Page Cache — включено.
- Advanced → Page Cache Method —
htaccessна Apache (Beget),phpна nginx. - Advanced → Cache Exclusions —
[^/]$не помешает (в режиме php оно не даёт кэшировать адреса без слэша), но в режиме htaccess переадресацию делает только блок из.htaccess. - Стандартные исключения — корзина, оформление заказа, личный кабинет, страницы входа — должны остаться.
- Режим после настройки больше не переключайте без нужды: каждое переключение очищает кэш.
Порядок действий: от нуля до идеала
Обычный хостинг (Apache, Beget):
- Включить Page Cache, метод — htaccess, сохранить.
- Сделать копию
.htaccessи вставить блок со слэшем в самый верх. - Нажать Purge Page Cache.
- Один раз вручную запустить curl-команду прогрева и посмотреть лог.
- Поставить эту же команду в крон на ночь.
- Проверить заголовки (ниже).
Облачный сервер (nginx):
- Включить Page Cache, метод — php (htaccess там не работает).
- В
.htaccessничего не добавлять — nginx его не читает, 301 со слэшем делает WordPress. - Purge → прогрев curl-командой (или кнопкой Preload, если стоит расширение для карты-оглавления).
- Поставить curl-прогрев в крон с
Accept-Encoding: gzipи User-Agent.
Как проверить самому
Самый быстрый способ — два запроса из терминала:
curl -sI -H "Accept-Encoding: gzip" https://example.com/uslugi/ | grep -iE "x-cache|x-cached-by|content-encoding"
curl -sI https://example.com/uslugi | grep -iE "^HTTP|location" Правильный результат:
x-cache: HIT (desktop)
x-cached-by: Kadence Performance (htaccess)
content-encoding: gzip
HTTP/1.1 301 Moved Permanently
location: https://example.com/uslugi/ Без терминала: откройте страницу в режиме инкогнито → F12 → вкладка Network → обновите страницу → кликните по первому запросу и посмотрите заголовки ответа. x-cache: MISS на первом заходе после прогрева означает, что прогрев не прошёл.
Что значат типичные симптомы
| Симптом | Причина | Что делать |
|---|---|---|
| Первый заход медленный, второй быстрый | прогрев не наполняет кэш или греет несжатые копии | curl-прогрев с Accept-Encoding: gzip |
Found 4 crawled sitemap URLs | карта сайта — оглавление | curl по вложенным картам |
| «0 pages cached», сайт не открывается | бесконечная переадресация из-за ошибки в .htaccess | вернуть строку !/$ или удалить блок |
| Адрес без слэша отдаёт 200 из кэша | режим htaccess, нет своего блока | вставить блок выше правил плагина |
| Всё «сломалось» после смены php ↔ htaccess | переключение очистило кэш | Purge и прогрев |
Не сохраняется .htaccess | владелец/права файла | временно 766, после — 644 |
Error establishing a database connection | сбой базы на стороне хостинга, кэш тут ни при чём | проверить MySQL, написать в поддержку |
Итог
Кэш работает идеально, когда соблюдены четыре условия: правильный метод под ваш сервер (htaccess на Apache, php на nginx), переадресация адресов без слэша (в режиме htaccess — своим блоком в самом верху .htaccess), прогрев по вложенным картам сайта с заголовком gzip и ежедневный запуск этого прогрева из крона. Тогда каждая страница открывается из кэша с первого захода за 0,2–0,5 секунды, адреса без слэша отдают 301, а служебные файлы и карта сайта работают как обычно.

