Limit the post for differents custom post type in the same wp_query

I have three custom post type:

  • books
  • magazine
  • videos

Now i want to limit the number of post for custom post type, for example:

Read More
  • books => 3 post
  • magazine => 2 post
  • videos => 1 post

I used a query post like this:

query_posts( array(
    'post_type' => array(
    'books',
    'magazine',
    'videos'
),
'paged' => $paged,
'posts_per_page' => 6, 
));
$counter = 1;
if (have_posts()) :
    while (have_posts()) : the_post();  
if (($counter == 2) || ($counter == 3) || ($counter == 4)) {
        $div = 'alpha';
    } elseif(($counter == 6)) {
        $div = 'omega';
    } else {
        $div = '';
    }

The problems is i cant limit the numbers by custom post type.
Any idea?

Thank you 🙂

Related posts

Leave a Reply

2 comments

  1. I hate writing “you can’t do that” answers, but you can’t. That is the strict answer to your question about whether you can do this with a single WP_Query. You can’t limit post type counts individually in the same query using WP_Query (You are actually using query_posts. Please don’t. It is not the right tool for secondary loops.)

    Even in raw SQL you have to write separate queries and UNION them together, which is how I’d approach this.

    $sql = "(SELECT ID FROM {$wpdb->posts} WHERE post_type = 'books' AND post_status = 'publish' LIMIT 3)
    UNION ALL
    (SELECT ID FROM {$wpdb->posts} WHERE post_type = 'magazines' AND post_status = 'publish' LIMIT 2)
    UNION ALL
    (SELECT ID FROM {$wpdb->posts} WHERE post_type = 'videos' AND post_status = 'publish' LIMIT 1)";
    // be sure to add any other conditions you need
    $ids = $wpdb->get_col($sql);
    

    Then run those $ids through a new WP_Query to get the post objects you need for a proper Loop.

    You could even break the SQL into a pattern and reuse it. Something like…

    $sqlpat = "(SELECT ID FROM {$wpdb->posts} WHERE post_type = '%s' AND post_status = 'publish' LIMIT %d)";
    $sql = '('.sprintf($sqlpat,'books',3).') UNION ALL ('.sprintf($sqlpat,'magazines',2).') UNION ALL ('.sprintf($sqlpat,'videos',1).')';
    

    Assuming I didn’t make a mistake (the code is not tested), you should then have what you want– three post types each with a particular count. They may not come out in the order you want so you may have to sort them in PHP, or build an even trickier SQL query.

  2. You can do this by merging queries:

    $q1 = get_posts(array(
        'post_type' => 'books',
        'posts_per_page' => 3
    ));
    
    $q2 = get_posts(array(
        'post_type' => 'magazines',
        'posts_per_page' => 2
    ));
    
    $q3 = get_posts(array(
        'post_type' => 'videos',
        'posts_per_page' => 1
    ));
    
    $merged = array_merge( $q1, $q2, $q3 );
    
    $post_ids = array();
    foreach( $merged as $item ) {
        $post_ids[] = $item->ID;
    }
    
    $unique = array_unique($post_ids);
    
    $args = array(
        'post_type' => array(
        'books',
        'magazine',
        'videos'
        ),
        'post__in' => $unique,
        'post_status' => 'publish',
        'posts_per_page' => 6
    );
    
    $the_query = new WP_Query( $args );
    
    while ( $the_query->have_posts() ) : $the_query->the_post();
    // post stuff here
    endwhile;