You can create your own function to return posts objects from different categories using the get_object_in_term()
function with some customization on the sql request. This function has only one filter (order).
I know that you seem to want a one time WP_Query, but it can give you some idea.
In this example, I directly set an array of term_id and the args (you can add the order parameter, loop through the term_ids instead of directly set the first parameter of the custom function (I needed to randomize each category).
$term_ids = array(15,11,24);
$taxonomies="product_cat";
$args = array(
'global_limit'=>25,
'posts_per_page'=>1
);
foreach ($term_ids as $term_id){
$terms_object = get_objects_in_term_with_limit( $term_id, $taxonomies, $args ) ;
foreach ($terms_object as $object){
$post = get_post($object);
$post_object[] = array('ID'=>$post->ID, 'post_title'=> $post->post_title, 'term_id'=>$term_id);
}
}
echo json_encode($post_object);
function get_objects_in_term_with_limit( $term_ids, $taxonomies, $args = array() ) {
global $wpdb;
if ( ! is_array( $term_ids ) ) {
$term_ids = array( $term_ids );
}
if ( ! is_array( $taxonomies ) ) {
$taxonomies = array( $taxonomies );
}
foreach ( (array) $taxonomies as $taxonomy ) {
if ( ! taxonomy_exists( $taxonomy ) ) {
return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) );
}
}
$defaults = array( 'order' => 'ASC', 'posts_per_page'=>5, 'global_limit'=>25 );
$args = wp_parse_args( $args, $defaults );
$order = ( 'desc' == strtolower( $args['order'] ) ) ? 'DESC' : 'ASC';
$global_limit="LIMIT ". $args['global_limit'];
$limit="BY RAND() LIMIT ". $args['posts_per_page'];
$term_ids = array_map('intval', $term_ids );
$taxonomies = "'" . implode( "', '", array_map( 'esc_sql', $taxonomies ) ) . "'";
$term_ids = "'" . implode( "', '", $term_ids ) . "'";
$object_ids = $wpdb->get_col("(SELECT tr.object_id FROM $wpdb->term_relationships AS tr
INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
WHERE tt.taxonomy IN ($taxonomies) AND tt.term_id IN ($term_ids)
ORDER BY tr.object_id $order $global_limit)
ORDER $limit");
if ( ! $object_ids ){
return array();
}
return $object_ids;
}
Hope it helps and that saves your time.