Превращаем свой WordPress-сайт в статичный с помощью агрессивного страничного кэширования в Nginx

В истории веб-публикации был один странный период, который я никогда не понимал — взлет генераторов статичных сайтов.

Но постойте! Не надо мне перечислять их преимущества! Я знаю, для чего они придуманы, просто я не видел в них никакого смысла. Как и многие другие, я начал создавать свои сайты с использованием HTML, CSS и щепотки JavaScript. Мой первый сайт, размещенный на GeoCities, выглядел примерно так. Я использовал marquee для бегущей строки, таблицы для разметки, стилизацию с помощью атрибута style, а также несколько JS-функций alert.

Затем я решил обратиться к динамически генерируемому контенту (спасибо моему другу). Я открыл для себя ASP, PHP, MySQL, после чего я уже не оглядывался назад. В то время генераторы статичных сайтов казались мне чем-то сумасшедшим в плане объема работ при минимально получаемом «выхлопе». Да, я знал, что генераторы существуют, но при этом я предпочитал динамически генерируемый контент с использованием либо фреймворка, такого как CakePHP или CodeIgniter, либо CMS, такой как Drupal или WordPress.

Я знаком со многими людьми, которые пробовали генераторы статичных сайтов, такие как Jekyll, Hugo или Gatsby, но полезность данных решений для меня всегда была спорной.

Статичный WordPress или Headless WordPress – что лучше?

Прежде чем углубляться в детали, давайте поговорим о Headless WordPress. Этот термин остается неизменно популярным с 2017 года. В конце 2016 года вышел WordPress 4.7, в котором появился WP REST API. Именно API, позволяющий запрашивать данные из БД WordPress, и лежит в основе функциональности Headless. В Headless CMS используется decoupled-архитектура, позволяющая CMS работать в качестве бэкенд-сервиса, доступного по API (или SDK). В случае headless-подхода CMS предлагает только возможности редактирования контента, а интерфейс (фронтенд) обслуживается с помощью других решений. В качестве таких решений могут выступать одностраничные приложения или генераторы статичных сайтов.

Реализация Headless WordPress означает отказ от использования фронтенда WordPress-сайта. Тема WordPress, а также любые плагины, которые влияют на фронтенд, окажутся бесполезными при использовании WordPress в качестве headless CMS. Это сильно отличается от использования WP в качестве генератора статичных сайтов, ведь в таком случае в полной мере пригодятся и темы, и плагины, формирующие фронтенд сайта. Сгенерированные страницы будут сохраняться в виде HTML-файлов.

Gatsby – яркий пример headless-подхода в WordPress. Здесь плагин WP GraphQL включает GraphQL API, к которому затем обращается Gatsby для генерации статичных страниц.

Почему пользователям нравятся статичные сайты

Есть несколько причин, почему статичные сайты так популярны – вне зависимости от того, используется ли Headless-решение или более традиционный плагин генерации статичных страниц. Давайте кратко приведем их:

  1. Безопасность – главный аргумент в пользу статичных сайтов. На статичном сайте в открытом доступе есть только HTML, CSS, JavaScript, изображения и т.д. Все это статичные файлы. Нет PHP, нет базы данных. Возможные атаки существенно урезаны.
  2. Статичные сайты работают быстро и справляются с существенным потоком трафика, поскольку нет бэкенда (ни PHP, ни MySQL), который обычно обрабатывается при каждом запросе страницы.
  3. Статичные сайты никогда не сломаются, за исключением ситуаций, когда веб-сервер (Apache или Nginx), обслуживающий страницы, перестает работать.
  4. Статичные сайты дешевле размещать в сети. Вам не надо платить за дополнительные процессорные мощности для обслуживания статичных HTML-файлов.

Революция генераторов статичных сайтов

Когда веб-публикация только зародилась, создание и обслуживание статичного сайта представляло собой довольно утомительное занятие. В основном вам приходилось хранить локальные копии всех HTML-страниц сайта, и, если вам требовалось внести изменения, вам нужно было отредактировать локальную страницу, после чего залить ее на сервер. Многие веб-агентства появились именно в то время, поскольку предприятиям требовались специалисты для создания и обслуживания их сайтов.

С появлением персональных сетевых журналов (блогов) в конце 1990-х – начале 2000-х годов все больше и больше пользователей искали способы публикации своего контента без необходимости изучения HTML, CSS, основ FTP. Появились инструменты ведения блогов, такие как Blogger, Movable Type, Textpattern, b2, WordPress. Благодаря им пользователи смогли публиковать свой контент в сети, не погружаясь в технические аспекты.

Среди них Blogger и Movable Type были генераторами статичных сайтов; они генерировали статичные HTML-страницы на базе пользовательского контента. Blogger был запущен в 1999 году. Он одним из первых автоматизировал процесс публикации блога на веб-сервере. Пользователю нужно было всего лишь создать свой контент. Далее Blogger генерировал HTML-страницу и загружал ее на сервер. Двумя годами позже появился Moveable Type. Он улучшил данный процесс, добавив заголовки страниц, форматирование текста, присваивание рубрик, что сделало его самой популярной платформой для ведения блогов.

Movable Type был разработан на базе Perl, который должен был перестраивать страницу всякий раз, когда вносились изменения. Означало это следующее: если кто-то оставлял комментарий к посту, страницу нужно было собрать заново, чтобы комментарий отобразился. Ведение блогов было средой с высокой интерактивностью, люди регулярно комментировали посты других. Все эти проблемы заставили разработчиков искать другие инструменты, которые бы динамически обновляли содержимое страницы.

В конце 2000 года разработчики применяли связку PHP, Apache (веб-сервер) и MySQL (база данных) для создания CMS, таких как TextPattern, b2 и WordPress. Эти системы обслуживали как фронтенд (уровень представления), так и бэкенд (уровень содержимого) для редактирования контента. Преимущество этих инструментов заключалось в том, что владельцам сайтов больше не требовалось обновлять фронтенд всякий раз, когда публиковался комментарий или вносилось изменение.

Со временем разработчики начали расширять технологический стек. Популярность WordPress росла, люди начали создавать с помощью этой CMS не только блоги. Появились сайты с разнообразным контентом, более интерактивным функционалом, в результате чего на Apache, MySQL и PHP легла дополнительная нагрузка. При этом большинство предложений для размещения WordPress исходили от виртуальных хостингов, т.е. все веб-сайты заливались на один сервер с достаточно общей конфигурацией Apache.

С развитием WordPress интерес к этой системе вырос и у хакеров. Старые, заброшенные сайты, владельцы которых не обновляли темы, плагины и ядро, были легкой мишенью для злоумышленников, и в итоге WP получил клеймо небезопасного программного обеспечения.

Некоторые пользователи полагали, что им вообще не требуются никакие из динамических возможностей WordPress. Им просто хотелось публиковать простые HTML-страницы – без комментариев, контактных форм или другой сложной функциональности. Разработчики снова обратились к генераторам статичных сайтов. В 2008 году был выпущен Jekyll, и он зародил тренд возврата веб-разработки к статичным сайтам. В 2017 году Jekyll был одним из самых популярных генераторов статичных сайтов.

Известные проблемы с генераторами статичных сайтов

Генераторы статичных сайтов, такие как Jekyll, прекрасно подходят для простых блогов или сайтов компаний с одним автором, где контент меняется нечасто. При этом есть объективные причины, почему динамически генерируемые сайта, созданные на базе WordPress, по-прежнему популярны.

Основная проблема статичных сайтов связана с тем, что в них сложнее реализовать функциональность, обрабатывающую взаимодействие с пользователем и хранение данных. Контактные формы, интернет-магазины, сайты сообществ, форумы, системы онлайн-обучения – все это легко реализуется с помощью WordPress и связки правильных плагинов.

Если же вам нужно реализовать даже простую контактную форму на статичном сайте, все сильно усложняется. Преимущества статичного сайта быстро испаряются. Если вам нужно, чтобы кто-то еще редактировал ваш сайт, особенно человек без технических навыков, вы начинаете жалеть, что не воспользовались WordPress. Переход с генератора статичных сайтов на WordPress – процесс достаточно трудоемкий.

В настоящее время существуют CMS-сервисы, созданные на базе генераторов статичных сайтов, такие как Forestry.io, которые позволяют нескольким редакторам изменять контент статичного сайта. Однако в данном случае у нас нет никаких преимуществ перед использованием WordPress и плагина для генерации статичных страниц. В реальности все то же самое проще было бы реализовать с помощью WordPress, ведь в экосистеме есть очень много плагинов.

Современные генераторы статичных сайтов, такие как Gatsby, понравятся тем, кто уже является профессионалом в React, однако новичкам будет очень сложно начать работу с ними. Не говоря уже о том, что Gatsby – довольно сложная система, которая далека от простых генераторов статичных сайтов, как Jekyll. Мощь Gatsby  заключается в компиляции  сайта из нескольких источников данных. К примеру, вы можете создать сайт с данными, полученными от проприетарной CMS, используя WordPress для блога, Shopify для интернет-магазина и т.д.

Наконец, какой бы генератор статичных сайтов вы ни выбрали, вы добавляете дополнительный шаг «сборки» к публикации нового контента. Такие решения, как плагин  Simply Static, который мы обсудим позже, требуют, чтобы вы зашли в настройки плагина и перегенерировали страницы в качестве отдельного шага. Это добавляет проблем, когда вам нужно внести какие-либо изменения на сайт.

Плагины генерации статичных сайтов в WordPress

Чтобы улучшить производительность сайта WordPress, вы можете включить страничное кэширование, что позволит вам избежать выполнения PHP и MySQL при каждой загрузке страницы. Кэширование страниц напоминает генерацию статичных сайтов, поскольку содержимое страницы преобразуется в статичный файл. Ключевое отличие состоит в том, когда именно происходит это преобразование.

На заре существования WordPress были разработаны плагины для страничного кэширования, и общий подход выглядел примерно так:

  1. При первой попытке запроса содержимого страницы веб-сервер определяет, что передавать содержимое для запрошенного URL-адреса должно веб-приложение (в данном случае WordPress). WordPress (с помощью PHP) посылает запрос к БД (MySQL), создает содержимое страницы с помощью HTML/CSS/JavaScript, после чего сохраняет ее как статичный файл во временной локации, известной как кэш. Затем контент страницы передается в браузер.
  2. При последующих попытках веб-сервер снова определит, что передавать содержимое для запрошенного URL-адреса должно веб-приложение. Однако WordPress (с помощью PHP) увидит, что в кэше уже существует статичный файл, после чего его содержимое будет передано в браузер.
  3. Часто файл кэша для данного URL-адреса очищается при повторной сборке контента страницы либо по истечении заданного времени.

Плагины WP Super Cache и W3 Total Cache были одними из первых решений WordPress со страничным кэшированием в форме генерации статичных файлов. Они позволяют добавлять правила перезаписи URL в файл .htaccess для Apache или в конфигурацию Nginx (если у вас есть доступ), чтобы сервер мог обработать статичный контент без выполнения PHP и WordPress для повышения производительности.

С другой стороны, у нас есть такие плагины, как Simply Static и WP2Static, являющиеся реальными генераторами статичных сайтов в WordPress. С помощью этих плагинов вебмастер может создавать статичные HTML-файлы на базе контента своего WordPress-сайта. Храниться эти файлы будут в заранее отведенной локации. Затем эти статичные файлы можно либо загрузить на сервер, либо настроить веб-сервер так, чтобы он автоматически брал статичные файлы из установленной локации. В отличие от кэширующего плагина, при изменении содержимого URL владельцу сайта нужно будет заново сгенерировать либо этот файл, либо все статичные файлы.

Gatsby – популярное решение для генерации статичного контента на базе WordPress-сайта. В отличие от Simply Static, Gatsby использует плагин WP GraphQL, чтобы превратить сайт на WordPress в готовый источник данных GraphQL. Используя систему шаблонов React, Gatsby запрашивает источник данных GraphQL и генерирует статичный контент из данных WordPress – либо через командную строку, либо через сервис, как Gatsby Cloud.

За последние 5 лет я видел, как многие известные люди в среде WordPress переходили к какому-нибудь headless-решению или генератору статичных сайтов, после чего возвращались к обычному WordPress. Я никогда не понимал хайпа вокруг генераторов статичных сайтов и никогда не пробовал их. Все потому, что я годами использовал страничное кэширование Nginx.

Что представляет собой страничное кэширование Nginx

В отличие от страничного кэширования на базе плагинов, которое мы обсуждали ранее, когда WordPress (и PHP) участвуют в создании статичных файлов кэша при запросе страницы, существует возможность реализации страничного кэширования на уровне веб-сервера, когда последний сам формирует статичные файлы кэша.

И Apache, и Nginx позволяют нам автоматически создавать статичную версию страницы на уровне веб-сервера. Nginx был написан специально для устранения ограничений производительности Apache, а потому обогнал Apache в популярности. Как показали тесты, Nginx работает до 2,5 раз быстрее, чем Apache, если говорить про обслуживание статичного контента. По этой причине мы и выбрали Nginx, а не Apache. В Nginx + PHP страничное кэширование может быть настроено с помощью модуля FastCGI. Это позволяет Nginx передавать статичную версию страницы без выполнения PHP и MySQL.

Я долгие годы использовал связку Apache + Varnish, после чего решил переключиться на Nginx + FastCGI Cache. Включив страничное кэширование на уровне веб-сервера, я забыл про плагины кэширования или генераторы статичных сайтов. Мой веб-сервер всегда справлялся с обработкой статичных версий записей и страниц в WordPress.

Прежде чем мы углубимся в настройку правил страничного кэширования Nginx, важно отметить, что есть два других уровня кэширования, которые следует учитывать при оптимизации WP-сайта: браузерное кэширование и объектное кэширование. Мы уже рассматривали их ранее в статьях, но здесь тоже приведем краткую выдержку:

  1. Браузерное кэширование. В этом случае статичные ресурсы (JavaScript, CSS, изображения), а также сама HTML-страница кэшируются браузером. Браузерное кэширование не всегда влияет на время отклика приложения или на пропускную способность WP-сайта. Однако оно помогает сделать сайт более адаптивным, поскольку статичные ресурсы быстрее загружаются из кэша браузера, когда вы перемещаетесь по страницам одного и того же сайта.
  2. Объектное кэширование. Объектное кэширование полезно, когда вы работаете с динамическим контентом, таким как интернет-магазины или сайты сообществ. В данном случае кэшируются объекты данных, извлеченные из БД, что помогает сократить количество запросов к БД в будущем. Это отличный способ ускорить свой WP-сайт с минимальной технической настройкой.

Внедрение этих уровней кэширования наравне со страничным кэшированием позволит существенно поднять производительность вашего WP-сайта.

Страничное кэширование Nginx – разбираемся в деталях

Кэширование на уровне веб-сервера – не новое явление. Модуль mod_cache в Apache и подобные модули кэширования существуют еще с версии Apache 2.0, которая вышла в 2004 году. Почему тогда появились плагины кэширования? Все просто: владельцы WordPress-сайтов лишь в редких случаях могли менять конфигурацию веб-сервера на хостинге. Предложения от виртуальных хостингов обычно базируются на универсальной серверной конфигурации, когда «один размер подходит всем». Потому владельцам сайтов на WordPress приходилось полагаться на кэширующие решения на уровне веб-приложений, а не на уровне веб-сервера.

С появлением VPS-хостингов управление своим сервером стало дешевле и проще. Разработчики получили прямой доступ к конфигурации веб-сервера. Это открыло возможность реализации кэширования для сайта на уровне веб-сервера.

Самый простой способ реализации страничного кэширования Nginx в веб-приложении на базе PHP, таком как WordPress, — использование модуля FastCGI для автоматического кэширования статичной HTML-версии любого URL в WordPress. Мы уже тестировали производительность WP-сайта с отключенным кэшированием, с кэширующим плагином, с Varnish, а также с Nginx + FastCGI. В итоге связка Nginx + FastCGI стала явным победителем.

Правила, позволяющие отказаться от формирования страничного кэша

Конечно, на любом WordPress-сайте есть динамические части, которые перестанут работать, если их закэшировать. К примеру, если вы закэшируете форму входа в WordPress, вы не сможете войти в админку. Вот почему практически во всех реализациях страничного кэширования есть правила для отказа от кэша. Ниже приведены правила Nginx из нашего руководства:

# Don't skip by default
set $skip_cache 0;

# Don’t cache POST requests
if ($request_method = POST) {
    set $skip_cache 1;
}

# Don’t cache URLs with a query string
if ($query_string != "") {
    set $skip_cache 1;
}

# Don't cache URIs containing the following segments
if ($request_uri ~* "/wp-admin/|/wp-json/|/xmlrpc.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml|/cart/|/checkout/|/my-account/") {
    set $skip_cache 1;
}

# Don't use the cache for logged in users or recent commenters
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in|edd_items_in_cart|woocommerce_items_in_cart") {
    set $skip_cache 1;
}

Эти правила не дают сформировать кэш в следующих случаях:

При любых POST-запросах. Обычно POST-запрос означает, что некоторые данные требуется обработать, и результат обработки нужно вывести на экран, потому ответ с кэшированным содержимым вряд ли подойдет.

Если в URL имеется строка запроса. Как правило, владельцы WordPress-сайтов (разработчики) включают свои параметры Permalink Setting, отличные от «plain», а потому строки запроса в URL означают, что некоторые данные требуется извлечь и отобразить.

Для определенных URL в WordPress. Нельзя кэшировать wp-admin, wp-json, URL-адреса для динамических вещей, как корзина товаров, страница заказа, страница учетной записи и т.д.

Для зарегистрированных пользователей и недавних комментаторов. Сделать это можно путем проверки браузерных cookies, указывающих тип пользователя.

Агрессивное страничное кэширование с меньшим количеством правил

Возможно, вы заметили, что приведенные выше правила кэширования специфичны для WordPress, но по-прежнему достаточно обобщенные. Они предназначены для работы с любым WordPress-сайтом. Если мы хотим написать правила для конкретного сайта, мы должны действовать более агрессивно. Давайте посмотрим, как мы можем ужесточить правила.

Правило для POST-запросов

# Don’t cache POST requests
if ($request_method = POST) {
    set $skip_cache 1;
}

Мы можем удалить это первое правило, если на нашем сайте нет форм, которые передают POST-запросы к URL во фронтенде сайта. Также здесь мы имеем правило, которое запрещает формирование кэша для консоли WordPress, а также для любых запросов к определенным базовым файлам WordPress (подробнее об этом позже). Кэш не будет формироваться для любых POST-запросов к консоли WP, WP REST API и к отдельным файлам ядра. Многие плагины форм отправляют POST-запросы к /wp-admin/admin-ajax.php или к WP REST API, потому они будут работать после удаления этого правила. Нужно все тщательно тестировать, если вы решили изменить эти правила.

Правило для строки запроса

# Don’t cache URLs with a query string
if ($query_string != "") {
    set $skip_cache 1;
}

Это правило говорит о том, что если в URL-адресе есть строка запроса, то предполагается, что контент является динамическим, т.е. не должен кэшироваться. Иногда верно, что строка запроса указывает на динамический контент, но не всегда. Конечно, остаются некоторые URL со строками запроса, которые я по-прежнему не хочу кэшировать. К примеру, я бы хотел, чтобы мои поисковые результаты WordPress (https://oddstyle.ru/?s=buddypress) кэшировались.

Если вы хорошо знаете свой сайт, вы понимаете, какие строки запроса следует кэшировать. Хорошей идеей будет проверка логов доступа. Там вы, возможно, увидите некоторые строки запроса, о которых вы не знали.

Для сайта deliciousbrains.com мы используем произвольное правило кэширования, которое позволяет отказаться от формирования кэша для URL-адресов, содержащих специфичные параметры строки запроса:

if ($request_uri ~* "(\?|&)(coupon|preview|download_file|licence_key)=") {
    set $skip_cache 1;
}

Но это сайт WooCommerce. Если у вас простой сайт, который может быть статичным, вам, вероятно, нужно отказаться от кэша только для параметра preview.

По умолчанию WordPress добавляет ?doing_wp_cron к URL-адресу, чтобы выполнить WordPress cron как часть запроса. Таким образом, вы вряд ли захотите кэшировать запросы с этой строкой. Правда, если вы грамотно настроили cron, вам не придется беспокоиться о данной строке запроса.

Наше правило для строки запроса стало следующим:

# Don't cache post previews
if ($request_uri ~* "(\?|&)preview=") {
    set $skip_cache 1;
}

Правило для консоли WordPress

Следующее правило позволяет отказаться от формирования кэша WordPress для базовых файлов системы, а также для некоторых распространенных ecommerce-страниц:

# Don't cache URIs containing the following segments
if ($request_uri ~* "/wp-admin/|/wp-json/|/xmlrpc.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml|/cart/|/checkout/|/my-account/") {
    set $skip_cache 1;
}

Нам нужно запретить кэш для консоли WordPress, потому нам нужно включить /wp-admin/, /wp-json/ и wp-.*.php. При этом wp-.*.php – слишком широкое правило. Мы можем его конкретизировать, оставив только wp-login.php.

Возможно, вы подумали о том, что можно удалить /wp-json/, ибо вы не используете WP REST API. Но в реальности вы его используете. Панель инструментов WordPress активно обращается к WP REST API. При этом вы можете заблокировать его, разрешив доступ к нему только для зарегистрированных пользователей. Делается это с помощью простого PHP-сниппета. Следующая директива, добавленная в блок server для Nginx, позволит отклонять любые запросы, для которых не заданы cookie зарегистрированных пользователей.

location /wp-json/ {
    if ($http_cookie !~* "wordpress_logged_in") {
        return 403;
    }
    try_files $uri $uri/ /index.php?$args;
}

Можно убрать ecommerce URL-адреса, если вы их не используете. Я бы также удалил sitemap(_index)?.xml и /feed/, поскольку, я считаю, нам нужно обязательно кэшировать карту сайта и RSS-фиды.

Можно удалить index.php, поскольку это правило применимо только в случае, если вы не настроили красивые пермалинки, что непременно нужно сделать.

Часть /xmlrpc.php – то, что тоже можно удалить. XML-RPC – древний API, который редко используется в наши дни. Теперь у нас есть WP REST API, который является лучшим вариантом. Полностью отключить XML-RPC можно путем добавления следующего кода в блок server для Nginx:

location ~* /xmlrpc\.php$ {
    deny all;
    access_log off;
}

Я настоятельно рекомендую добавить следующий код в блок server для предотвращения выполнения PHP-файлов в папке uploads:

# Deny access to any files with a .php extension in the uploads directory
location ~* /uploads/.*\.php$ {
    deny all;
    access_log off;
}

В итоге наше правило будет иметь следующий вид:

# Don't cache the WordPress dashboard
if ($request_uri ~* "wp-(login|admin|json)") {
    set $skip_cache 1;
}

В некоторых случаях отказываться от кэширования всего WP REST API может быть нецелесообразно. У вас может быть публичная конечная точка, доступная только для чтения, которая получает много запросов, а потому существенно выиграет от страничного кэширования и отказа от PHP и MySQL. В этом случае вы можете добавить правило исключения, установив переменную $skip_cache в 0:

# Cache the Events API endpoint
if ($request_uri ~* "/wp-json/eventorama/v1/events") {
    set $skip_cache 0;
}

Правило для Cookies

Наконец, последнее правило позволяет отказаться от кэша, если в запросе обнаружены определенные cookies:

# Don't use the cache for logged in users or recent commenters
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in|edd_items_in_cart|woocommerce_items_in_cart") {
    set $skip_cache 1;
}

Вы можете удалить edd_items_in_cart и woocommerce_items_in_cart, если вы не используете Easy Digital Downloads или WooCommerce. Ядро WordPress не работает с wordpress_no_cache, и я не нашел упоминаний того, где используются такие cookie, а потому можем смело удалить этот параметр.

Cookie-файлы wp-postpass связаны со страницами, защищенными паролем в WordPress. Вы можете удалить этот параметр, если не планируете использовать данный функционал. Давайте также удалим wordpress_[a-f0-9]+, поскольку это какой-то универсальный параметр, лишенный конкретной цели.

Отказ от формирования кэша для comment_author позволяет автору комментария видеть свой комментарий и его статус (к примеру, «ожидает модерации») после отправки. Однако отключать кэш для всех страниц после отправки комментария – это излишество. Лучшим решением здесь является использование плагина, такого как wpDiscuz, чтобы асинхронно обрабатывать отправку комментариев.

Возможно, вы захотите отказаться от формирования кэша для cookie wordpress_logged_in, когда на вашем сайте есть несколько редакторов, обновляющих контент. Запретить кэширование для этих пользователей полезно, поскольку в таком случае во фронтенде сайта для них будет выводиться админ-бар.

В итоге наше правило будет иметь следующий вид:

# Don't use the cache for logged in users
if ($http_cookie ~* "wordpress_logged_in") {
    set $skip_cache 1;
}

Если вы ведете сайт с многочисленными пользователями (интернет-магазин, сайт сообщества) вам вряд ли захочется отказываться от кэширования для всех страниц только потому, что пользователь является зарегистрированным. Вам понадобится другая стратегия. Для сайта deliciousbrains.com мы используем такой подход: когда один из членов нашей команды входит в WordPress, мы задаем 1 для custom dbi_admin cookie.

/**
 * Set cookie for admin users on login.
 *
 * @param string  $user_login
 * @param WP_User $user
 */
function dbi_admin_cookie( $user_login, $user ) {
    if ( empty( $user->roles ) || ! in_array( 'administrator', $user->roles ) ) {
        return;
    }

    $expire = time() + YEAR_IN_SECONDS;
    setcookie( 'dbi_admin', 1, $expire, COOKIEPATH, COOKIE_DOMAIN, false, false );
}
add_action( 'wp_login', 'dbi_admin_cookie', 10, 2 );

Затем следующее правило позволяет отказаться от формирования кэша только для этих администраторов:

# Admin users
if ($cookie_dbi_admin = 1) {
    set $skip_cache 1;
}

Если вам интересно, где задается $cookie_dbi_admin, то вам надо помнить, что Nginx автоматически создает переменные для всех cookie.

Мы также используем этот cookie для отказа от загрузки Google Analytics и других фрагментов Javascript, чтобы избежать загрязнения данных при использовании сайта.

Если вы используете простой WordPress-сайт со статичными (по большей части) страницами, весь блок отказа от кэширования можно ужать до следующего:

# Don't skip by default
set $skip_cache 0;

# Don't cache the WordPress dashboard
if ($request_uri ~* "wp-(login|admin|json)") {
    set $skip_cache 1;
}

# Don't cache post previews
if ($request_uri ~* "(\?|&)preview=") {
    set $skip_cache 1;
}

# Don't use the cache for logged in users
if ($http_cookie ~* "wordpress_logged_in") {
    set $skip_cache 1;
}

Увеличиваем срок жизни кэша

Теперь, когда мы рассмотрели все наши рекомендуемые исключения, мы можем перейти к более агрессивному кэшированию WordPress-страниц.

Самое очевидное изменение, которое вы можете сделать – это увеличить продолжительность жизни кэша. В руководстве по установке WordPress на Ubuntu мы начинаем с задания продолжительности в 60 минут, но ее можно увеличить до 1 дня, недели или даже месяца, если вы действительно в этом нуждаетесь.

К примеру, в моем личном блоге я писал посты 1 раз в месяц, а потому срок жизни кэша можно было вполне задать в один месяц. Как быть, если мне придется обновить какой-нибудь пост раньше этого времени? В таком случае есть плагин Nginx Cache, который автоматически очищает кэш при изменении содержимого.

Как мы уже писали в статье ранее, мы задали более длительный срок кэширования – 7 дней. Затем мы настроили сайт на очистку всего кэша при каждом обновлении контента. Мы нашли это решение более надежным по сравнению с попытками точно определить, какую веб-страницу или страницы надо убрать из кэша, что существенно усложняется из-за архивов и пагинации.

Предварительная загрузка страничного кэша

Если вы используете плагин Nginx Cache, вы очищаете весь страничный кэш всякий раз, когда вы сохраняете изменения в контенте для вашего WordPress-сайта. Это, как мы уже говорили выше, еще одно слишком универсальное решение, от которого лучше отходить.

Возможно, на вашем сайте можно просто очистить кэш только для одной страницы, которую вы изменили. Однако на другом сайте такой подход может привести к тому, что в сайдбаре останется заголовок старой страницы. Чтобы гарантировать, что сохраненные изменения отображаются везде, плагины страничного кэширования чистят кэш для всего сайта.

Проблема в том, что каждая страница будет работать медленнее для следующего пользователя, который ее запросит. И мы говорим о 10-кратном замедлении. 300мс против 30мс.

В идеале мы могли бы точно определить, какие страницы требуют очистки кэша всякий раз при внесении изменений на сайте. Далее мы могли бы удалять из кэша только их. И затем мы могли бы предварительно загрузить их в кэш, чтобы следующий запрос брался именно из кэша. Это помогло бы нам избежать проседания в производительности.

Увы, точно определить все необходимые страницы, кэш для которых надо очистить при обновлении контента, очень сложно. Я пока в поисках подходящего решения.

Лучшие решения, которые я видел, очищают весь кэш, а затем сканируют весь сайт, выполняя предварительную загрузку кэша. WP Rocket и WP Super Cache предлагают этот функционал, но с нашей настройкой Nginx cache совместим только WP Rocket. Плагин будет предварительно загружать кэш, не вмешиваясь в настройку Nginx cache.

Персонализированный динамический контент

Есть еще один сценарий, который не позволяет вам воспользоваться всеми преимуществами кэширования Nginx. Связан он с персонализированным динамическим контентом. Всякий раз, когда кэширование реализуется на страницах с таким контентом, вы рискуете кэшировать личные данные одного пользователя и вывести их для другого. Представьте себе динамически сгенерированную корзину покупок в верхней части всех продуктовых страниц интернет-магазина. Вы же не хотите, чтобы эти данные кэшировались, ведь в таком случае все покупатели будут видеть одну и ту же кэшированную корзину с товарами.

К счастью, статичные файлы кэша – это не что иное, как обработанные HTML, CSS и JavaScript-файлы, которые WordPress выводит для этих страниц. С помощью кастомного JS-кода и асинхронного запроса можно получить релевантную информацию для каждого пользователя и обновить только те секции содержимого кэшируемой страницы, которые необходимо персонализировать. У нас есть руководство о том, как мы решили эту проблему для интернет-магазина, но теория одинакова для любого контента такого типа:

  1. Кэшируйте общую версию всей страницы, не содержащую личных данных.
  2. Используйте JavaScript и асинхронный запрос для обновления страницы с персонализированным контентом для каждого отдельного пользователя.

Заключение

Если бы я захотел сегодня сделать полностью статичный сайт без динамических частей, я бы поступил следующим образом:

  1. Установил бы WordPress в подкаталог субдомена (к примеру, https://cms.oddstyle.ru/wp/).
  2. Защитил этот подкаталог с помощью HTTP Basic Authentication.
  3. Использовал плагин Simply Static для генерации статичного сайта, сохранив его в корневом каталоге (к примеру, https://cms.oddstyle.ru/).
  4. Связал бы основной домен (https://oddstyle.ru) с CDN.

В итоге я бы получил все преимущества статичного сайта (скорость, безопасность и т.д.), но при этом легко бы смог предоставить кому-то еще доступ для редактирования, когда это необходимо. В будущем, если вдруг мне понадобились бы динамические части, я бы мог просто переместить WordPress-сайт из подкаталога в корень, превратив его в обычный WP-сайт. Затем я добавил бы агрессивное страничное кэширование, чтобы сайт работал так же быстро, как статичный.

Преимущества доступных инструментов кэширования на уровне сервера состоят в том, что вы можете эффективно превратить свой WP-сайт в статичный, избежав проблем с ручной перестройкой кэша. Наши сайты Delicious Brains и SpinupWP работают на базе WordPress с использованием кэширования Nginx, и у них редко возникают какие-то проблемы с работоспособностью или скоростью – даже во время Черной пятницы.

Какие решения для кэширования вы используете для своих WordPress-сайтов? Вы сами управляете кэшированием или за вас это делает ваш хостинг? Использовали ли вы генераторы статичных сайтов? Пробовали headless WordPress? Делитесь своими комментариями, мы им всегда рады.

Источник: https://spinupwp.com

Блог про WordPress
Комментарии: 2
  1. Алекс

    Спасибо Вам за очень интересные и полезные статьи по вордпресс!
    Очень круто что есть такие сайты!

    1. Дмитрий (автор)

      Спасибо!

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

Получать новые комментарии по электронной почте.