Кэш Kadence Performance: htaccess, слэши, прогрев по крону — как настроить идеально на хостинге и облачном сервере

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

Александр Лаврищев
Хотите сайт с воронкой продаж на WordPress?
Напишите мне в личку — обсудим вашу задачу.
Написать мне ВКонтакте

Вы включили кэш в Kadence Performance (бывший Solid Performance), сбросили его — и следующий посетитель ждёт страницу 2–3 секунды вместо 0,3. Потом включили режим htaccess, чтобы стало ещё быстрее, — и вдруг адреса без слэша на конце перестали перебрасывать на правильный адрес, а после неудачной правки .htaccess сайт вообще ушёл в бесконечную переадресацию. Всё это мы прошли на трёх реальных сайтах: одном на облачном сервере с nginx и двух на обычном хостинге Beget с Apache. Ниже — актуальная рабочая схема и все подводные камни.

Как должен работать кэш: эталон

Проверять лучше не ощущения «вроде быстро», а конкретные ответы сервера. Идеальное состояние выглядит так:

ЗапросПравильный ответ
/uslugi301 — переадресация на /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, а служебные файлы и карта сайта работают как обычно.

Александр Лаврищев
Хотите сайт с воронкой продаж на WordPress?
Напишите мне в личку — обсудим вашу задачу.
Написать мне ВКонтакте

Похожие записи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *