How to query different post types in specific order?

I have 3 posts types, articles, news and tips. On the home page I want to query 20 posts in this order:

article, article, news, news, tip, ...// same order again until 20

If I use a custom query like so:

Read More
$query = new WP_Query(array(
  'post_type' => array('articles', 'news', 'tips'),
  'posts_per_page' => 20,
));

I get 20 items but how to order them? Would it be possible to make 3 different queries and then merge the results?

Related posts

Leave a Reply

2 comments

  1. You definitely could use three different queries and then merge them.

    // Query 7 items per Custom Post Type.
    // A, A, N, N, T, T will result in 8 x A, 6 x N and 6 x T.
    $atricles = new WP_Query( 'post_type=article&posts_per_page=8' ); // A
    $news     = new WP_Query( 'post_type=news&posts_per_page=6' ); // N
    $tips     = new WP_Query( 'post_type=tips&posts_per_page=6' ); // T
    
    // Assign new array keys to the queried posts
    $stp = 0; $key = 0; $arr = array();
    foreach ( $articles->posts as $post_obj ) { $key++; $arr[$stp + $key] = $post_obj; if ( $key === 2 ) { $stp += 6; $key = 0; } }
    $articles->posts = $arr;
    
    $stp = 2; $key = 0; $arr = array();
    foreach ( $news->posts as $post_obj ) { $key++; $arr[$stp + $key] = $post_obj; if ( $key === 2 ) { $stp += 6; $key = 0; } }
    $news->posts = $arr;
    
    $stp = 4; $key = 0; $arr = array();
    foreach ( $tips->posts as $post_obj ) { $key++; $arr[$stp + $key] = $post_obj; if ( $key === 2 ) { $stp += 6; $key = 0; } }
    $tips->posts = $arr;
    
    // Modify one object to contain all Posts
    // Use the + array union operator to preserve the array keys
    $articles->posts = $articles->posts + $news->posts + $tips->posts;
    
    // Sort the array by keys.
    ksort( $articles->posts );
    
    // Don't forget to "reset" the post_count variable in the modified object.
    // This way you will have 20 posts instead of the queried 8 (in this case).
    $articles->post_count += $news->post_count;
    $articles->post_count += $tips->post_count;
    
    // Use the modified result object for the loop
    while ( $articles->has_posts() ):
      $articles->the_post();
    
      // Do your stuff with it :-)
    endwhile;
    

    This may look like a very odd way to do this, but this way you can use the loop and preserve the option to use pagination. Although a direct query to the database can be quicker I guess.

  2. You could try a modified version of this answer :

    add_filter('posts_orderby', 'custom_posts_orderby');
    
    $query = new WP_Query(array(
      'post_type' => array('articles', 'news', 'tips'),
      'posts_per_page' => 20,
    ));
    
    remove_filter('posts_orderby', 'custom_posts_orderby');
    

    where

    function custom_posts_orderby($orderby) {
        global $wpdb;
        return $wpdb->posts .".post_type ASC,".$wpdb->posts .".post_date DESC";
    }
    

    So the posts are first ordered by post_type (asc) and then by post_date (desc).