Summary
This is a summary of the WP_Query WordPress In-depth talk by Andrew Nacin from WordCamp Netherlands 2012.
Main point: Do not use query_posts() in your themes or plugins
query_posts() is bad because it overwrites the main WordPress query, which resides in a global variable called $wp_query.
The proper way of modifying the main query is via the pre_get_posts hook.
Example that excludes posts from author with id = 5 from the front page main query.
function nacin_alter_home($query) {
if($query->is_main_query() && $query->is_home())
$query->set('author', '-5');
}
add_action('pre_get_posts', 'nacin_alter_home');
Example that excludes posts from author with id = 5 from a specific page template:
function nacin_alter_template($query) {
if(!$query->is_main_query())
return;
if(!is_page_template('my-template.php'))
return;
$query->set('author', '-5');
}
add_action('pre_get_posts', 'nacin_alter_template');
These examples should be put in your themes functions.php or in a plugin.
The proper way of creating a secondary query / secondary loop in your plugin or theme is this:
$query = new WP_Query( ... );
while($query->have_posts()) :
$query->the_post();
endwhile;
wp_reset_postdata();
wp_reset_postdata() is needed to clean the $post global, so that the any other loops (including the main loop) may use it.
Video notes
Below is additional information that may be of interest.
is_author(), is_single() and similar methods are just wrapper functions that run functions on the $wp_query object
Implementation of is_author() from WordPress core:
function is_author(){
global $wp_query;
return $wp_query->is_author();
}
If you decide to run query_posts() despite everything you have read above, you need to use wp_reset_query() afterwards.
Like so:
query_posts('author=-5');
while(have_posts()):
the_post();
endwhile;
wp_reset_query();
Note:
wp_reset_query() automatically runs wp_reset_postdata()
WordPress keeps the real main query in a variable called $wp_the_query.
- $wp_query is a reference to the real query variable called $wp_the_query.
- Running query_posts() overwrites $wp_query with a new WP_Query. That’s why we need wp_reset_query(), to restore the reference so that $wp_query =& $wp_the_query again.
- $wp_the_query should never be modified by any theme or plugin.
query_posts() implementation from WordPress core:
function query_posts($query) {
//Break the reference to $wp_the_query
unset($wp_query);
$wp_query =& new WP_Query($query);
return $wp_query;
}
WordPress knows which query you want before the theme is loaded.
It is suboptimal to run query_posts() inside your theme, since WordPress has already ran the query it thinks you need before the theme loaded.
Every time you run query_posts() or create a new WP_Query() (secondary loop), four queries are run:
- Getting the posts according to your query string
- Calculating how many posts exist for this query (to create pagination)
- Loading all metadata for the posts
- Loading all taxonomy term information for the posts
It is possible to turn off queries 2-4 to increase performance, like this:
$my_query = new WP_Query(array(
'no_found_rows' => true,
'update_post_meta_cache' => false,
'update_post_term_cache' => false
));
Always check if you are modifying is_main_query() (and modify only it) when using the pre_get_posts hook
Otherwise sidebars and other loops might break.
Theme functions.php file loads before the rest of the theme
That’s why you can hook into pre_get_posts, which happens before the theme is loaded.
query_posts() and WP_Query diagram.
Below is a nice diagram that shows the flow of query_posts()