Объединение запросов с разными аргументами для разных типов записей

5 нояб. 2012 г., 09:31:58
Просмотры: 32.1K
Голосов: 16

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

Вот что я пробовал:

  • Один запрос с несколькими типами записей можно сделать с помощью массива:

    $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-запрос напрямую к базе данных, но мне необходимо иметь возможность объединить эти два отдельных типа записей в один цикл, расположить их в случайном порядке И ограничить определенным количеством записей для каждого типа.

Спасибо за помощь!

0
Все ответы на вопрос 2
5
21

Один из способов — настроить 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 );
5 нояб. 2012 г. 10:04:00
Комментарии

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

Andy Merskin Andy Merskin
5 нояб. 2012 г. 10:34:46

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

Mridul Aggarwal Mridul Aggarwal
5 нояб. 2012 г. 10:54:14

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

Solomon Closson Solomon Closson
28 окт. 2017 г. 01:07:08

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

Mridul Aggarwal Mridul Aggarwal
30 окт. 2017 г. 15:45:51

Спасибо. Очень полезно. Должно быть более заметно в основной документации WP.

Khom Nazid Khom Nazid
10 апр. 2022 г. 18:29:46
0

@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();?>
28 окт. 2013 г. 15:26:29