Получение и вывод записей/постов WordPress - WP_Query и get_posts()

Категория: WordPress

Параметры запроса постов и таксономий WordPress. Примеры фильтров и способов рендеринга постов, категорий и кастомных таксономий.

Для каждой страницы ядро WordPress формирует запрос к БД для получения записей на основе параметров GET запроса. Параметры запроса постов устанавливаются в глобальном объекте $wp_query. При необходимости, вы можете модифицировать этот базовый запрос иди же сформировать новый объект запроса к БД - WP_Query.

Внимание!

Не вызывайте ф-цию get_posts() и не используйте класс WP_Query непосредственно в файле functions.php! Получите мучительно долгую отладку неработающего запроса. Используйте запросы WP_Query внутри хуков или в самих шаблонах.

Внимание!

Никогда не используйте функцию query_posts()! Эта ф-ция используется ядром WP для формирования основного запроса на получение постов по GET параметрам URL/ЧПУ. Вызвав эту ф-цию, вы замените глобальный объект основного запроса - $wp_query. Для дополнительных кастомных запросов всегда используйте WP_Query или обертку get_posts().

Если вы все же изменили глобальную переменную $wp_query (что не рекомендуется!) с помощью функции query_posts(), верните ее в исходное состояние с помощью wp_reset_query(). И убедитесь, что вы делаете все правильно..

Отладка

SQL запрос объекта WP_Query хранится в свойстве request:

die($query->request);

Изменение базового запроса

Задать параметры основного/базового запроса глобальный объект запроса вы можете только через хук  pre_get_posts:

add_action('pre_get_posts', 'my_alter_category_wp_query');
function my_alter_category_wp_query(WP_Query $query) {
    if (!is_category()) return;
    $query->set('posts_per_page', 20);
}

Параметры GET запроса


Использование WP_Query для получения записей

Сразу приведу пример полного цикла вывода записей/постов:

<?php

// 1. Формируем параметры запроса
$args = [];
 
// 2. Выполняем дополнительный запрос на получение записей (похожие, последние, популярные и т.д.)
$query = new WP_Query($args);
 
// 3. Проверяем наличие результатов и выводим записи
if ($query->have_posts()) {

  // Цикличный обход записей
  while ($query->have_posts()) {

    // "Извлечение" каждой последующей записи
    $query->the_post();

    // вывод данных каждой записи...

  }
}

// 4. Восстановление данных и параметров оригинального запроса!
wp_reset_postdata();
Примечание

Ф-ция wp_reset_postdata() восстанавливает глобальную переменную $post из глобального объекта $wp_query:

$GLOBALS['wp_query']->reset_postdata();
public function reset_postdata()
{
  if (!empty($this->post)) {
    $GLOBALS['post'] = $this->post;
    $this->setup_postdata($this->post);
  }
}

Далее подробно рассмотрим детали каждого этапа и дополнительных возможностей.

Методы получения записей

Получение одной записи/поста по id или slug:

$post = get_post($postid = 14);
$query = new WP_Query(['p' => 14]); // ['name' => 'url-slug']
$query->the_post();
Примечание

Функция get_post() - это обертка над WP_Post, она принимает дополнительные параметры $output и $filter:

$post = get_post($postId, $output = 'OBJECT', $filter = 'raw');
$output: OBJECT, ARRAY_A, ARRAY_N
$filter: raw

Сформировать новый запрос для получения записей/постов  WP_Query:

$query_args = ['post_status' => 'publish', 'paged' => 2];
$query = new WP_Query($query_args = []);

Получение записей/постов используя функцию get_posts():

$posts = get_posts(['paged' => 2]);
Примечание

Функция get_posts() - это просто обертка над WP_Query. Принимает массив с теми же параметрами для фильтрации постов. В отличие от query_posts(), она не вмешивается в глобальный запрос $wp_query, а создает отдельный экземпляр класса WP_Query. Также ф-ция get_posts() устанавливает некоторые дефолтные значения:

$query_args = [
  'post_status' => 'publish', // или inherit для attachments
  'post_type' => 'post',
  'numberposts' => 5,         // он же posts_per_page
  'category' => 0,
  'orderby' => 'date',
  'order' => 'DESC',
  'suppress_filters' => true,
];

// ЭТИ ПАРАМЕТРЫ УСТАНАВЛИВАЮТСЯ СТАТИЧНО, БЕЗ ВОЗМОЖНОСТИ ИЗМЕНЕНИЯ
$query_args['ignore_sticky_posts'] = true;
$query_args['no_found_rows'] => true;

Фильтры записей

Основные фильтры и параметры запроса

$posts = new WP_Query([
  'ignore_sticky_posts' => 'true', // не закреплять/приоритезировать записи (см. 'caller_get_posts')
  'no_found_rows' => true,         // отключить подсчет всех найденных записей

  'post_type' => 'post',           // post, page, attachment, revision, nav_menu_item, any. Default: post
  'post_status' => 'publish',

  'category_name' => 'reviews',    // фильтр по slug

  'post__in' => [1,2,3],           // посты с указанными ID ('include')
  'post__not_in' => [4,5],         // исключить ID указанных постов ('exclude')

  'meta_key' => 'some_meta_field', // сортировка по заданному meta-полю
  'orderby' => 'meta_value_num',   // meta_value,  meta_value_num
  'order' => 'ASC',                // ASC, DESC

  'paged' => 7,                    // N страницы архива ('page' - N страницы главной)
  'posts_per_page' => 20,          // число записей на страницу ('numberposts')
]);
Примечание

paged - Номер страницы пагинации. Показывает посты, которые в обычном режиме должны были быть показаны на странице пагинации Х. Переписывает параметр posts_per_page.

page(число) - Номер для статической домашней страницы. Показывает записи, которые в обычном режиме должны были быть показаны на странице пагинации Х главной статической странице (front page).

Примечание

Примечание к типам постов:

attachment     при получении вложения нужно установить: post_status=inherit
nav_menu_item  элемент меню навигации
any            все типы кроме ревизий и записей с параметром exclude_from_search=true

Фильтр по дереву (иерархии)

post_parent ID           - получить дочерние страницы для указанной страницы
post_parent__in [ID]     - получить дочерние для нескольких ID страниц указанных в массиве
post_parent__not_in [ID]

Фильтр по категориям

category_name 'slug,slug2' - найти записи по slug в любой из категорий
cat 'ID,-ID'               - '6,7,-12' из 6 или 7 категории, но игнорировать посты из 12-ой
category__in [ID]          - найти записи в любой из категорий (аналог `cat`)
category__not_in ID|[ID]   - посты, которые не входят в указанные категории
category__and [ID]         - найти записи, которые состоят во всех указанных категориях
Примечание

При использовании фильтра post_in, WordPress будет извлекать "прикрепленные" записи, даже если их ID нет в массиве! Чтобы отключить вывод "прилепленных" записей - передайте параметр ignore_sticky_posts.

Фильтр по тегам (меткам)

tag 'SLUG,SLUG'
tag_id [ID]
tag__and [ID]
tag__in [ID]
tag__not_in [ID]
tag_slug__and [SLUG]
tag_slug__in [SLUG]

meta_query - фильтр по мета данным

Параметр meta_query представляет массив вложенных параметров фильтрации записей/постов по мета данным.

$posts = get_posts([
  'relation' => 'OR', // по умолчанию AND
  'meta_query' => [
    [
      'key'   => 'название параметра',
      'value' => 'значение',
      'compare' => '=, !=, >, >=, <, <=, LIKE, NOT LIKE, IN, NOT IN, BETWEEN, NOT BETWEEN, EXISTS, NOT EXISTS',
      'type'    => 'NUMERIC, BINARY, CHAR, DATE, DATETIME, DECIMAL, SIGNED, TIME, UNSIGNED'
    ],
    [ // только посты с изображениями
        'key' => '_thumbnail_id',
        'compare' => 'EXISTS' // `compare` можно опустить
    ],
  ]
]);

tax_query - фильтр по таксономиям

https://codex.wordpress.org/Class_Reference/WP_Query#Taxonomy_Parameters

Фильтр по категории кастомных постов:

$posts = get_posts([
  'post_type' => 'advert',
  'tax_query' => [ // (i) для одного условия фильтрации
    'taxonomy' => 'advert-category',
    'field' => 'slug',   // 'tax_id', 'term_id', 'name', 'slug', 'term_taxonomy_id'
    'terms' => 'realty', // ID, string, array
    'operator' => 'NOT IN'
  ]
]);

Фильтр по категории и тегам:

$posts = get_posts([
  'post_type' => 'advert',
  'tax_query' => [
    [
      'taxonomy' => 'advert-category',
      'field' => 'slug',   // 'tax_id', 'term_id', 'name', 'slug', 'term_taxonomy_id'
      'terms' => 'realty', // ID, string, array
      'operator' => 'NOT IN'
    ], [
      'taxonomy' => 'advert-tag',
      'field' => 'tax_id',
      'terms' => [14, 15],
      'operator': 'IN'
    ]
  ]
]);

Примеры запросов

Получить дочерние страницы для текущей страницы:

$query = get_posts(['post_type' => 'page', 'post_parent' => get_the_ID()]);

Всего доступно постов:

$wp_query->found_posts;

Добавить фильтр запроса "посты только с изображениями":

add_action('pre_get_posts', 'korsun_home_get_carousel_posts_with_images_only');
function korsun_home_get_carousel_posts_with_images_only(WP_Query $query) {
    if (!is_front_page()) return;
    if (!in_array($query->query_vars['post_type'], ['news', 'advert'])) return;

    $query->set('meta_query', [
        [
            'key' => '_thumbnail_id',
            'compare' => 'EXISTS'
        ],
    ]);
}

Получить изображения:

$args = array(
  'post_type' => 'attachment',
  'post_status' => 'inherit',
  'post_mime_type' => 'image/jpeg',
  'fields' => 'id=>parent',
  'posts_per_page' => -1,
);

Вывод записей

Цикл вывода записей


Примечание

Используйте wp_reset_postdata() для "сброса" значения глобальной переменной $post к состоянию основного запроса, после завершения любых циклов обхода записей! Поскольку каждый the_post() заменяет глобальные переменные, вы можете обнаружить, что на странице записи, например, переменная $post содержит не основной пост, а какой-то другой. Который скорее всего будет последним постом из какого-то цикла.

Дополнительные/мета поля

post_meta

Получить мета поля:

get_post_meta($post->ID, 'meta_field', $is_single_meta_field = false);

Получить ссылку на основное изображение поста:

$postImgUrl = wp_get_attachment_url(get_post_thumbnail_id($post->ID)); // вернет ссылку
$postImg = wp_get_attachment_image_src(get_post_thumbnail_id($post->ID), 'full'); // вернет массив
Array
(
    [0] => http:/site.lcl/blog/wp-content/uploads/2016/03/image.png
    [1] => 132
    [2] => 116
    [3] => 
)

WP_Query: query_vars

Получить объект (пост или таксономия) запроса для текущего маршрута/ЧПУ:

get_queried_object();
get_queried_object()->name
get_queried_object()->slug

Получить параметры запроса для текущей страницы:

$wp_query->query_vars;

Получить параметр запроса WP_Query текущей страницы (поста или записей раздела):

$cat_name = get_query_var('category_name', $default = '');

Получить объект параметров основного GET запроса текущей страницы. Параметры формируются в зависимости от страницы - это может быть набор параметров для получения поста на странице поста, или параметры получения списка постов на страницах категории/архива.

/** @var WP_Query $wp_query */
/** @var WP_Term $term */
$term = $wp_query->get_queried_object();
$term = get_queried_object(); // это просто обертка над предыдущей ф-цией
object WP_Term:
  'term_id' => int 119
  'name' => string 'Обзоры'
  'slug' => string 'reviews'
  'term_group' => int 0
  'term_taxonomy_id' => int 119
  'taxonomy' => string 'category'
  'description' => string 'Обзоры техники и технологий'
  'parent' => int 0
  'count' => int 263
  'filter' => string 'raw'
  'cat_ID' => int 119
  'category_count' => int 263
  'category_description' => string 'Обзоры техники и технологий'
  'cat_name' => string 'Обзоры'
  'category_nicename' => string 'reviews'
  'category_parent' => int 0

Пример получения название категории для архива:

get_queried_object()->name

setup_postdata($post)

Извлекает данные поста и формирует глобальные переменные поста. Использует переданную переменную $post и глобальный объект запроса $wp_query. Создаются следующие глобальные переменные: $id, $authordata, $currentday, $currentmonth, $page, $pages, $multipage, $more, $numpages.

Функция работает только при условии, что вы передаете ей глобальный объект поста с именем $post. Если у вас объект поста находится в другой переменной - установите $post = $myWpPost, после чего передайте $post в эту ф-цию. Я не очень понимаю как работает эта ф-ция, если передавать ей ID поста вместо $post. 

$found_posts - количество найденных записей

$query_vars - аргументы запроса

Получение отдельных полей поста (post_type, post_title, post_status, post_content..):

$context = ''; // Фильтр значения по применению (raw, edit, db, display, attribute, js)
get_post_field($field, $post_id, $context = 'display');

См. поля $field: http://codex.wordpress.org/Database_Description#Table:_wp_posts

Источники:

  • Свойства и методы WP Query (условные "теги") - https://wp-panda.com/mastering-wp_query-properties-and-methods/
  • WP Query фильтр по таксономиям (taxonomy, terms) - https://wp-panda.com/wp_query-arguments-taxonomies/

#worspress, #search, #filter