WP_Query
— это один из самых важных API в WordPress, ведь именно с помощью WP_Query
мы имеем возможность получать записи, страницы и произвольные типы из базы данных. В этой статье мы рассмотрим основные принципы работы с классом WP_Query
и примеры его использования в плагинах и темах.
- Что такое WP_Query
- Параметры WP_Query
- Категории (рубрики)
- Метки
- Записи, страницы и произвольные типы данных
- Авторы
- Поиск по ключевым словам и датам
- Порядок и пагинация
- Работа с мета-данными и таксономией
- Использование WP_Query в темах и плагинах
Что такое WP_Query
WP_Query
— это класс, который позволяет разработчикам получать доступ к записям, страницам и произвольным типам данных в WordPress. При этом разработчикам не нужно самостоятельно писать сложные SQL запросы в базу данных, ведь WP_Query
сделает это всё за нас.
Ниже приведён самый простой запрос с помощью класса WP_Query
:
$query = new WP_Query( array( 'category_name' => 'news' ) );
Таким образом WordPress сделает запрос в базу данных, чтобы получить наши записи из категории «news». Результаты запроса будут храниться в объекте $query
, с которым мы будем работать с помощью специальных методов, наверняка знакомых вам:
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
— год, например 2013monthnum
— порядковый номер месяца, от 1 до 12w
— номер недели, от 0 до 53day
— день, от 1 до 31day
— день, от 1 до 31hour
— час, от 0 до 23minute
— минута, от 0 до 60second
— секунда, от 0 до 60m
— год и месяц слитно, например 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
, оставьте комментарий и мы обязательно вам ответим.