3 способа построения циклов в WordPress — WP_Query{} get_posts() query_posts()
Статья для новичков и тех, кто уже немного знаком с WordPress, которая должна развенчать все мифы использования разных вариантов циклов в WordPress.
О Цикле WordPress и с чем его едят я уже писал и вскользь упоминал о разных вариантах циклов в описаниях функций. В этой статье я сделаю следующий шаг и расскажу о 3-х вариантах построения циклов для вывода записей и о плюсах и минусах каждого из них.
Правильное использование нескольких циклов на странице даст вам возможность выводить блоки с нужными записями, сортировать их в нужном порядке и при этом не переживать о нарушении логической структуры страницы и «ловле» различных багов.
Возможные варианты построения циклов вывода записей:
- Стандартный цикл и цикл на основе query_posts().
- Дополнительный цикл на основе WP_Query().
- Дополнительный цикл на основе get_posts().
Каждый из этих вариантов удобно использовать в разных ситуациях. Для использования каждого варианта не нужно изучать разный мануал, потому что все они работают с одинаковыми параметрами, нужно лишь понять как и где их использовать.
Для лучшего понимания и визуального восприятия работы функций запроса, изучите эту схему:
1) Стандартный Цикл и цикл на основе query_posts()
Я объединил 2 вида циклов (с query_posts() и начинающийся с if( have_posts() ), потому что технически они абсолютно одинаковые.
Давайте вспомним, как выглядит стандартный Цикл WordPress:
<?php // проверяем есть ли посты в глобальном запросе - переменная $wp_query if( have_posts() ){ // перебираем все имеющиеся посты и выводим их while( have_posts() ){ the_post(); ?> <div <?php post_class(); ?> id="post-<?php the_ID(); ?>"> <h1><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h1> <?php the_content(); ?> </div> <?php } ?> <div class="navigation"> <div class="next-posts"><?php next_posts_link(); ?></div> <div class="prev-posts"><?php previous_posts_link(); ?></div> </div> <?php } // постов нет else { echo "<h2>Записей нет.</h2>"; }
Такой код мы можем встретить в файлах index.php, category.php и т.д. Эти файлы отвечают за вывод на странице списка записей. Этот цикл перебирает по очереди посты, которые выводятся на странице и во время перебора, используя Теги Шаблона (предназначенные для использования внутри Цикла), мы можем вывести различные данные поста (заголовок, текст, метаданные и т.д.).
Обратите внимание: в стандартном Цикле мы не указываем никаких данных для выборки записей, а сразу начинаем цикл с if( have_posts() ){ while( have_posts() ){…
Это говорит о том, что данные уже существуют и их нужно просто обработать и вывести на экран.
«Уже существующие» данные находятся в глобальной переменной $wp_query
и для каждого типа страниц WordPress определяются автоматически, т.е. WordPress заранее делает запрос в БД, на основе того какая страница сейчас отображается (категория, метка, статья, постоянная страница и т.д.) и результат запроса записывается в $wp_query
, а затем мы используем эти данные для создания цикла. Интересно, что такой запрос делается функцией query_posts(), которую мы разберем ниже.
Обычный Цикл WordPress используется для базовых страниц WP (категории, метки, архивы по дате).
Цикл на основе query_posts()
query_posts() позволяет изменить базовый запрос и вывести нужный нам вариант записей.
Вариант 1
Мы можем изменить базовый запрос (сделать еще один запрос и перезаписать данные предыдущего запроса) и, например, вырезать ненужные категории из вывода или изменить количество выводимых записей, порядок сортировки и т.д.
<?php global $query_string; // параметры базового запроса // базовый запрос + свои параметры query_posts( $query_string .'&cat=-6,-9&order=ASC&posts_per_page=20' ); [СТАНДАРТНЫЙ ЦИКЛ WORDPRESS] wp_reset_query(); // сброс запроса ?>
В этом примере мы создали новый запрос к БД, в котором использовали параметры базового запроса + свои параметры: исключили категории 6 и 9 (cat=-6,-9), а также отсортировали записи по порядку (order=ASC) и вывели 20 записей на странице вместо, установленных в настройках 10 (posts_per_page=20).
Полный список параметров, которыми можно сформировать нужный нам вывод, смотрите в описании функции query_posts().
Преимущества такого изменения в том, что если мы, например, изменим количество выводимых записей на странице с 10 (по умолчанию) на 20, то пагинация на странице автоматически подстроится под это изменение, потому что query_post() меняет данные глобальной переменной $wp_query, а пагинация строится именно на основе этих данных. Это лишь один из примеров, показывающий что query_posts() и поведение других функций на странице взаимосвязаны.
Но все же, изменять базовый запрос WP рекомендуется через фильтр pre_get_posts, а не через query_posts().
Вариант 2
Можно не использовать параметры базового запроса ($query_string
), а полностью переписать базовый запрос:
query_posts( 'cat=-6,-9&order=ASC' );
Однако, такой подход по сути сотрет базовый запрос и создаст новый, который может быть составлен неправильно, поэтому полностью переписывать базовый запрос не рекомендуется. Лучше постараться решить задачу как-то по-другому.
Необходимость wp_reset_query()
Сбрасывать измененный запрос при использовании query_posts() нужно, потому что query_posts() переписывает глобальную переменную $wp_query
которая отвечает за некоторые свойства страницы. Давайте посмотрим на примере.
Предположим нам на странице категории 6 (ID категории), нужно вывести данные только поста 9 (ID поста):
<?php query_posts( 'p=9' ); if( have_posts() ){ while( have_posts() ){ the_post(); the_title(); the_content(); } } else { echo 'Записей нет'; } ?>
В этом примере мы не сбросили запрос и функция query_posts()
переписала глобальную переменную $wp_query
. Теперь, кода мы проверим какая это страница (а это страница категории: is_category() == true
), мы увидим, что это уже совсем не страница категории, а страница поста: is_single() == true
. Т.е. следующий код вернет нам «Это страница поста», хотя на самом деле это страница категории:
if( is_category() ) echo 'Это страница категории'; // не сработает if( is_single() ) echo 'Это страница поста'; // сработает
Ошибочка, которая может в последствии создать немало головной боли.
Когда использовать query_posts()?
Когда нужно немного изменить основной (базовый) запрос WordPress. В идеале:
- для исключения рубрики/метки (например, на главной странице).
- изменение направления сортировки.
- ограничения количества выводимых постов
- исключения определенных постов из категории/метки
- и т.п.
И напомню еще раз, для таких задач все же лучше использовать фильтр pre_get_posts.
Не нужно использовать query_posts() для создания нескольких циклов на одной странице, для вывода в сайдбар списка постов, для создания дополнительного вывода записей и т.п. Для этих целей используйте циклы на основе get_posts(). Они используют одни и те же параметры.
2) Цикл на основе WP_Query()
Для вывода постов никак не связанных с текущей страницей или для создания множественных (дополнительных) циклов можно использовать циклы на основе класса WP_Query. Выглядят они аналогично циклам с использование query_posts(). Для WP_Query используются те же самые параметры, что и для query_posts().
Интересно, что WP_Query является ядром функций query_posts() и get_posts(), т.е. обе эти функции работают на основе этого класса.
Пример цикла: выведем все записи из категории 9:
<?php // указываем категорию 9 и выключаем разбиение на страницы (пагинацию) $query = new WP_Query( 'cat=9&nopaging=1' ); if( $query->have_posts() ){ while( $query->have_posts() ){ $query->the_post(); ?> <h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2> <?php the_content(); ?> <?php } wp_reset_postdata(); // сбрасываем переменную $post } else echo 'Записей нет.'; ?>
Пример создания множественных циклов на основе WP_Query():
<?php // Цикл 1 $query1 = new WP_Query('cat=-1&nopaging=1'); // все посты, кроме категории 1 while( $query1->have_posts() ){ $query1->the_post(); // вывод записей } wp_reset_postdata(); // Цикл 2 $query2 = new WP_Query('cat=-2&nopaging=1'); // все посты, кроме категории 2 while( $query2->have_posts() ){ $query2->the_post(); // вывод записей } wp_reset_postdata(); // Цикл 3 $query3 = new WP_Query('cat=-3&nopaging=1'); // все посты, кроме категории 3 while( $query3->have_posts() ){ $query3->the_post(); // вывод записей } wp_reset_postdata(); ?>
Особенность циклов на WP_Query() в том, что мы создаем новый объект $query, который никак не связан с аналогичным глобальным объектом $wp_query и поэтому мы никак не нарушаем структуру текущей страницы.
Также, мы можем использовать новый объект в других целях, не только для вывода записей, но и для различного рода проверок: например, записи какой страницы используются в этом новом объекте; можем узнать общее количество записей удовлетворяющих запросу ($query->found_posts) и т.д. Такие данные могут пригодится при создании дополнительных запросов с пагинацией или где-то еще (пример в комментариях).
Зачем нужно использовать wp_reset_postdata()?
В глобальной переменной $post хранятся данные текущего поста (если показывается страница поста, то данные этого поста). Когда срабатывает часть кода $query->the_post()
, то в переменную $post
записываются данные текущего поста в цикле и в конце цикла в этой переменной остаются данные последнего поста из этого цикла, а нужно чтобы $post всегда содержала данные текущего поста страницы. Т.е. получается до использования цикла $post->ID
(ID текущего поста) было равно, допустим, 10, а после срабатывания цикла, та же самая переменная $post->ID
уже равна, допустим, 56 (ID последнего поста из цикле), а нужно чтобы она по-прежнему равнялась 10.
wp_reset_postdata() используется как раз для того, чтобы вернуть правильные данные в переменную $post.
Когда использовать WP_Query()?
- Если нужно вывести записи не затрагивая основной цикл (допустим записи в боковой панели).
- Если нужно создать множественные запросы.
- Если нужно сколько всего постов удовлетворяют условиям выборки (для этого в SQL запрос добавляется флаг SQL_CALC_FOUND_ROWS - это создает дополнительную нагрузку на запрос). Так циклы WP_Query() дополнительно нагружают запрос, то чаще нам будет подходить циклы с помощью get_posts().
3) Цикл на основе get_posts()
Самый удобный вариант выводить нужные записи в нужном порядке — это выводить их с помощью get_posts(). get_posts()
чаще всего подходит лучше под вашу задачу, например:
- нужно вывести 10 последних постов в сайдбаре.
- нужно вывести 10 случайных записей в подвале.
- нужно вывести все картинки прикрепленные к посту.
- нужно вывести записи с определенным произвольным полем.
get_posts() так же как и query_posts() работает на основе класса WP_Query() и поэтому передаваемые параметры одинаковые (см. их здесь).
Важной особенностью этой функции является то, что она форсированно устанавливает параметры:
suppress_filters=true
(можно изменить)posts_per_page=5
(можно изменить)ignore_sticky_posts=true
(нельзя изменить)no_found_rows=true
(нельзя изменить)
Последние два параметра значительно ускоряют запрос. Чем больше постов на сайте, тем больше будет разница в скорости работы функции get_posts() и WP_Query.
#1. Пример цикла на основе get_posts(). Выведем 5 записей из рубрики 9:
<?php global $post; // не обязательно // 5 записей из рубрики 9 $myposts = get_posts( array( 'category' => 9 ) ); foreach( $myposts as $post ){ setup_postdata( $post ); // стандартный вывод записей } wp_reset_postdata(); // сбрасываем переменную $post ?>
Код выведет именно 5 записей, хотя в аргументах мы указали только номер рубрики. Вызвано это тем, что у функции get_posts() есть параметры по умолчанию (см. описание), о которых нужно помнить. Например, если нам нужно вывести все записи из рубрики 9, то мы должны добавить еще параметр 'nopaging' => 1
или 'posts_per_page' => -1
(разницы нет).
Когда использовать get_posts()
- Всегда, когда нужно просто вывести записи из БД в любом месте шаблона.
- Когда нужно создать несколько циклов.
- Когда не нужно знать сколько всего записей подходят под выборку.
- Так как get_posts() принимает те же параметры что и query_posts(), её очень удобно использовать для вывода записей по самым разным критериям.
Выводы
Где и какой из 3-х вариантов циклов использовать:
-
query_posts() — если нужно изменить/подправить стандартный вывод записей на страницах WordPress. Можно использовать 1 раз на странице.
-
get_posts() — если нужно вывести записи из Базы Данных. Можно использовать сколько угодно раз на странице.
- WP_Query() — во всех других случаях когда не подошли query_posts() и get_posts(). Класс WP_Query() является ядром query_posts() и get_posts() и может быть использован для каких-либо сложных случаев вывода.
Помните, что параметры для всех вариантов одинаковые и описаны они на этом блоге.
—
Попробуйте уже сейчас заказать комментарии к посту в Инстаграм с привлекательными скидками на сайте doctorsmm. Здесь Вам будут предложены разнообразные форматы текстов на выбор, а также возможность самостоятельно выбрать любое подходящее предложение.