16

I am building a section on a site where I am merging two different post types into one loop, and then displaying them randomly. The problem is, I'm having a hard time finding a way to limit the amount of posts per type.

Here's what I've tried:

  • One query with multiple post types can be achieved with an array:

    $args = array( 'post_type' => array( 'photos', 'quotes' ), ...
    

    ... but cannot limited to a certain number of posts per type.

  • Merging two query argument arrays before running WP_Query on it:

    $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;
    // Also tried array_merge( $photos, $quotes );
    

    No luck on this. What happens is the latter variable $quotes overwrites $photos and only shows the quotes.

  • Merging two WP_Query objects together through typecasting:

    $photos_query = new WP_Query( $photos );
    $quotes_query = new WP_Query( $quotes );
    $result = (object)array_merge( (array)$photos_query, (array)$quotes_query );
    

... and so on.

I could probably use an SQL query straight to the database, but I need to be able to combine these two separate post types for one loop, arranged randomly, AND limited to a certain amount of posts per type.

Thanks for your help!

2 Answers 2

21

One way is to customize the SQL query executed using posts_clauses or other such filters. To find them search for posts_clauses in "wp-includes/query.php" & see the series of filters just before this line. These together are capable of customizing any part of the query

Another thing you can do is manually merge the queried posts in the objects

$photos_query = new WP_Query( $photos );
$quotes_query = new WP_Query( $quotes );
$result = new WP_Query();

// start putting the contents in the new object
$result->posts = array_merge( $photos_query->posts, $quotes_query->posts );

// here you might wanna apply some sort of sorting on $result->posts

// we also need to set post count correctly so as to enable the looping
$result->post_count = count( $result->posts );
5
  • Your second solution (without the SQL) did the trick! Now I have complete control over what is going into that final query before going into the loop. Thanks for your help! Nov 5, 2012 at 8:34
  • 1
    The first one is difficult but more efficient(in second there are still 2 database queries). I would say it comes down to personal preference Nov 5, 2012 at 8:54
  • Would be extremely interested in a way to accomplish the first solution! The filters needed, etc. Does this call for a UNION of some sort in the sql for each post_type? Oct 27, 2017 at 22:07
  • @SolomonClosson this filter can help- codex.wordpress.org/Plugin_API/Filter_Reference/posts_clauses Oct 30, 2017 at 13:45
  • Thanks for this. Helps a lot. Should be more obvious in the main WP docs.
    – Khom Nazid
    Apr 10, 2022 at 15:29
8

@mridual aggarwal your answer is very very good but unfortuntly it is not really combining the 2 wp_query it is only shows the posts from both in arrange i mean 5 posts from the first & 5 from the second but not sorted all in one so i have this solution & it exactly achieved the goal for my self at least

<?php
$term = get_term_by( 'slug', get_query_var( 'tag' ), "post_tag" );
$tagslug = $term->slug;
$post_types = get_post_types('','names');
?>
<?php
//first query
$blogposts = get_posts(array(
    'tag' => $tagslug, //first taxonomy
    'post_type' => $post_types,
    'post_status' => 'publish',
    ));
//second query
$authorposts = get_posts(array(
    'bookauthor' => $tagslug, //second taxonomy
    'post_type' => $post_types,
    'post_status' => 'publish',
    ));
$mergedposts = array_merge( $blogposts, $authorposts ); //combine queries

$postids = array();
foreach( $mergedposts as $item ) {
$postids[]=$item->ID; //create a new query only of the post ids
}
$uniqueposts = array_unique($postids); //remove duplicate post ids

$posts = get_posts(array(
        //new query of only the unique post ids on the merged queries from above
    'post__in' => $uniqueposts,  
    'post_type' => $post_types,
    'post_status' => 'publish',
    ));
foreach( $posts as $post ) :
setup_postdata($post);
?>
// posts layout
<?php endforeach; ?>
<?php wp_reset_postdata();?>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.