Choosing the Right Query for WordPress Development
Let’s say you want to do something unique with the way posts are queried and displayed on a particular page of your website. Maybe you want to have multiple queries — one for featured posts and one for recent posts. Or perhaps you want to exclude certain categories of posts from your blog page.
Whatever your goal, you decide to build a custom page template with a query that does something a bit differently. However, before you start coding you have a decision to make: which WordPress query tool should you use?
WordPress includes several different queries:
pre_get_posts. In many cases, you could use more than one of these tools to achieve the desired results. However, the question remains, which on should you use?
In this post we’ll look at each of these five WordPress query functions in detail. We’ll learn how each one works, identify any inherent limitations or pitfalls, and determine the scenarios in which each should be used. By the end of this post, you’ll know be able to make an educated decision as to the proper tool for your post querying needs.
Let’s get right to it.
WP_Query is the class behind (almost) every WordPress query. When you load a page or post in WordPress, a
$query, is created and pulls up the relevant post or page data. Think of
WP_Query as the engine that powers most WordPress queries.
WP_Query even without realizing you’re using it. When your load a URL the WordPress core builds a database query with
WP_Query based on the URL and the settings you’ve applied to your website. So, if you access a page with a URL like http://example.com/category/wordpress WordPress creates a
WP_Query object that locates all posts in the WordPress category and loads all of the post data.
WP_Query powers the standard post and page queries built into WordPress and it can also be used to build custom queries. This is done with a bit of object-oriented programming. All you have to do is create a new variable and declare it as a new instance of the
WP_Query class, like this:
Of course, then you need to do something with the results of the query. However, that something that’s beyond the scope of this tutorial. Instead, refer to the list of tutorials at the end of this post if you need help putting
WP_Query into practice.
As a WordPress developer, you’ll probably use
WP_Query more frequently that any other query function or hook. It’s versatile and powerful. While some of the other queries covered in this post may save you a few keystrokes in some cases, in general, you can’t go wrong selecting
WP_Query for your custom query writing needs.
The only exception to this is the case where all you need to do is filter the results of the standard query. In that case,
pre_get_posts is the tool you should use. So let’s take a look at it next.
pre_get_posts is a hook, not a function. Rather than query the database anew,
pre_get_posts allows you to modify the
$query object before the database is queried — effectively filtering the results returned by the standard query.
In most cases,
pre_get_posts is paired with conditional tags to filter the query results in specific situations. For example, you could use
pre_get_posts to return a different number of posts on the site homepage. In essence, if you want to run the standard query but modify it in some way,
pre_get_posts is the tool for the job.
There are some instances in which
pre_get_posts will not work and should not be used. The WordPress Codex suggests two such instances:
pre_get_postsfilter should not be used to alter the query on the template for a single page because doing so will interfere with properties already set by
pre_get_postsfilter will not work if added to a template files such as archive.php because these files are loaded after the main query has already run.
Where does that leave us? That means that
pre_get_posts is a great choice for modifying the query loading posts into the main loop of the homepage, blog page, and individual pages such as page.php and single.php.
However, sometimes filtering the standard query isn’t enough. Perhaps you want to use multiple WordPress queries, or manipulate query results in a fashion that
pre_get_posts won’t allow. In that case, you can head back to
WP_Query or read on for a few additional options.
If you dig around looking for WordPress tutorials from several years ago, you’ll find many tutorials recommending the use of
query_posts(). However, modern tutorials almost universally recommend against this. Here’s why.
query_posts() function replaces the main query object,
$query, which is created and used by the default loop run by the WordPress core. It does this by creating a new
WP_Query instance and assigning it to the
That may make it sound as if
query_posts() is really powerful and useful. However, fiddling with the core loop means that
query_posts() has major downsides and should be avoided.
The official WordPress code reference provides several reasons why use of
query_posts() should be avoided in the vast majority of cases. The primary reasons given for this include:
query_posts()can significantly slow down page load time by increasing by as much as double the amount of work required to process the query.
query_posts()replaces the standard query data it can cause any number of problems with pagination and wreak havoc on pages that make use of multiple queries.
In short, use of
query_posts() is a dangerous proposition. As a matter of fact, the official documentation opens with the caveat:
This function will completely override the main query and isn’t intended for use by plugins or themes. Its overly-simplistic approach to modifying the main query can be problematic and should be avoided wherever possible.
In other words, if you’re coding a theme or plugin — which is exactly what the vast majority of us are doing — avoid the use of
query_posts(). Instead, create an entirely new
WP_Query object or use
Think of the
get_posts() function as a modifiable, predefined instance of the
WP_Query class, because that’s exactly what it is. When you use
get_posts() you’re effectively calling up preset default values and using them to create an instance of the
In one sense,
get_posts() is a lot like
query_posts(): they are both predefined instances of
WP_Query. However, they are also quite different because
query_posts() replaces the default
$query object while
get_posts() simply creates an entirely new query that does not interfere with global variables in the way that
So, what’s the point in using
get_posts()? Why not just use
WP_Query? The answer is convenience. If you’re thinking of using
get_posts() you could definitely accomplish whatever it is you’re trying to accomplish with
WP_Query. However, by using
get_posts() you save yourself a few keystrokes.
There is another difference between
get_posts(). That is that the latter returns an array of posts while the former returns posts one at a time with
the_post() function. That means that
get_posts() returns all posts at once as an array while
WP_Query iterates through posts one at a time echoing out the relevant content of each post as it iterates. Practically speaking, this means that when using
get_posts() you use a
foreach function to display the results, but you use the standard
if...while loop structure to echo out content while using
The other thing to keep in mind is that since
get_posts() does not modify the global
$query object, you need to use
setup_postdata() for each post to get access to
WP_Query methods and properties. While that may sound complicated, it really isn’t. Have a look:
So that bit of code will return four posts from the
slider category (presumably to display them in a post slider). First, we make sure that the query returned something with the
if ( $slider_posts ) code, and then cycle through the posts displaying the title and content. By using
setup_postdata() we’re able to use global variables such as
$authordata as well as template tags such as
the_content(). Without setting up post data, we would not be able to use those variables and template tags.
One query function that doesn’t get very much attention is the
get_pages() query. Unlike all of the other queries in this post, which are all somehow related to
get_pages() is a function that bypasses
WP_Query and directly queries the database.
get_posts(), this function returns the content it locates in an array. However, unlike
get_posts(), which can be used to pull up any posts of any post type (posts, pages, custom post types, and so forth),
get_pages() can only be used to retrieve hierarchical post types such as pages and hierarchical custom post types.
get_pages() allows you to specify a few query parameters that are unique to hierarchical post types including
'hierarchical'. Access to these parameters is the primary reason why you might consider using this particular query.
Putting Theory Into Practice
In this post we’ve introduced five powerful WordPress query tools but we haven’t really shown you how to use them. However, we have written about writing custom queries in the past and you can learn more about how to use these queries in your themes and plugins by checking out these other resources from our blog:
- An In-Depth Guide to Conquering WP_Query
- The WordPress Loop Explained
- How to Arrange WordPress Posts in Any Order
- WordPress Development for Intermediate Users: Queries and Loops
- 5 Simple Methods for Creating Custom Queries in WordPress
As you can see, when it comes to querying the WordPress database, there is no shortage of options. There are at least five powerful tools that WordPress developers can use to get ahold of the database entries they wish to display. Let’s recap each of the available options:
WP_Query: the versatile class that powers most WordPress queries. It is flexible and can be used to create any sort of query.
pre_get_posts: a hook which can be used to refine the
$queryobject before the database is queried, thereby safely modifying the default query. Use it along with conditional tags to refine the results of the standard query.
query_posts(): a powerful instance of the
WP_Queryclass that replaces the default
$queryobject and is not intended for theme or plugin development. Don’t use it.
get_posts(): an instance of the
WP_Queryclass that returns an array of posts. It includes a range of default values that may save you a few keystrokes versus crafting a custom instance of
WP_Query, but only if the default options fit your needs.
get_pages(): a function that can be refined through the use of hierarchical parameters and returns an array of hierarchical post types, such as pages or hierarchical custom post types.