I cannot really see doing this than to run a couple of queries here, one per category. We will need to be clever here to avoid a lot of unnecessary work.
Lets look at the code; (which I will comment to ease the process of understanding)
// Get the categories. We will only get the category ID's to speed things up
$category_args = [
'fields' => 'ids',
];
$categories = get_categories ( $category_args );
// Check if we have categories to avoid bugs
if ( $categories ) {
// Define the variable to hold an array of posts not to duplicate
$do_not_duplicate = [];
// Define a variable to hold our posts
$posts_array = [];
foreach ( $categories as $cat_id ) {
// Setup our query arguments to get our posts
$args = [
'cat' => $cat_id,
'posts_per_page' => 1,
'post__not_in' => $do_not_duplicate,
'fields' => 'ids' // Only get post id's to increase performance
];
/**
* Lets use get_posts as we do not need the whole object and get_posts by default
* legally breaks pagination which makes the query faster, and it automatically
* ignore sticky posts and by default does not get modified by filters
*/
$q = get_posts( $args );
// Check if we have posts
if ( $q ) {
/**
* Now we need to add the post ID to the $do_not_duplicate array.
* We will also pass the posts in $q to $posts_array
* NOTE: you will need to rework this if you ever need more than one post per category
*/
$do_not_duplicate[] = $q[0];
$posts_array[] = $q[0];
}
} //endforeach $categories
// We can now run an instance of WP_Query to get the posts and query object
if ( $posts_array ) {
$final_args = [
'posts_per_page' => count( $posts_array ),
'post__in' => $posts_array,
'ignore_sticky_posts' => 1, // Ignore stickies
'no_found_rows' => true, // Skip pagination, remove if needed
];
$final_query = new WP_Query( $final_args );
var_dump( $final_query );
// Now we can run te loop and output our posts
if ( $final_query->have_posts() ) {
while ( $final_query->have_posts() ) {
$final_query->the_post();
the_title();
} //endwhile
wp_reset_postdata(); // NEVER EVER forget this line
} // endif $final_query->have_posts()
} // endif $posts_array
} // endif $categories
You can adjust, extend and modify it to suit your needs. Note, everything in the code has been setup to accommodate for one post per category only. You will need to alter how $do_not_duplicate
and $posts_array
are build if you are going to query more than one post per category