Figured it out!
It’s a little messy, and not as controllable as I would have liked – but its working, and the site for the client is a campaign landing page so will only be live for a few weeks/months anyway.
If anyone has a similar issue, of wanting to handle different WP_Query arguments from multiple Custom Post Types in the one loop, maybe this will help you out. IT IS VERY BESPOKE however, and I doubt much of it will make sense, but I tried to comment as much as I could.
I also ran into issues because I was using a plugin called WPML for translation into 3 different languages.
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1; // Get the page value
$filter = get_query_var('filter'); // Get filter query var from permalink
$langs = array('en','fr','nl'); // Define languages
$notlangs = array_diff($langs, array(ICL_LANGUAGE_CODE)); // Create a new array from the languages minus the current language
foreach($notlangs as $l) $lids[] = get_category_by_slug($l)->cat_ID; // Get the category IDs of the languages
$pts = array('pt1','pt2','pt3','pt4'); // My Custom Post Types
if(!in_array($filter, $pts)) $filter = array_diff($pts, array('pt1')); // Due to the conflicts with WPML, pt1 was causing the issues, so if the filter is all (as in, it isn't just "one" of the defined $pts, remove pt1 from the filter list
// This is the main query - if $filter is just one post_type it runs as normal, if not, it is post_types minus pt1
$args = array('post_type' => $filter,
'posts_per_page' => 8,
'paged' => $paged,
'orderby' => 'menu_order',
'post_status' => 'publish',
);
// This is the second query - this is for pt1 specifically, and has different args
$eargs = array('post_type' => 'pt1',
'posts_per_page' => 8,
'paged' => $paged,
'category__not_in' => $lids,
'suppress_filters' => true
);
$the_query = new WP_Query; // Create the main query
if($filter=='pt1') $args=$eargs; // If the filter is for just pt1 by itself, make the pt1 specific args the main args
$the_query->query($args); // Run the standard WP loop query
if(is_array($filter)) { // If $filter is an array, meaning it is not JUST a single filter
$ent_query = new WP_Query; // Create a new WP Query
$ent_query->query($eargs); // Run the query with pt1 args, effectively running two simultaneous queries
$the_query->posts = array_merge($the_query->posts, $ent_query->posts); // So then merge the two results into array, the original, "main" WP query
$the_query->post_count = count($the_query->posts); // So that the page count isn't broken by the merge, recount the query
shuffle($the_query->posts); // Randomise the results so it isn't 8 of each in a row
}
Because the 3 less populated post_types are queried first, the top part of my gallery is now garuanteed to be populated by them first, and the shuffle after each merge ensures I get a nice random pattern until they disappear normally when there is no more left for that page.
I know this is highly specific – but hopefully some of the logic helps someone.
The important part is running two queries simultaneously and then merging both of those results into the original main query.
Thanks again Birgire, you got me thinking on the right track.
Regards,
GB.