Объединение запросов с разными аргументами для разных типов записей
Я создаю раздел на сайте, где объединяю два разных типа записей в один цикл с их случайным отображением. Проблема в том, что я не могу найти способ ограничить количество записей для каждого типа.
Вот что я пробовал:
Один запрос с несколькими типами записей можно сделать с помощью массива:
$args = array( 'post_type' => array( 'photos', 'quotes' ), ...
... но нельзя ограничить определенное количество записей для каждого типа.
Объединение двух массивов аргументов запроса перед выполнением WP_Query:
$photos = array( 'post_type' => 'photos', 'posts_per_page' => 15, 'orderby' => 'rand' ); $quotes = array( 'post_type' => 'quotes', 'posts_per_page' => 5, 'orderby' => 'rand' ); $args = $photos + $quotes; // Также пробовал array_merge( $photos, $quotes );
Это не сработало. Происходит то, что последняя переменная
$quotes
перезаписывает$photos
и показывает только цитаты.Объединение двух объектов WP_Query через приведение типов:
$photos_query = new WP_Query( $photos ); $quotes_query = new WP_Query( $quotes ); $result = (object)array_merge( (array)$photos_query, (array)$quotes_query );
... и так далее.
Я мог бы использовать SQL-запрос напрямую к базе данных, но мне необходимо иметь возможность объединить эти два отдельных типа записей в один цикл, расположить их в случайном порядке И ограничить определенным количеством записей для каждого типа.
Спасибо за помощь!

Один из способов — настроить SQL-запрос с помощью фильтров posts_clauses
или других подобных. Для этого найдите posts_clauses
в файле "wp-includes/query.php" и посмотрите на серию фильтров перед этой строкой. Вместе они позволяют кастомизировать любую часть запроса.
Другой вариант — вручную объединить полученные записи в объектах:
$photos_query = new WP_Query( $photos );
$quotes_query = new WP_Query( $quotes );
$result = new WP_Query();
// начинаем добавлять содержимое в новый объект
$result->posts = array_merge( $photos_query->posts, $quotes_query->posts );
// здесь можно применить сортировку к $result->posts
// также нужно правильно установить количество записей для корректной работы циклов
$result->post_count = count( $result->posts );

Ваше второе решение (без SQL) сработало! Теперь у меня есть полный контроль над тем, что попадает в итоговый запрос перед циклом. Спасибо за помощь!

Первое решение сложнее, но более эффективно (во втором всё ещё остаётся 2 запроса к базе данных). Я бы сказал, это вопрос личных предпочтений.

Был бы крайне заинтересован в способе реализации первого решения! Какие нужны фильтры и т.д. Потребуется ли здесь UNION
в SQL для каждого post_type?

@SolomonClosson этот фильтр может помочь - https://codex.wordpress.org/Plugin_API/Filter_Reference/posts_clauses

@mridual aggarwal ваш ответ очень-очень хороший, но, к сожалению, он не совсем объединяет 2 wp_query
, а просто показывает посты из обоих в порядке: 5 постов из первого и 5 из второго, но не сортирует все вместе. У меня есть решение, которое, по крайней мере для меня, точно достигает цели.
<?php
$term = get_term_by( 'slug', get_query_var( 'tag' ), "post_tag" );
$tagslug = $term->slug;
$post_types = get_post_types('','names');
?>
<?php
//первый запрос
$blogposts = get_posts(array(
'tag' => $tagslug, //первая таксономия
'post_type' => $post_types,
'post_status' => 'publish',
));
//второй запрос
$authorposts = get_posts(array(
'bookauthor' => $tagslug, //вторая таксономия
'post_type' => $post_types,
'post_status' => 'publish',
));
$mergedposts = array_merge( $blogposts, $authorposts ); //объединение запросов
$postids = array();
foreach( $mergedposts as $item ) {
$postids[]=$item->ID; //создание нового запроса только из ID постов
}
$uniqueposts = array_unique($postids); //удаление дубликатов ID постов
$posts = get_posts(array(
//новый запрос только с уникальными ID постов из объединенных запросов выше
'post__in' => $uniqueposts,
'post_type' => $post_types,
'post_status' => 'publish',
));
foreach( $posts as $post ) :
setup_postdata($post);
?>
// макет постов
<?php endforeach; ?>
<?php wp_reset_postdata();?>
