Первая версия комментариев в этом блоге печатала список прямо в HTML статьи. Чтобы одобренный комментарий появился на сайте, кэш приходилось сбрасывать — и сбрасывался он целиком, на каждый комментарий. Переделали: список приходит отдельным запросом, и комментарии больше не трогают кэш вообще.
Это восьмая часть цикла «WordPress на кэшируемом сайте».
Как было
// сброс всего кэша страниц
add_action('comment_post', 'cache_purge_all'); // новый комментарий
add_action('wp_set_comment_status', 'cache_purge_all'); // одобрили, отклонили, в корзину
Обе строки были честными: комментарий выводился в разметке статьи, значит, его появление меняло страницу. Но цена у этого такая:
- сброс на каждый новый комментарий — даже на тот, что ушёл на модерацию и на сайте не виден. Сбрасывать нечего, а кэш всего сайта уже пуст;
- второй сброс при одобрении;
- после каждого сброса — обход всего сайта заново: у нас это 138 адресов, по 15 за проход;
- пока обход идёт, страницы отдаются посетителям из PHP, медленнее обычного.
Точечная чистка одной статьи была бы дешевле, но решала бы не ту задачу. Вопрос не «что чистить», а «почему список вообще в кэшированной разметке».
Как стало
Тот же приём, что для просмотров и лайков (пятая часть): в разметке — пустое место, список приходит запросом после загрузки страницы.
<section class="blockComments" id="comments">
<h2>Комментарии <span class="count" hidden></span></h2>
<div class="commentsBody" data-post="160">
<p class="empty">// загружаю комментарии…</p>
</div>
<form class="commentForm">…</form>
</section>
add_action('wp_ajax_blog_comments', 'blog_comments_ajax');
add_action('wp_ajax_nopriv_blog_comments', 'blog_comments_ajax');
function blog_comments_ajax(): void
{
nocache_headers();
$postId = (int) ($_POST['id'] ?? 0);
if (get_post_type($postId) !== 'post' || get_post_status($postId) !== 'publish') {
wp_send_json(['ok' => false], 404);
}
// разметка одобренных комментариев (экранирование — на сервере) и их число
wp_send_json(['ok' => true] + blog_comments_render($postId));
}
await afterLoad();
const res = await wpAjax('blog_comments', { id: body.dataset.post });
body.innerHTML = res.html;
count.textContent = res.count;
count.hidden = !res.count;
// пришли по ссылке на комментарий — его не было в разметке, докручиваем сами
if (location.hash.startsWith('#comment-')) {
document.getElementById(location.hash.slice(1))?.scrollIntoView({ block: 'center' });
}
Хуки сброса на комментариях удалены. Кнопки «ответить» приходят вместе со списком, поэтому клик по ним слушается на контейнере, а не на каждой кнопке.
Проверка
- HTML статьи отдаётся из кэша (
HIT), текста комментариев в нём нет; - запрос возвращает одобренный комментарий и число
1; - в браузере список и счётчик отрисовываются, ссылка вида
#comment-3докручивает к комментарию; - снятие одобрения: страница по-прежнему
HIT, а запрос уже возвращает пустой список.
Чем заплатили
- ещё один небольшой запрос к PHP на просмотр статьи. Он не рисует страницу, а выбирает комментарии одной статьи — на фоне полного обхода сайта после каждого комментария это несравнимо дешевле;
- комментарии появляются через долю секунды после загрузки, а не вместе со страницей. Они в самом низу, до них ещё надо долистать;
- без JavaScript комментариев не видно. Поисковик, который выполняет скрипты, их увидит; для блога о разработке это приемлемо.
Одобрение теперь видно сразу — без ожидания сброса и прогрева. Раньше комментарий появлялся на сайте только после того, как обход доходил до его статьи.
Каждый комментарий или отзыв сбрасывает кэш сайта?
Пришлите адрес — вынесу их из кэшированной разметки.
// загружаю комментарии…