Ordering a query by a taxonomy term or a meta field value isn’t as straightforward as you might hope. But it is doable!

Tale as old as time. You have a post type that you want to output on your website, but you’d like to mark some posts as featured in order to show them first. No problem, right? This should be simple, you say. And then you start writing your query and after an hour of messing around with ORDERBY, TAX_QUERY, and META_QUERY parameters you slam your head into your keyboard out of frustration.

Unfortunately, this isn’t something easily handled in a single wp_query declaration, but you can accomplish it by merging the results of two wp_query objects!

Before we start… Taxonomies vs. Meta Fields

Before we dive into merging wp_query results, lets quickly discuss what may, on the surface, seem like an inconsequential decision: using a taxonomy term or a meta field value to mark posts as featured. There are many inherent reasons you may be compelled to use a meta field for this purpose, especially if you’re using Advanced Custom Fields and you want to take advantage of their fancy true/false toggle, however it turns out querying by a meta field can be significantly slower than querying by a taxonomy term (we had a site where making this switch was the difference between a page loading in 30 seconds and the same page loading instantaneously!).

So if you’re able to use a taxonomy term for this purpose, we highly recommend doing so, and we will continue through this article using a taxonomy term in our example. With that said, we also understand you may be working with old code where this is not possible or will require updating massive amounts of archived data, so we will also provide a full meta field example at the end of the post as well.

1. Build Your Featured Posts wp_query Object

In our example, we are going to build a query that pulls in featured posts based on a taxonomy term:

// Define the total number of posts you would like to output
$posts_to_show = 10;

// Build your featured posts query
$args_featured = array(
	'post_type' => 'my_cpt',
	'posts_per_page' => $posts_to_show,
	'tax_query' => array(
		array(
          'taxonomy' => 'my_taxonomy',
          'field'    => 'slug',
          'terms'    => 'featured',
		)
	)
);
$featured_query = new WP_Query($args_featured);

2. Tack on Your Non-Featured Posts, If Necessary

Next, we’re going to check if we need to display additional non-featured posts. If we need the additional posts, we build a non-featured posts query and merge its results with the featured posts. Otherwise, we will just use our featured post query.

// Determine how many featured posts were returned and decide if we need to add additional non-featured posts or not
$featured_count = $featured_query->post_count;

if ($featured_count < $posts_to_show) {
  
	// We need more posts, so build a non-featured posts query
	$args_notfeatured = array(
		'post_type' => 'my_cpt',
		'posts_per_page' => $posts_to_show - $featured_count,
		'tax_query' => array(
			array(
          		'taxonomy' => 'my_taxonomy',
          		'field'    => 'slug',
          		'terms'    => 'featured',
          		'operator' => 'NOT IN',
			)
		)
	);
	$notfeatured_query = new WP_Query($args_notfeatured);
	
	// Merge our featured query results with our non-featured query results into a single full query we can loop
	$full_query = new WP_Query();
	$full_query->posts = array_merge( $featured_query->posts, $notfeatured_query->posts );
	$full_query->post_count = count( $full_query->posts );
	
} else {
  
	// We have enough posts, set our featured query as the full query
	$full_query = $featured_query;
  
}

3. Let’s Start Loopin’!

Whether we were able to fill our query with only featured posts or we merged it with non-featured posts, we can now use the $full_query object to loop through our posts:

// Let's get loopin'!
if ( $full_query->have_posts() ) {
	while ( $full_query->have_posts() ) {
		$full_query->the_post();
		// Output your post HTML
    }
}
wp_reset_postdata();

Let’s Bring It All Together

Here’s our full example:

// Define the total number of posts you would like to output
$posts_to_show = 10;

// Build your featured posts query
$args_featured = array(
	'post_type' => 'my_cpt',
	'posts_per_page' => $posts_to_show,
	'tax_query' => array(
		array(
          'taxonomy' => 'my_taxonomy',
          'field'    => 'slug',
          'terms'    => 'featured',
		)
	)
);
$featured_query = new WP_Query($args_featured);

// Determine how many featured posts were returned and decide if we need to add additional non-featured posts or not
$featured_count = $featured_query->post_count;

if ($featured_count < $posts_to_show) {
  
	// We need more posts, so build a non-featured posts query
	$args_notfeatured = array(
		'post_type' => 'my_cpt',
		'posts_per_page' => $posts_to_show - $featured_count,
		'tax_query' => array(
			array(
          		'taxonomy' => 'my_taxonomy',
          		'field'    => 'slug',
          		'terms'    => 'featured',
          		'operator' => 'NOT IN',
			)
		)
	);
	$notfeatured_query = new WP_Query($args_notfeatured);
	
	// Merge our featured query results with our non-featured query results into a single full query we can loop
	$full_query = new WP_Query();
	$full_query->posts = array_merge( $featured_query->posts, $notfeatured_query->posts );
	$full_query->post_count = count( $full_query->posts );
	
} else {
  
	// We have enough posts, set our featured query as the full query
	$full_query = $featured_query;
  
}

// Let's get loopin'!
if ( $full_query->have_posts() ) {
	while ( $full_query->have_posts() ) {
		$full_query->the_post();
		// Output your post HTML
    }
}
wp_reset_postdata();

Addendum: Meta Field Example

Here’s the same example with a meta_query swapped in for the tax_query:

// Define the total number of posts you would like to output
$posts_to_show = 10;

// Build your featured posts query
$args_featured = array(
	'post_type' => 'my_cpt',
	'posts_per_page' => $posts_to_show,
	'meta_query' => array(
		array(
			'key' => 'featured',
			'compare' => '=',
			'value' => '1'
		)
	)
);
$featured_query = new WP_Query($args_featured);

// Determine how many featured posts were returned and decide if we need to add additional non-featured posts or not
$featured_count = $featured_query->post_count;

if ($featured_count < $posts_to_show) {
  
	// We need more posts, so build a non-featured posts query
	$args_notfeatured = array(
		'post_type' => 'my_cpt',
		'posts_per_page' => $posts_to_show - $featured_count,
		'meta_query' => array(
			'meta_query' => array(
				'relation' => 'OR',
				array(
					'key'     => 'featured',
					'value'   => '0',
					'compare' => '='
				),
				array(
					'key'     => 'featured',
					'compare' => 'NOT EXISTS'
				)
			)
		)
	);
	$notfeatured_query = new WP_Query($args_notfeatured);
	
	// Merge our featured query results with our non-featured query results into a single full query we can loop
	$full_query = new WP_Query();
	$full_query->posts = array_merge( $featured_query->posts, $notfeatured_query->posts );
	$full_query->post_count = count( $full_query->posts );
	
} else {
  
	// We have enough posts, set our featured query as the full query
	$full_query = $featured_query;
  
}

// Let's get loopin'!
if ( $full_query->have_posts() ) {
	while ( $full_query->have_posts() ) {
		$full_query->the_post();
		// Output your post HTML
    }
}
wp_reset_postdata();

And you’re all set! Let us know if you have any comments or suggestions below!

Allen Robinson

Director of Application Development
Allen has been responsible for overseeing client website development, implementation, and maintenance at Foxtrot Media for over 10 years. A Computer Science graduate from the University of Wisconsin- Madison, Robinson is a software development and content management system specialist, fluent in CSS, PHP, MySQL, HTML, and JavaScript.

Comments

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Allen Robinson

Director of Application Development
Allen has been responsible for overseeing client website development, implementation, and maintenance at Foxtrot Media for over 10 years. A Computer Science graduate from the University of Wisconsin- Madison, Robinson is a software development and content management system specialist, fluent in CSS, PHP, MySQL, HTML, and JavaScript.

Post Details

Categories:

Software/Plugins:

Languages:

Related Resources:

Related Articles