Первая версия комментариев в этом блоге печатала список прямо в 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 комментариев не видно. Поисковик, который выполняет скрипты, их увидит; для блога о разработке это приемлемо.

Одобрение теперь видно сразу — без ожидания сброса и прогрева. Раньше комментарий появлялся на сайте только после того, как обход доходил до его статьи.

Каждый комментарий или отзыв сбрасывает кэш сайта?

Пришлите адрес — вынесу их из кэшированной разметки.

· полезно?
АЧ
Алексей Чикун веб-разработчик, команда TRIOHEAD

Делаю сайты и сервисы целиком: от вёрстки до сервера. Пишу о том, что проверил на своих проектах.

Комментарии

// загружаю комментарии…

Комментарии публикуются после проверки. Ссылки и HTML не принимаются.