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— тип записи, по умолчаниюpostpost_status— статус записи, по умолчаниюpublishp— идентификатор записи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, оставьте комментарий и мы обязательно вам ответим.



