Home News

Основы WP_Query в WordPress

05.09.2018

видео Основы WP_Query в WordPress

Создание WordPress темы #6 - Цикл WordPress (the loop)

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



Что такое WP_Query

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

Ниже приведён самый простой запрос с помощью класса WP_Query:


WordPress Theme Development Part 8 (Templates, Custom Post Type, WP_Query)

$query = new WP_Query( array( 'category_name' => 'news' ) );

Таким образом WordPress сделает запрос в базу данных, чтобы получить наши записи из категории «news». Результаты запроса будут храниться в объекте $query, с которым мы будем работать с помощью специальных методов, наверняка знакомых вам:


Using WP Query to Create a Custom Loop in WordPress

while ( $query->have_posts() ) : $query->the_post(); the_title(); // вывести название статьи the_content(); // вывести содержание endwhile;

С помощью метода have_posts() мы проверяем есть ли записи в буфере объекта $query, а с помощью метода the_post() мы берём одну запись из буфера и готовим её к выводу, делая доступными привычные нам функции the_title(), the_content() и другие.

После итерации над каждым объектом в буфере записей $query, метод have_posts() вернёт значение false и выйдет из нашего цикла while. Таким образом мы выведем заголовок и содержимое каждой статьи, полученной с помощью WP_Query.

Параметры WP_Query

Аргументом к запросу WP_Query может быть массив содержащий параметры запроса:

$query = new WP_Query( array( 'category_name' => 'news', 'posts_per_page' => 5, 'tag' => 'finance', ) );

Или аналогичной строкой:

$query = new WP_Query( 'category_name=news&posts_per_page=5&tag=finance' );

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

Существует огромное количество допустимых параметров в запросах WP_Query: категории, метки, типы записей, даты, авторы, таксономия, мета-данные и многое другое. Здесь мы попытаемся рассказать о самых важных и часто используемых параметрах.

Категории (рубрики)

Параметры категорий позволяют получить записи входящие (или не входящие) в определённую категорию или ряд категорий:

cat — число идентификатор определённой категории category_name — название определённой категории (ярлык) category__and — получить только те записи, которые присутствуют во всех категориях заданных данным массивом category__in — получить записи, которые присутствуют хотя бы в одной из категорий заданных массивом category__not_in — получить записи, которые не входят ни в одну из категорий заданных массивом

Например получить записи из категории с ярлыком (slug) «news»:

$query = new WP_Query( array( 'category_name' => 'news', ) );

Получить записи, входящие в одну из категорий с идентификатором 10, 11 или 12. Получить идентификатор категории, имея её ярлык или название, можно с помощью функции get_term_by() .

$query = new WP_Query( array( 'category__in' => array( 10, 11, 12 ), ) );

Получить записи, входящие в одну из категорий с идентификатором 10, 11 или 12, но не входящие ни в одну из категорий с идентификатором 21 или 22:

$query = new WP_Query( array( 'category__in' => array( 10, 11, 12 ), 'category__not_in' => array( 21, 22 ), ) );

Метки

Работа с параметрами меток (или тегов) в WP_Query мало чем отличается от категорий:

tag — получить записи с указанной меткой (ярлык) tag_id — получить записи с указанной меткой с помощью идентификатора tag__and — получить записи имеющие все указанные метки в массиве (идентификаторы) tag__in — получить записи имеющие хотя бы одну метку из массива (идентификаторы) tag__not_in — получить записи не имеющие ни одной из меток в массиве (идентификаторы) tag_slug__and — получить записи имеющие все метки указанные в массиве (ярлыки) tag_slug__in — получить записи имеющие хотя бы одну метку из указанного массива (ярлыки)

Например, получить записи имеющие метки с идентификаторами 11, 12 и 13, но исключить записи, которые имеют метки с идентификаторами 21, 22 или 23. Так же как и с категориями, получить идентификатор метки из её названия можно с помощью функции get_term_by() .

$query = new WP_Query( array( 'tag__and' => array( 11, 12, 13 ), 'tag__not_in' => array( 21, 22, 23 ), ) );

Записи, страницы и произвольные типы данных

С помощью WP_Query вы можете делать запросы на определённые записи, страницы и типы данных:

post_type — тип записи, по умолчанию post post_status — статус записи, по умолчанию publish p — идентификатор записи page_id — идентификатор страницы name — получить запись по её названию pagename — получить страницу по её названию post__in — получить записи, идентификатор которых входит в массив post__not_in — получить записи, идентификатор которых не входит в массив

Например, получить черновики страниц и записей:

$query = new WP_Query( array( 'post_type' => array( 'post', 'page' ), 'post_status' => 'draft', ) );

Получить страницу по адресу /about/contacts:

$query = new WP_Query( array( 'pagename' => 'about/contacts', ) );

Получить все запланированные записи и записи на утверждении, кроме тех, которые указаны в массиве post__not_in:

$query = new WP_Query( array( 'post_type' => 'post', 'post_status' => array( 'future', 'pending' ), 'post__not_in' => array( 40, 41, 42 ), ) );

При работе с иерархическими типами записей вы так же можете воспользоваться параметрами post_parent, post_parent__in и post_parent__not_in для того, чтобы задать поиск с ограничением по родительским записями.

Авторы

Для поиска записей по авторам существуют следующие параметры:

author — идентификатор автора author_name — ярлык автора author__in — записи авторов, указанных в массиве author__not_in — все записи, кроме авторов, указанных в массиве

Например, получить записи авторов, указанных в массиве:

$query = new WP_Query( array( 'author__in' => array( 12, 13, 14 ), ) );

Получить записи текущего пользователя:

$query = new WP_Query( array( 'author' => get_current_user_id(), ) );

Поиск по ключевым словам и датам

Для поиска по ключевым словам и ограничения результатов по датам в WP_Query используются следующие параметры:

s — ключевое слово или фраза year — год, например 2013 monthnum — порядковый номер месяца, от 1 до 12 w — номер недели, от 0 до 53 day — день, от 1 до 31 day — день, от 1 до 31 hour — час, от 0 до 23 minute — минута, от 0 до 60 second — секунда, от 0 до 60 m — год и месяц слитно, например 201311 (ноябрь, 2013)

Начиная с WordPress версии 3.7, в WP_Query доступен новый параметр date_query, который позволяет выполнять запросы со сложными датами. Про работу с date_query и с классом WP_Date_Query читайте в нашей статье .

Пример поиска записей, содержащих ключевую фразу и опубликованных в 2013 году:

$query = new WP_Query( array( 's' => 'ключевая фраза', 'year' => 2013, ) );

Порядок и пагинация

Для установления порядка вывода результатов в WP_Query используются следующие параметры:

order — DESC для сортировки по убыванию (по умолчанию) или ASC для сортировки по возрастанию orderby — поля, по которым производить сортировку, например (список не полный): date — по дате публикации (по умолчанию) ID — по уникальному идентификатору записи title — по заголовку записи rand — в случайном порядке comment_count — по количеству комментариев post__in — в соответствии с заданным массивом

Для пагинации в WP_Query используются всего два основных параметра:

posts_per_page — количество записей на каждую страницу paged — номер страницы

Например, получить три записи, отсортированные по заголовку в порядке возрастания:

$query = new WP_Query( array( 'order' => 'ASC', 'orderby' => 'title', 'posts_per_page' => 3, ) );

Этот же запрос со следующими тремя записями:

$query = new WP_Query( array( 'order' => 'ASC', 'orderby' => 'title', 'posts_per_page' => 3, 'paged' => 2, ) );

Кстати, чтобы получить все записи, можно указать -1 в качестве параметра posts_per_page. Делать это не желательно, поскольку записей может оказаться больше чем вы ожидаете, и серверу может не хватить памяти для их обработки и хранения.

Так же следует отметить, что прилепленные записи (sticky posts) добавляются автоматически в начало возвращаемых результатов WP_Query. Если вы хотите получить результаты без учёта прилепленных записей, воспользуйтесь параметром ignore_sticky_posts.

Для запроса записей по мета-данным (произвольным полям) или терминам, в WP_Query существуют два основных параметра: meta_query и tax_query. О том, как ими пользоваться мы расскажем в отдельной статье.

Использование WP_Query в темах и плагинах

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

Рассмотрим простую ситуацию:

// Основной цикл while ( have_posts() ) : the_post(); the_title(); // вывести заголовок // Вторичный цикл, например схожие статьи $related = new WP_Query( ... ); while ( $related->have_posts() ) : $related->the_post(); the_title(); // заголовок схожей статьи endwhile; endwhile;

В первом обращении функция the_title() выведет заголовок статьи из нашего основного цикла, а второе обращение — из вторичного цикла, хотя функция одна и та же. За это отвечает вызов метода the_post(), который не только делает «шаг в цикле», но и готовит глобальную переменную $post для работы с функциями the_title(), the_content() и прочими.

Именно поэтому, если слегка изменить наш код:

// Основной цикл while ( have_posts() ) : the_post(); the_title(); // вывести заголовок // Вторичный цикл, например схожие статьи $related = new WP_Query( ... ); while ( $related->have_posts() ) : $related->the_post(); the_title(); // заголовок схожей статьи endwhile; // Снова заголовок. в чём ошибка? the_title(); endwhile;

Мы получаем, на первый взгляд, совершенно непредсказуемый результат. Третий вызов функции the_title() выведет заголовок последней записи из вторичного цикла, несмотря на то, что вызов функции находится за пределами этого цикла.

Дело в том, что вызов the_post() изменил нашу глобальную переменную $post для работы с данными вторичного цикла, а после завершения цикла мы так и не вернули данные на свои места. В нашем случае это вполне очевидно, но что если после блока со схожими записями у нас располагается блок комментариев, или блок «поделиться»?

Функция wp_reset_postdata()

Функция wp_reset_postdata() устанавливает глобальную переменную $post в её исходное значение: текущая запись основного цикла. Использовать данную функцию следует сразу же после завершения нашего вторичного цикла:

// Основной цикл while ( have_posts() ) : the_post(); the_title(); // вывести заголовок // Вторичный цикл, например схожие статьи $related = new WP_Query( ... ); while ( $related->have_posts() ) : $related->the_post(); the_title(); // заголовок схожей статьи endwhile; // Вернуть $post в исходное значение wp_reset_postdata(); // Всё ок! the_title(); endwhile;

Поэтому при использовании вторичных циклов в ваших темах и плагинах не забывайте возвращать глобальную переменную $post в её исходное значение. А если вы изменили глобальную переменную $wp_query (что делать не рекомендуется), например с помощью функции query_posts(), её можно вернуть в исходное значение с помощью функции wp_reset_query().

Пример простого плагина

Для полноценного примера, предлагаем рассмотреть простой плагин, который добавляет блок с пятью последними записями к содержимому каждой статьи:

<?php /** * Plugin Name: Append Latest Posts to Content */ function my_append_latest_posts( $content ) { $query = new WP_Query( array( 'posts_per_page' => 5, 'post__not_in' => array( get_the_ID() ), ) ); if ( ! $query->have_posts() ) return $content; $content .= '<h3>Свежие записи</h3>'; $content .= '<ul>'; while ( $query->have_posts() ) : $query->the_post(); $content .= sprintf( '<li><a href="%s">%s</a></li>', esc_url( get_permalink() ), get_the_title() ); endwhile; $content .= '</ul>'; // Не забываем wp_reset_postdata(); return $content; } add_action( 'the_content', 'my_append_latest_posts' );

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

Последние записи

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

После того, как вы освоили основы работы с классом WP_Query, мы советуем ознакомиться с его остальными методами и переменными, например get_query_var(), get_queried_object(), $found_posts, $query_vars и другие. Если вам интересно узнать, как именно работает WP_Query, загляните в файл wp-includes/query.php.

Если у вас возникли вопросы при работе с WP_Query, оставьте комментарий и мы обязательно вам ответим.

rss