Как оптимизировать сайт на WordPress. Подробное руководство.

Сегодня доля сайтов на WordPress составляет 25%. Легкий в использовании, невероятно популярный.
Но WordPress может быть медленным. Итак, как же его оптимизировать?
Есть множество статей о том, как настроить и оптимизировать WordPress. По большей части эти статьи и учебные пособия охватывают довольно простые, но полезные концепции, такие как использование плагинов кэширования, интеграция с CDN и минимизация запросов. Хотя эти советы очень эффективны и даже необходимы, в конце концов, они не затрагивают основную проблему: большинство медленных сайтов WordPress являются результатом плохого или неэффективного кода.

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

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

Получение постов

В WordPress существует три основных способа получения любой записи из базы данных:

  • использование функции query_posts()Это очень прямой подход, но проблема в том, что он переопределяет основной запрос, что может привести к неудобствам. Например, это может быть проблемой, если мы хотим определить, в какой-то момент после получения сообщений (например, внутри footer.php), с какой страницей мы имеем дело. Фактически в официальной документации есть примечание, рекомендующее использовать эту функцию, поскольку вам потребуется вызвать дополнительную функцию для восстановления исходного запроса. Более того, замена основного запроса негативно скажется на времени загрузки страницы;
  • использование функции get_posts(): она работает почти как query_posts (), но не изменяет основной запрос. С другой стороны, get_posts () по умолчанию выполняет запрос с параметром suppress_filters, установленным в true. Это может привести к несогласованности, особенно если мы используем фильтры, связанные с запросами, в нашем коде, и потому могут появиться посты, которые вы не ожидаете на странице;
  • использование класса WP_Query: на мой взгляд, это лучший способ получить сообщения из базы данных. Он не изменяет основной запрос, и он выполняется стандартным образом, как и любой другой запрос WordPress.

Но какой бы метод для взаимодействия с базой данных мы ни использовали , есть и способы, которые нам нужно рассмотреть.

Ограничение запросов

Мы должны всегда указывать, сколько постов должен отображать наш запрос.

Для этого мы используем параметр posts_per_page.

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

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

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

Другое дело, в том, что WordPress делает по умолчанию, — может отрицательно сказаться на производительности, заключается в том, что он пытается принести sticky posts и рассчитать, сколько строк было найдено в запросе.

Часто, однако, нам не нужна эта информация. Добавление этих двух параметров отключит эти функции и ускорит наш запрос:

$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_to_exclude.

Отказ от комплексной параметризации

Все эти query methods предлагают широкие возможности для получения постов: по категориям, meta keys or values, по дате, по авторам и т.д.

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

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

Сжатие с помощью опций WordPress

WordPress Options API предлагает серию инструментов для легкого сохранения и загрузки данных.

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

Например, если нам нужно сохранить authentication key или background color для header нашего сайта, —  options это то что нам нужно.

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

Рассмотрим, например, сайт, на котором у нас есть карусель, отображающая последние новости, определенные в back-end. Наш первый порыв должен был быть —  использование для этого meta-key следующим образом:

// 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;

Как видите, это очень просто, но не оптимально. Такой код выполнит запрос в базу данных, пытаясь найти пост с определенным мета-ключом ( meta-key ). Мы могли бы использовать опцию для достижения аналогичного результата:

// 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 ()), который является лучшим и более эффективным.

Мы также можем внести небольшие изменения и использовать временные опции вместо опций.

Временные опции работают аналогичным образом, но позволяют указывать expiration time.

Для последних новостей они подходят наилучшим способом

// 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 есть нативный object caching mechanism.

Опции, например, кэшируются с использованием этого механизма.

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

Поддержка постоянного кэширования требует установки плагина постоянного кэша.

Некоторые полнотекстовые плагины кэша поставляются с включенным плагином постоянного кэша (например, W3 Total Cache), но другие нет, и мы должны установить его отдельно.

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

Можно спросить: «Если это такая замечательная функция, почему WordPress не разрешает ее по умолчанию»?

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

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

Одна вещь, которую мы должны учитывать, — это срок действия кеша. Это наиболее распространенная ошибка работы с постоянным кэшированием.

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

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

 

Разрушаем миф, что WordPress это медленно

Это всего лишь несколько советов, которые разработчики должны учитывать при кодировании WordPress.

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

Мы просто сосредоточиваемся на том, как должен работать плагин, а не на его функциональности или как это повысить ее эффективность.

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

 

Оригинал статьи The Advanced Guide to Optimizing WordPress Performance

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

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