WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I have three custom post type:

  • books
  • magazine
  • videos

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

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

I used a query post like this:

query_posts( array(
    'post_type' => array(
'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 :)

share|improve this question

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)
(SELECT ID FROM {$wpdb->posts} WHERE post_type = 'magazines' AND post_status = 'publish' LIMIT 2)
(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.

share|improve this answer

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(
    '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
share|improve this answer
Thanks dude, it's a great solution – rodboc Jan 11 '13 at 3:31
But you run four queries to do it and get_posts does a lot of work on the PHP side as well. You should at least reduce the workload by requesting only IDs as here: wordpress.stackexchange.com/a/99619/21376 – s_ha_dum Sep 2 '13 at 16:49

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

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