A single query
Thought about this a bit more and there's a chance that you can go with a single/the main query. Or in other words: No need for two additional queries when you can work with the default one. And in case you can't work with a default one, you won't need more than a single query no matter for how many loops you want to split the query.
First you need to set (as shown in my other answer) the needed values inside a
pre_get_posts filter. There you'll likely set
cat. Example without the
$catID = 1;
$catQuery = new WP_Query( array(
'posts_per_page' => -1,
'cat' => $catID,
// Add a headline:
printf( '<h1>%s</h1>', number_format_i18n( $catQuery->found_posts )
.__( " Posts filed under ", 'YourTextdomain' )
.get_cat_name( $catID ) );
Building a base
The next thing we need is a small custom plugin (or just put it into your
functions.php file if you don't mind moving it around during updates or theme changes):
* Plugin Name: (#130009) Merge Two Queries
* Description: "Merges" two queries by using a <code>RecursiveFilterIterator</code> to divide one main query into two queries
* Plugin URl: http://wordpress.stackexchange.com/questions/130009/how-to-merge-two-queries-together
class ThumbnailFilter extends FilterIterator implements Countable
private $counter = 0;
public function __construct( Iterator $iterator, WP_Query $wp_query )
NULL === $this->wp_query AND $this->wp_query = $wp_query;
// Save some processing time by saving it once
NULL === $this->allowed
AND $this->allowed = $this->wp_query->have_posts();
parent::__construct( $iterator );
public function accept()
OR ! $this->current() instanceof WP_Post
// Switch index, Setup post data, etc.
// Last WP_Post reached: Setup WP_Query for next loop
$this->wp_query->current_post === $this->wp_query->query_vars['posts_per_page'] -1
// Doesn't meet criteria? Abort.
if ( $this->deny() )
public function deny()
return ! has_post_thumbnail( $this->current()->ID );
public function count()
This plugin does one thing: It utilizes the PHP SPL (Standard PHP Library) and its Interfaces and Iterators. What we now got is a
FilterIterator that allows us to conveniently remove items from our loop. It extends the PHP SPL Filter Iterator so we don't have to set everything. The code is well commented, but here're some notes:
accept() method allows to define criteria that allow looping the item - or not.
- Inside that method we use
WP_Query::the_post(), so you can simply use every template tag in your template files loop.
- And as well are we monitoring the loop and rewinding the posts when we reach the last item. This allows to loop trough an infinite amount of loops without resetting our query.
- There's one custom method that isn't part of the
deny(). This method is especially convenient as it contains only our "process or not"-statement and we can easily overwrite it in later classes without needing to know anything aside from WordPress template tags.
How to loop?
With this new Iterator, we don't need
if ( $customQuery->have_posts() ) and
while ( $customQuery->have_posts() ) anymore. We can go with a simple
foreach statement as all needed checks are already done for us. Example:
// First we need an ArrayObject made out of the actual posts
$arrayObj = new ArrayObject( $wp_query->get_posts() );
// Then we need to throw it into our new custom Filter Iterator
// We pass the $wp_query object in as second argument to keep track with it
$primaryQuery = new ThumbnailFilter( $arrayObj->getIterator(), $wp_query );
Finally we need nothing more than a default
foreach loop. We can even drop
the_post() and still use all template tags. The global
$post object will always stay in sync.
foreach ( $primaryQuery as $post )
var_dump( get_the_ID() );
Now the nice thing is that every later query filter is quite easy to handle: Simply define the
deny() method and you're ready to go for your next loop.
$this->current() will always point to our currently looped post.
class NoThumbnailFilter extends ThumbnailFilter
public function deny()
return has_post_thumbnail( $this->current()->ID );
As we defined that we now
deny() looping every post that has a thumbnail, we then can instantly loop all posts without a thumbnail:
foreach ( $secondaryQuery as $post )
var_dump( get_the_title( get_the_ID() ) );
The following test plugin is available as Gist on GitHub. Simply upload and activate it. It outputs/dumps the ID of every looped post as callback on the
loop_start action. This means that might get quite a bit output depending on your setup, number of posts and configuration. Please add some abort statements and alter the
var_dump()s at the end to what you want to see and where you want to see it. It's just a proof of concept.