Download the slides

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()

Image source