В этом разделе рассматривается расширенное использование циклов. Это немного технично, но пусть это вас не пугает. Мы начнем с простого примера и будем двигаться дальше. Проявив немного здравого смысла, терпения и энтузиазма, вы тоже сможете создавать циклы под любые ваши нужды.
Во-первых, зачем использовать несколько циклов? В общем, ответ заключается в том, что вы можете захотеть сделать что-то с одной группой сообщений и сделать что-то другое с другой группой сообщений, но отобразить обе группы на одной странице . «Что-то» может означать почти что угодно; вы ограничены только вашими навыками PHP и вашим воображением.
Мы рассмотрим примеры ниже, но сначала вы должны прочитать об основах. Взгляните на основной цикл. Его структура такова:
<?php if ( have_posts() ) : ?>
<?php while ( have_posts() ) : the_post(); ?>
<!-- do stuff ... -->
<?php endwhile; ?>
<?php endif; ?>
На английском (PHP-типы и люди, знакомые с кодом, могут пропустить ниже) приведенное выше будет читаться так: Если мы собираемся отображать сообщения, то получайте их по одному. Для каждого сообщения в списке отображайте его в соответствии с некоторым шаблоном. Когда дойдём до последнего поста, обработайте его и остановить цикл. Строка (строки) работы зависит от шаблона.
Небольшое отступление о том, что делать : в этом примере это просто заполнитель для кода, который определяет, как форматировать и отображать каждый пост на странице. Этот код может меняться в зависимости от того, как вы хотите, чтобы ваш WordPress выглядел. Если вы посмотрите на файл index.php темы Кубрика, то в разделе «Делать что-то» будет все ниже:
<?php while ( have_posts() ) : the_post(); ?>
<?php comments_popup_link( 'No Comments »', '1 Comment »', '% Comments »' ); ?>
Пояснение: have_posts() и the_post() — это удобные оболочки вокруг глобального объекта $wp_query , в котором и происходит все действие. $wp_query вызывается в заголовке блога и передает аргументы запроса, поступающие через GET и PATH_INFO . $wp_query принимает аргументы, строит и выполняет запрос к БД, результатом которого является массив сообщений. Этот массив сохраняется в объекте, а также возвращается обратно в заголовок блога, где он помещается в глобальный массив $posts (для обратной совместимости со старыми циклами сообщений).
Как только WordPress завершит загрузку заголовка блога и спустится в шаблон, мы придем к циклу публикации. Функция have_posts() просто вызывает метод $wp_query->have_posts() , которая проверяет счетчик циклов, чтобы узнать, остались ли какие-либо сообщения в массиве сообщений. И the_post() вызывает $wp_query->the_post() , который увеличивает счетчик циклов и устанавливает глобальную переменную $post , а также все глобальные данные поста. Как только мы исчерпаем цикл, функция have_posts() вернет false, и мы закончим.
Примеры циклов
Ниже приведены три примера использования нескольких циклов. Ключом к использованию нескольких циклов является то, что $wp_query можно вызвать только один раз. Чтобы обойти это, можно повторно использовать запрос, вызвав rewind_posts() или создав новый объект запроса. Это рассматривается в примере 1. В примере 2 рассматривается использование переменной для хранения результатов запроса. Наконец, «несколько циклов в действии» объединяет множество идей, чтобы задокументировать один из способов использования нескольких циклов для продвижения сообщений определенной категории на главной странице вашего блога.
Пример 1
Чтобы повторить тот же запрос во второй раз, вызовите rewind_posts() . Это сбросит счетчик циклов и позволит вам выполнить еще один цикл.
<?php rewind_posts(); ?>
<?php while ( have_posts() ) : the_post(); ?>
<!-- Do stuff... -->
<?php endwhile; ?>
Если вы закончили работу с сообщениями в исходном запросе и хотите использовать другой запрос, вы можете повторно использовать объект $wp_query, вызвав query_posts() , а затем вернуться к циклу. query_posts () выполнит новый запрос, создаст новый массив сообщений и сбросит счетчик циклов.
// Get the last 10 posts in the special_cat category.
<?php query_posts( 'category_name=special_cat&posts_per_page=10' ); ?>
<?php while ( have_posts() ) : the_post(); ?>
<!-- Do special_cat stuff... -->
<?php endwhile; ?>
Если вам нужно сохранить исходный запрос, вы можете создать новый объект запроса.
<?php $my_query = new WP_Query( 'category_name=special_cat&posts_per_page=10' ); ?>
<?php while ( $my_query->have_posts() ) : $my_query->the_post(); ?>
<!-- Do special_cat stuff... -->
<?php endwhile; ?>
Объект запроса my_query используется, потому что вы не можете использовать глобальные функции have_posts() и the_post(), так как они оба используют $wp_query . Вместо этого вызовите новый объект $my_query .
Пример 2
Другая версия использования нескольких циклов использует другой способ обойти невозможность использования have_posts() и the_post() . Чтобы решить эту проблему, вам нужно сохранить исходный запрос в переменной, а затем переназначить его с помощью другого цикла. Таким образом, вы можете использовать все стандартные функции, которые полагаются на все глобальные переменные.
// going off on my own here
<?php $temp_query = clone $wp_query; ?>
<!-- Do stuff... -->
<?php query_posts( 'category_name=special_cat&posts_per_page=10' ); ?>
<?php while ( have_posts() ) : the_post(); ?>
<!-- Do special_cat stuff... -->
<?php endwhile; ?>
// now back to our regularly scheduled programming
<?php $wp_query = clone $temp_query; ?>
Несколько циклов в действии
Лучший способ понять, как использовать несколько циклов, — показать пример их использования. Возможно, наиболее распространенное использование нескольких циклов — это отображение двух (или более) списков сообщений на одной странице. Это часто делается, когда веб-мастер хочет показать не только самый последний написанный пост, но и посты из определенной категории.
Оставив в стороне все проблемы с форматированием и CSS, предположим, что мы хотим иметь два списка сообщений. Один, в котором будут перечислены самые последние сообщения (стандартные 10 последних добавленных сообщений), а другой будет содержать только одно сообщение из категории «избранные». Сообщения в категории «избранные» должны отображаться первыми, а затем следует второй список сообщений (стандартный). Подвох в том, что ни один пост не должен появляться в обеих категориях.
Шаг 1. Получите только один пост из категории «Избранное».
<?php $my_query = new WP_Query( 'category_name=featured&posts_per_page=1' ); while ( $my_query->have_posts() ) : $my_query->the_post(); $do_not_duplicate = $post->ID; ?> <!-- Do stuff... --> <?php endwhile; ?>
Происходит тут следующее:
Устанавливаем $my_query равным результату запроса всех сообщений, в которых категория названа избранной, и выбираем только одно сообщение. Кроме того, устанавливаем переменную $do_not_duplicate равной идентификационному номеру возвращаемого сообщения. Напомним, что в строке «Do stuff» подразумеваются все параметры форматирования, связанные с полученным сообщением.
Обратите внимание, что на следующем шаге нам понадобится значение $do_not_duplicate , чтобы одно и то же сообщение не отображалось в обоих списках.
Шаг 2 . Второй цикл, получить X последних сообщений (кроме одного).
Следующий код получает X последних сообщений (как определено в настройках WordPress), сохраняет сообщение, уже отображаемое в первом цикле, и отображает их в соответствии с Do stuff .
<?php if ( have_posts() ) : while ( have_posts() ) : the_post();
if ( $post->ID == $do_not_duplicate ) continue;?>
<!-- Do stuff... -->
<?php endwhile; endif; ?>
Тут происходит следующее: Получите все сообщения. Сообщение с идентификатором равным $do_not_duplicate, пропустить ( continue), все остальные сообщения отобразить в соответствии с Do stuff . Кроме того, обновите кеш, чтобы плагины тегов и ключевых слов работали нормально. Напомним, переменная $do_not_duplicate содержит идентификатор уже отображаемого поста.
Конечный результат
<?php $my_query = new WP_Query( 'category_name=featured&posts_per_page=1' );
while ( $my_query->have_posts() ) : $my_query->the_post();
$do_not_duplicate = $post->ID; ?>
<!-- Do stuff... -->
<?php endwhile; ?>
<!-- Do other stuff... -->
<?php if ( have_posts() ) : while ( have_posts() ) : the_post();
if ( $post->ID == $do_not_duplicate ) continue; ?>
<!-- Do stuff... -->
<?php endwhile; endif; ?>
Конечным результатом будет страница с двумя списками. Первый список содержит только один пост — самый последний пост из категории «избранное». Второй список будет содержать X последних сообщений (как определено в настройках WordPress), за исключением сообщения, которое уже отображается в первом списке. Таким образом, как только сообщение с функцией будет заменено новым, предыдущая функция будет отображаться в разделе стандартного списка сообщений ниже (в зависимости от того, сколько сообщений вы выберете для отображения, и от частоты публикации). Этот метод (или аналогичный) использовался многими в сочетании со знанием иерархии шаблонов для создания другого вида для home.php и index.php.
Примечание для нескольких сообщений в первой категории
Если posts_per_page=2 или больше, вам нужно будет немного изменить код. Переменная $do_not_duplicate должна быть преобразована в массив, а не в одно значение. В противном случае первый цикл завершится и переменная $do_not_duplicate будет равна только идентификатору последнего сообщения. Это приведет к дублированию сообщений во втором цикле. Чтобы устранить проблему, замените:
<?php $my_query = new WP_Query( 'category_name=featured&posts_per_page=1' );
while ( $my_query->have_posts() ) : $my_query->the_post();
$do_not_duplicate = $post->ID; ?>
на
<?php $my_query = new WP_Query( 'category_name=featured&posts_per_page=2' );
while ( $my_query->have_posts() ) : $my_query->the_post();
$do_not_duplicate[] = $post->ID; ?>
Обратите внимание, что «posts_per_page» может быть любым числом. Это превращает $do_not_duplicate в массив. Затем замените
<?php if ( have_posts() ) : while ( have_posts() ) : the_post();
if ( $post->ID == $do_not_duplicate ) continue; ?>
на
<?php if ( have_posts() ) : while ( have_posts() ) : the_post();
if ( in_array( $post->ID, $do_not_duplicate ) ) continue; ?>
Где вы продолжаете шаблон для любого значения posts_per_page, равного (2 в данном случае).
В качестве альтернативы вы можете передать весь массив $do_not_duplicate в $wp_query , и будут возвращены только записи, соответствующие вашим критериям:
<?php query_posts(array('post__not_in' => $do_not_duplicate));
if ( have_posts() ) : while ( have_posts() ): the_post(); ?>
Обратите внимание, что вместо строки параметр запроса был ассоциативным массивом, задающим опцию post__not_in .
Вложенные циклы
Вложенные циклы означают, что вы выполняете второй цикл до завершения первого. Это может быть полезно, например, для отображения списка сообщений с коротким кодом .
$my_query = new WP_Query( 'cat=3' );
if ( $my_query->have_posts() ) {
while ( $my_query->have_posts() ) {
$my_query->the_post();
the_content();
}
}
wp_reset_postdata();
Необходимо сбросить данные основного цикла после вложенного цикла, чтобы некоторые глобальные переменные снова имели правильные значения.