Retrieving 3 latest post from each of 5 different custom post types

I have 5 different custom post types. I am showing 15 latest post from them on my home page using following query:

$query = new WP_Query( array (
             'posts_per_page'   => 15,
             'post_type' => array ( 'cpt1', 'cpt2', 'cpt3', 'cpt4', 'cpt5' ) 
          )
 );

It works fine, shows latest 15 posts from these 5 custom post types.
But problem is, there are too many updates on cpt1 and cpt3 (around 8-10 posts per day on each post type). So on home page, I rarely find posts from cpt2/4/5.

So I want to show latest 3 posts from each post type (total 15 posts) using date as order by (sorting). So 3 posts from each post type will be visible and sorted based on date among all 5 post types. But I could not find any good solution for this.

What came so far in my mind is, running 5 queries and saving them to an array, and then sort them.

Is there anyway I can do this using only one query, instead of 5 queries?

Solutions Collecting From Web of "Retrieving 3 latest post from each of 5 different custom post types"

I am not sure, if this is the most efficient option or not, but I have doen it in following way:

  1. I have stored 5 separate query using get_posts and stored them in a single array
  2. I had to flatten the array, since it was multidimensional. Then used usort using post_date to get the latest post
  3. I have saved this sorted data using Transient API, to minimize database call.

Here is the code:

function delete_front_page_query_results() {
    delete_transient('post_data');

    $query_cpt1 = array (
            'posts_per_page'   => 3,
            'post_type' => 'cpt1'
            );
    $query_cpt2 = array (
            'posts_per_page'   => 3,
            'post_type' => 'cpt2'
            );
    $query_cpt3 = array (
            'posts_per_page'   => 3,
            'post_type' => 'cpt3'
            );
    $query_cpt4 = array (
            'posts_per_page'   => 3,
            'post_type' => 'cpt4'
            );
    $query_cpt5 = array (
            'posts_per_page'   => 3,
            'post_type' => 'cpt5'
            );

    $query_results[] = get_posts($query_cpt1);
    $query_results[] = get_posts($query_cpt2);
    $query_results[] = get_posts($query_cpt3);
    $query_results[] = get_posts($query_cpt4);
    $query_results[] = get_posts($query_cpt5);

    //flattening three dimentional array to two dimensonal array
    $flatten_array =array();
    foreach ($query_results as $data) {
            foreach($data as $flatten_data) {
                 $flatten_array[] = $flatten_data;
            }
    }

    function cpt_array_sort($a, $b) {
            return strtotime($b->post_date) - strtotime($a->post_date);
    }
    usort($flatten_array, 'cpt_array_sort');

    //setting transient with the array
    set_transient ( 'post_data', $flatten_array, 365*24*60*60);
}
add_action('publish_post', 'delete_front_page_query_results);

There is no way to do this in a single query. You must separate it out into multiple queries as SQL commands are not built to handle this type of processing, and thus neither is WordPress’s Query API.