Post Queries
Post queries retrieve posts from the database so that they can be processed or displayed on the frontend. This section covers some vital concepts, and methods of generating these queries.
As a summary:
Use the main loop to display the primary content on the page.
Use
WP_Query
for secondary requests and queries.If the main loop does not show what you want it to show, change it with
pre_get_posts
.Avoid
query_posts
andwp_reset_query
at all costs.
The Main Loop
Every page displayed by WordPress has a main query. This query grabs posts from the database, and is used to determine what template should be loaded.
Once that template is loaded, the main loop begins, allowing the theme to display the posts found by the main query. Here is an example main loop:
The Main Query and Query Variables
The main query is created using the URL, and is represented by a WP_Query
object.
This object is told what to fetch using Query Variables. These values are passed into the query object at the start, and must be part of a list of valid query variables.
For example, the query variable 'p' is used to fetch a specific post type, e.g.
Fetches the post with ID 12. The full list of options are available on the WP_Query
codex entry.
Note: When using get_posts
always specify suppress_filters
and use the value false
, so that caches get used. If you do not set this, there will be a performance penalty. This is not needed for WP_Query
.
Making a Query
To retrieve posts from the Database, you need to make a post query. All methods of getting posts are layers on top of the WP_Query
object.
There are 3 ways to do this:
WP_Query
( best )get_posts
( okay )query_posts
( avoid at all costs )
This diagram explains what happens in each method:
WP_Query
WP_Query
All post queries are wrappers around WP_Query
objects. A WP_Query
object represents a query, e.g. the main query, and has helpful methods such as:
etc. The functions have_posts();
and the_post();
found in most themes are wrappers around the main query object:
get_posts
get_posts
get_posts
is similar to WP_Query
, and takes the same arguments, but it returns an array containing the requested posts in full. You shouldn't use get_posts
if you're intending to create a post loop.
While get_posts
is conceptually simpler than WP_Query
for novice programmers to understand, it does have a downside. get_posts
doesn't make extensive use of the object cache in the way that WP_Query
does, and may not be as performant.
When using this function, always specify suppress_filters
as false
. By default, get_posts
ignores cache, and will run slower.
Do not use query_posts
query_posts
query_posts
is an overly simplistic and problematic way to modify the main query of a page by replacing it with new instance of the query.
It is inefficient (re-runs SQL queries) and will outright fail in some circumstances (especially often when dealing with posts pagination). Any modern WordPress code should use more reliable methods, such as making use of the pre_get_posts
hook, for this purpose. Do not use query_posts()
.
Meta Queries and Performance
When performing a query involving meta keys, there can be performance issues. This is because there is no index on the post meta tables. As a result post meta queries have the potential to be very expensive. Queries involving both post meta keys and post meta values can be even more expensive.
NOT IN
Queries
NOT IN
QueriesQueries looking for posts that are not in a category or don't have a post meta key can be very expensive, and should be avoided. The nature of the query means that they are expensive, as the database has to figure out which posts do have the term/meta key, then subtract those results from the full list of posts. These queries don't scale and are resource intensive.
Cleaning up after Queries
wp_reset_postdata
wp_reset_postdata
When using WP_Query
or get_posts
, you may set the current post object, using the_post
or setup_postdata
. If you do, you need to clean up after yourself when you finish your while loop. Do this by calling wp_reset_postdata
.
A common mistake is to call wp_reset_postdata
after the if statement. This is incorrect, as the post hasn't changed if the if statement is false, leading to potentially unexpected behavior. Always call the function before the closing brace, not after, e.g.
wp_reset_query
wp_reset_query
When you call query_posts
, you will need to restore the main query after you've done your work. Failure to do so can lead to a large number of issues and unexpected behavior. You can do this with wp_reset_query
. Always do this after calling query_posts
, and only do it when necessary. This means you should never need to use this function.
The pre_get_posts
Filter
pre_get_posts
FilterIf you need to change the main query and display something else on the page, you should use the pre_get_posts
filter.
Many people will want to use this for things such as removing posts from an archive, changing the post types for search, excluding categories, and others
Here is the Codex example for searching only for posts:
These filters can go in a themes functions.php
, or in a plugin.
Further Reading
You don't know query, a talk by Andrew Nacin
When you should use WP_Query vs query_posts, Andrei Savchenko/Rarst
Last updated