ГлавнаяРазноеОсновы WP_Query в WordPress

Основы WP_Query в WordPress

WP_Query — это один из самых важных API в WordPress, ведь именно с помощью 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 — год, например 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 используются следующие параметры:

  • orderDESC для сортировки по убыванию (по умолчанию) или 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, вы легко можете реализовать блок схожих записей, популярных записей, записей с наибольшим количеством комментариев и многое другое.


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

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

Подписаться на рассылку

Подписаться → Подпишитесь на бесплатную рассылку журнала WP Magazine и получайте новости, события, подборки тем и плагинов, уроки, советы и многое другое в мире WordPress!