Расширенное руководство по оптимизации производительности WordPress
Опубликовано: 2022-03-11Сегодня WordPress используется более чем в 30% Интернета. Он прост в использовании, невероятно популярен и никуда не денется в ближайшее время.
Но WordPress может быть медленным. Итак, как вы его оптимизируете?
Существует множество статей о том, как настроить и оптимизировать WordPress. Фактически, сам WordPress предоставляет надежное руководство по оптимизации WordPress.
По большей части эти статьи и руководства охватывают довольно простые, но полезные концепции, такие как использование плагинов кэширования, интеграция с сетями доставки контента (CDN) и минимизация запросов. Хотя эти советы очень эффективны и даже необходимы, в конце концов, они не решают основную проблему: большинство медленных сайтов WordPress являются результатом плохого или неэффективного кода.
Таким образом, эта статья в основном предназначена для предоставления разработчикам и компаниям-разработчикам WordPress некоторых рекомендаций, которые могут помочь им устранить основные причины многих проблем с производительностью WordPress.
WordPress предоставляет множество функций, ориентированных на производительность, которые разработчики часто упускают из виду. Код, не использующий эти функции, может замедлить выполнение простейших задач, например получение сообщений. В этой статье подробно описаны четыре возможных решения, которые устраняют некоторые основные проблемы, связанные с низкой производительностью WordPress.
Получение сообщений
WordPress предлагает возможность извлечения любых сообщений из базы данных. Есть три основных способа сделать это:
Использование функции
query_posts()
: это очень прямой подход, но проблема в том, что он переопределяет основной запрос, что может привести к неудобствам. Например, это может быть проблемой, если мы хотим определить в какой-то момент после получения сообщений (например, внутриfooter.php
), с какой страницей мы имеем дело. На самом деле, в официальной документации есть примечание, рекомендующее не использовать эту функцию, поскольку вам потребуется вызвать дополнительную функцию для восстановления исходного запроса. Более того, замена основного запроса негативно повлияет на время загрузки страницы.Использование функции
get_posts()
: работает почти так же, какquery_posts()
, но не изменяет основной запрос. С другой стороны,get_posts()
по умолчанию выполняет запрос с параметромsuppress_filters
, установленным вtrue
. Это может привести к несоответствиям, особенно если мы используем в коде фильтры, связанные с запросами, поскольку эта функция может возвращать сообщения, которых вы не ожидаете на странице.Использование класса
WP_Query
: на мой взгляд, это лучший способ получить сообщения из базы данных. Он не изменяет основной запрос и выполняется стандартным образом, как и любой другой запрос WordPress.
Но какой бы метод мы ни использовали для взаимодействия с базой данных, нам нужно учитывать и другие вещи.
Ограничение запроса
Мы всегда должны указывать, сколько постов должен получить наш запрос.
Для этого мы используем параметр posts_per_page
.
WordPress позволяет нам указать -1 в качестве возможного значения для этого параметра, и в этом случае система попытается получить все сообщения, которые соответствуют определенным условиям.
Это не очень хорошая практика, даже если мы уверены, что получим лишь несколько результатов в качестве ответа.
Во-первых, мы редко можем быть уверены, что получим только несколько результатов. И даже если мы можем, установка без ограничения потребует от ядра базы данных сканирования всей базы данных в поисках совпадений.
И наоборот, ограничение результатов часто позволяет ядру базы данных сканировать данные только частично, что приводит к меньшему времени обработки и более быстрому ответу.
Еще одна вещь, которую WordPress делает по умолчанию, что может отрицательно сказаться на производительности, заключается в том, что он пытается добавить прикрепленные записи и вычислить, сколько строк было найдено в запросе.
Часто, однако, нам действительно не нужна эта информация. Добавление этих двух параметров отключит эти функции и ускорит наш запрос:
$query = new WP_Query( array( 'ignore_sticky_posts' => true, 'no_found_rows' => true ) );
Исключение сообщений из запроса
Иногда мы хотим исключить определенные сообщения из запроса. WordPress предлагает довольно прямой способ добиться этого: используя параметр post__not_in
. Например:
$posts_to_exclude = array( 1, 2, 3 ); $posts_per_page = 10; $query = new WP_Query( array( 'posts_per_page' => $posts_per_page, 'post__not_in' => $posts_to_exclude ) ); for ( $i = 0; $i < count( $query->posts ); $i++ ) { //do stuff with $query->posts[ $i ] }
Но хотя это довольно просто, это не оптимально, потому что внутри генерируется подзапрос. Это может привести к медленному отклику, особенно в больших установках. Быстрее разрешить эту обработку интерпретатору PHP с некоторыми простыми изменениями:
$posts_to_exclude = array( 1, 2, 3 ); $posts_per_page = 10; $query = new WP_Query( array( 'posts_per_page' => $posts_per_page + count( $posts_to_exclude ) ) ); for ( $i = 0; $i < count( $query->posts ) && $i < $posts_per_page; $i++ ) { if ( ! in_array( $query->posts[ $i ]->ID, $posts_to_exclude ) ) { //do stuff with $query->posts[ $i ] } }
Что я там делал?
По сути, я снял часть работы с движка базы данных и оставил ее движку PHP, который делает то же самое, но в памяти, что намного быстрее.
Как?
Во-первых, я удалил из запроса параметр post__not_in
.
Так как в результате запрос может принести нам некоторые посты, которые нам не нужны, я увеличил параметр posts_per_page
. Таким образом я гарантирую, что, даже если бы в моем ответе было несколько нежелательных сообщений, у меня было бы там как минимум $posts_per_page
желаемых сообщений.
Затем, когда я перебираю сообщения, я обрабатываю только те, которые не входят в массив $posts_to_exclude
.
Как избежать сложной параметризации
Все эти методы запросов предлагают широкий спектр возможностей для получения сообщений: по категориям, по мета-ключам или значениям, по дате, по автору и т. д.
И хотя эта гибкость является мощной функцией, ее следует использовать с осторожностью, поскольку такая параметризация может привести к сложным соединениям таблиц и дорогостоящим операциям с базой данных.
В следующем разделе мы расскажем об элегантном способе достижения аналогичной функциональности без ущерба для производительности.
Выжать максимум из опций WordPress
API параметров WordPress предоставляет ряд инструментов для простой загрузки или сохранения данных. Это полезно для обработки небольших фрагментов информации, для которых другие механизмы, предлагаемые WordPress (такие как сообщения или таксономии), слишком сложны.

Например, если мы хотим сохранить ключ аутентификации или цвет фона заголовка нашего сайта, параметры — это то, что нам нужно.
WordPress не только дает нам функции для их обработки, но и позволяет нам делать это наиболее эффективным способом.
Некоторые параметры даже загружаются непосредственно при запуске системы, что обеспечивает нам более быстрый доступ (при создании нового параметра нам нужно подумать, хотим ли мы его загружать автоматически или нет).
Рассмотрим, например, сайт, на котором у нас есть карусель, отображающая последние новости, указанные в админке. Нашим первым побуждением было бы использовать для этого мета-ключ следующим образом:
// functions.php add_action( 'save_post', function ( $post_id ) { // For simplicity, we do not include all the required validation before saving // the meta key: checking nonces, checking post type and status, checking // it is not a revision or an autosaving, etc. update_post_meta( $post_id, 'is_breaking_news', ! empty ( $_POST['is_breaking_news'] ) ); } ); // front-page.php $query = new WP_Query( array( 'posts_per_page' => 1, 'meta_key' => 'is_breaking_news' ) ); $breaking_news = $query->posts[0] ?: NULL;
Как видите, этот подход очень прост, но не оптимален. Он выполнит запрос к базе данных, пытаясь найти сообщение с определенным мета-ключом. Мы могли бы использовать опцию для достижения аналогичного результата:
// functions.php add_action( 'save_post', function ( $post_id ) { // Same comment for post validation if ( ! empty ( $_POST['is_breaking_news'] ) ) update_option( 'breaking_news_id', $post_id ); } ); // front-page.php if ( $breaking_news_id = get_option( 'breaking_news_id' ) ) $breaking_news = get_post( $breaking_news_id ); else $breaking_news = NULL;
Функциональность немного отличается от одного примера к другому.
В первом фрагменте кода мы всегда будем получать последние новости с точки зрения даты публикации сообщения.
Во втором каждый раз, когда новый пост устанавливается как экстренная новость, он перезаписывает предыдущую экстренную новость.
Но поскольку мы, вероятно, хотим по одному выпуску новостей за раз, это не должно быть проблемой.
И, в конце концов, мы заменили тяжелый запрос к базе данных (используя WP_Query
с метаключами) на простой и прямой запрос (вызов get_post()
), который является лучшим и более производительным подходом.
Мы также можем внести небольшое изменение и использовать переходные процессы вместо опций.
Переходные процессы работают аналогично, но позволяют нам указать время истечения.
Например, для экстренных новостей это подходит как перчатка, потому что мы не хотим, чтобы старое сообщение было экстренным, и если мы оставим задачу изменения или удаления этих экстренных новостей администратору, [s]он может забыть сделать Это. Итак, двумя простыми изменениями мы добавляем дату истечения срока действия:
// functions.php add_action( 'save_post', function ( $post_id ) { // Same comment for post validation // Let's say we want that breaking news for one hour // (3600 = # of seconds in an hour). if ( ! empty ( $_POST['is_breaking_news'] ) ) set_transient( 'breaking_news_id', $post_id, 3600 ); } ); // front-page.php if ( $breaking_news_id = get_transient( 'breaking_news_id' ) ) $breaking_news = get_post( $breaking_news_id ); else $breaking_news = NULL;
Включить постоянное кэширование
WordPress изначально имеет механизм кэширования объектов.
Параметры, например, кэшируются с использованием этого механизма.
Но по умолчанию это кэширование не является постоянным, а это означает, что оно существует только в течение одного запроса. Все данные кэшируются в памяти для более быстрого доступа, но они доступны только во время этого запроса.
Для поддержки постоянного кэширования требуется установка подключаемого модуля постоянного кэша.
Некоторые плагины полностраничного кеша поставляются с включенным плагином постоянного кеша (например, W3 Total Cache), а другие нет, и нам нужно установить его отдельно.
Это будет зависеть от архитектуры нашей платформы, будем ли мы использовать файлы, Memcached или какой-либо другой механизм для хранения кэшированных данных, но мы должны воспользоваться этой удивительной функцией.
Кто-то может спросить: «Если это такая замечательная функция, почему WordPress не включает ее по умолчанию»?
Основная причина в том, что в зависимости от архитектуры нашей платформы одни методы кэширования будут работать, а другие нет.
Например, если мы размещаем наш сайт на нашем распределенном сервере, мы должны использовать внешнюю систему кэширования (например, сервер Memcached), но если наш веб-сайт находится на одном сервере, мы могли бы сэкономить немного денег, просто используя файловую систему. кешировать.
Одна вещь, которую мы должны принять во внимание, — это истечение срока действия кеша. Это самая распространенная ошибка при работе с постоянным кэшированием.
Если мы не решим эту проблему должным образом, наши пользователи будут жаловаться, что они не увидят внесенные ими изменения или что их применение заняло слишком много времени.
Иногда нам приходится идти на компромисс между производительностью и динамичностью, но даже с учетом этих препятствий постоянное кэширование — это то, чем должна воспользоваться практически каждая установка WordPress.
AJAXing самый быстрый способ
Если нам нужно общаться через AJAX с нашим сайтом, WordPress предлагает некоторую абстракцию во время обработки запроса на стороне сервера.
Несмотря на то, что эти методы можно использовать при программировании внутренних инструментов или отправке форм из внешнего интерфейса, их следует избегать, если в этом нет строгой необходимости.
Причина этого в том, что для использования этих механизмов мы обязаны сделать почтовый запрос к некоторому файлу, расположенному внутри папки wp-admin
. Большинство (если не все) плагинов полностраничного кэширования WordPress не кэшируют ни запросы на публикацию, ни обращения к файлам администратора.
Например, если мы динамически загружаем больше сообщений, когда пользователь прокручивает нашу домашнюю страницу, было бы лучше напрямую обращаться к какой-либо другой странице внешнего интерфейса, которая получит преимущества кэширования.
Затем мы могли бы проанализировать результаты с помощью JavaScript в браузере.
Да, мы отправляем больше данных, чем нужно, но выигрываем по скорости обработки и времени отклика.
Разрушьте представление о том, что WordPress просто медленный
Это всего лишь несколько советов, которые разработчики должны учитывать при написании кода для WordPress.
Иногда мы забываем, что наш плагин или тема должны работать вместе с другими плагинами или что наш сайт может обслуживаться хостинговой компанией, которая обслуживает сотни или тысячи других сайтов с общей базой данных.
Мы просто фокусируемся на том, как плагин должен работать, а не на том, как он справляется с этой функциональностью или как сделать это эффективным способом.
Из вышесказанного ясно, что коренными причинами низкой производительности WordPress являются плохой и неэффективный код. Тем не менее, WordPress предоставляет все необходимые функции через различные API, которые могут помочь нам создавать гораздо более производительные плагины и темы без ущерба для скорости всей платформы.