Transients API: Часть 4. Использование transients для улучшения производительности шорткодов
Последнее, что я хочу показать вам – как вы можете использовать transients для улучшения производительности вашего WP сайта на примере кэширования динамических данных шорткодов.
Хранение динамических данных шорткодов
Давайте перейдем к примеру с тем же клиентским сайтом, для которого я настраивал произвольные запросы. Для этого сайта я разработал несколько шорткодов, позволяющие выполнять разнообразные, сложные запросы, которые помогают легко и быстро вывести на экран определенные данные в разных частях веб-сайта.
К примеру, для освещения разных событий я создал шорткод, который позволяет редактору сайта получать весь контент разных типов записей, структурированный при помощи определенной таксономии. Такой подход позволяет редакторам легко создать полноценную область, посвященную определенному событию.
Это лишь один из многочисленных шорткодов, позволяющих получать контент для разных ситуаций. При использовании любого шорткода во время каждой загрузки страницы запускается сложный запрос WP_Query, позволяющий получить определенный набор контента. Как вы, возможно, уже предположили, здесь мы тоже можем применить transients для кэширования результатов. Нам не нужно совершать запрос при каждом просмотре страницы, что помогает снизить нагрузку на сервер и ускорить работу сайта.
Общие принципы работы с transients напоминают те, которые уже были мною раскрыты в прошлых статьях серии. Однако в данном случае есть свои нюансы, поскольку мы работаем с шорткодами, а не с файлами темы.
Все свои шорткоды я создавал в виде функциональных плагинов, поэтому они будут работать даже в том случае, если тема будет изменена в будущем.
Вот шорткод в исходном виде, без использования transients:
<?php // SPECIAL FEATURE CONTENT SHORTCODE function hpc_special_feature_shortcode( $atts ) { extract( shortcode_atts( array( 'type' => '', 'showposts' => -1, 'feature' => '', 'cat' => '', 'offset' => '', 'layout' => 'bullets' ), $atts ) ); $hpc_special_feature_query = new WP_Query( array( 'post_type' => $type, 'showposts' => $showposts, 'tax_query' => array( array( 'taxonomy' => 'special-feature', 'field' => 'slug', 'terms' => $feature ) ), 'category_name' => $cat, 'offset' => $offset ) ); ob_start(); ?> <div class="<?php echo $feature; ?>-content <?php echo $type; ?> <?php echo $layout; ?>"> <?php if( $layout == 'bullets' ) { ?> // BULLETS LOOP - NOT IMPORTANT FOR EXAMPLE <?php } elseif( $layout == 'small-feature' ) { ?> // SMALL FEATURE LOOP - NOT IMPORTANT FOR EXAMPLE <?php } elseif( $layout == 'big-feature' ) { ?> // BIG FEATURE LOOP - NOT IMPORTANT FOR EXAMPLE <?php } elseif( $layout == 'small-excerpt' ) { ?> // SMALL EXCERPT LOOP - NOT IMPORTANT FOR EXAMPLE <?php } ?> </div> <?php $output = ob_get_contents(); ob_end_clean(); return $output; wp_reset_postdata(); } add_shortcode( 'special-feature-content', 'hpc_special_feature_shortcode' );
А теперь измененный код, в котором используются transients для кэширования результатов шорткода. Объяснение его будет приведено ниже:
<?php // SPECIAL FEATURE CONTENT SHORTCODE function hpc_special_feature_shortcode( $atts ) { extract( shortcode_atts( array( 'type' => '', 'showposts' => -1, 'feature' => '', 'cat' => '', 'offset' => '', 'layout' => 'bullets' ), $atts ) ); $hpc_special_feature_query = get_transient( 'hpc_special_feature_query_' . $type . '_' . $showposts . '_' . $feature . '_' . $cat . '_' . $offset ); if( $hpc_special_feature_query === false ) { $hpc_special_feature_query = new WP_Query( array( 'post_type' => $type, 'showposts' => $showposts, 'tax_query' => array( array( 'taxonomy' => 'special-feature', 'field' => 'slug', 'terms' => $feature ) ), 'category_name' => $cat, 'offset' => $offset ) ); set_transient( 'hpc_special_feature_query_' . $type . '_' . $showposts . '_' . $feature . '_' . $cat . '_' . $offset, $hpc_special_feature_query, 60*3 ); } ob_start(); ?> <div class="<?php echo $feature; ?>-content <?php echo $type; ?> <?php echo $layout; ?>"> <?php if( $layout == 'bullets' ) { ?> // BULLETS LOOP - NOT IMPORTANT FOR EXAMPLE <?php } elseif( $layout == 'small-feature' ) { ?> // SMALL FEATURE LOOP - NOT IMPORTANT FOR EXAMPLE <?php } elseif( $layout == 'big-feature' ) { ?> // BIG FEATURE LOOP - NOT IMPORTANT FOR EXAMPLE <?php } elseif( $layout == 'small-excerpt' ) { ?> // SMALL EXCERPT LOOP - NOT IMPORTANT FOR EXAMPLE <?php } ?> </div> <?php $output = ob_get_contents(); ob_end_clean(); return $output; wp_reset_postdata(); } add_shortcode( 'special-feature-content', 'hpc_special_feature_shortcode' );
Вы можете заметить, что шорткод принимает 6 параметров: type, showposts, feature, cat, offset и layout. Эти параметры, кроме одного из них, используются в WP_Query, который требуется нам для получения релевантного контента. Параметр “Layout” применяется для определения того, как именно будет выводиться информация на экран, что не требуется нам для сохранения в transient (поскольку параметр затрагивает лишь фактический вывод контента на странице, а не способ получения контента из базы данных).
Все, что было до строки 15, совпадает с оригиналом. В строке 15 мы задаем новую переменную, равную значению transient, которое мы получаем через get_transient(). Однако в данном случае значение transient имеет более сложный вид, чем раньше. И вот почему: в первых примерах мы не сталкивались с пользовательским вводом, поэтому вся информация, полученные из базы данных, была каждый раз одной и той же. Однако шорткоды могут принимать определенные пользователями переменные, что делает их очень динамичными и уникальными. Информация, которую получает шорткод из базы данных, может быть разной для каждой комбинации используемых параметров.
К примеру, шорткод, используемый в примере, может использоваться для вывода контента о прошлогодней конференции на какой-либо отдельной странице, и тот же самый шорткод с другим набором переменных может использоваться для вывода информации о конференции, прошедшей в этом году, на другой странице. Следовательно, transients нужно разделить так, чтобы уникальные данные для каждой страницы хранились независимо друг от друга.
Именно поэтому я добавил значение каждого параметра, разделенное знаком подчеркивания, к имени transient, за исключением параметра layout, что было сделано по причинам, описанным выше. К примеру, на одной странице я мог использовать следующий шорткод для вывода всех подкастов о прошедшей в этом году конференции:
[ special-feature-content type=”podcast” showposts=”-1″ feature=”2014-sc-conf” cat=”soundbites” offset=”0″ layout=”bullets” ]
На 15 строке мы получим transient с именем:
“hpc_special_feature_query_podcast_-1_2014-sc-conf_soundbites_0“
Этот transient может использоваться в дальнейшем для того, чтобы увеличить производительность указанного шорткода.
Удобство данной реализации заключается в том, что мы можем получить столько transients, сколько нам необходимо, чтобы автоматически кэшировать данные для всех вариантов использования шорткодов.
Строка 16 содержит в себе еще одно отличие: здесь мы проверяем, имеются ли данные, сохраненные в transient, и если нет, то запускаем WP_Query (строки 17-29), чтобы получить свежие данные из базы данных (обратите внимание на то, что WP_Query такой же, как в исходном коде). Затем, в строке 30, мы сохраняем эту новую информацию в transient через функцию set_transient(), чтобы использовать данные при будущих просмотрах страницы. Обратите внимание, что формат имени transient соответствует тому, что мы использовали в строке 15, т.е. он параметры шорткода добавляются к имени transient. В этом экземпляре я задал время истечения равным 3 минутам, поскольку веб-сайт имеет высокий траффик во время таких событий, новый контент постоянно добавляется, проверка присутствия новых данных осуществляется как минимум каждые три минуты.
Остальная часть кода описывает получение данных из запроса и вывод их на странице.
Время истечения данных
Вы заметили, что время истечения данных для этого transient очень мало. Однако для данной реализации это помогает потенциально избежать тысячи просмотров страниц, что представляет собой значительное улучшение по сравнению с запуском WP_Query несколько раз в секунду.
Как и в предыдущих примерах, нам нужно будет удалять transients, если мы знаем, что они уже не актуальны. В данном случае это означает, что если новый подкаст опубликован, то нам нужно удалить существующие transients, чтобы обновить их (т.е. добавить в них новый подкаст).
Однако тут есть одна проблема: поскольку шорткоды могут обладать бесконечным числом возможных комбинаций, вы не в состоянии перечислить все имена transient, чтобы удалить их через хук save_post, как мы это делали в произвольных запросах (если кто-то знает решение, сообщите мне о нем). Именно по этой причине я решил сделать время истечения относительно коротким (ничего страшного не произойдет, если новый контент не будет отображаться на сайте в течение 3 минут после того, как он будет опубликован).
Все зависит от ваших шорткодов: у вас может быть всего несколько параметров с несколькими известными значениями, поэтому вы можете перечислить все возможные комбинации и удалить их так, как это было сделано в примере с произвольными запросами.
Источник: doitwithwp.com