You Don't Know Query - WordCamp Portland 2011

61
WordCamp Portland 2011 September 17, 2011

description

The slides for my talk, You Don't Know Query, at WordCamp Portland on September 17, 2011.

Transcript of You Don't Know Query - WordCamp Portland 2011

Page 1: You Don't Know Query - WordCamp Portland 2011

WordCamp Portland 2011 September 17, 2011

Page 2: You Don't Know Query - WordCamp Portland 2011

Andrew Nacin Core Developer of WordPress Tech Ninja at Audrey Capital

[email protected] @nacin on Twitter

Page 3: You Don't Know Query - WordCamp Portland 2011

You Don't Know Query

Page 4: You Don't Know Query - WordCamp Portland 2011

What do you know?

Page 5: You Don't Know Query - WordCamp Portland 2011

Conditional Tags

is_author( ), is_home( ), etc.

Page 6: You Don't Know Query - WordCamp Portland 2011

Who has ever heard of query_posts( )?

Page 7: You Don't Know Query - WordCamp Portland 2011

Ways to query

query_posts( ) new WP_Query( ) get_posts( )

Page 8: You Don't Know Query - WordCamp Portland 2011

The loop

if ( have_posts( ) ) while ( have_posts( ) ) : the_post( );

endwhile( );

Page 9: You Don't Know Query - WordCamp Portland 2011

What don't you know?

Page 10: You Don't Know Query - WordCamp Portland 2011

Every query object has its own methods

is_author( ) is the same as calling $wp_query->is_author( )

Page 11: You Don't Know Query - WordCamp Portland 2011

function is_author( ) { global $wp_query;

return $wp_query->is_author( );

}

Page 12: You Don't Know Query - WordCamp Portland 2011

If you do: $my_query = new WP_Query( $query ); You can do: while ( $my_query->have_posts( ) ) : $my_query->the_post( ); endwhile; wp_reset_postdata( );

Page 13: You Don't Know Query - WordCamp Portland 2011

But why do we call things like wp_reset_postdata( ) and wp_reset_query( )? What about using query_posts( )? How can you alter a query? What about the main query?

Page 14: You Don't Know Query - WordCamp Portland 2011

What is the main query, and why should I care?

Page 15: You Don't Know Query - WordCamp Portland 2011

Let's dig in.

Page 16: You Don't Know Query - WordCamp Portland 2011

wp-blog-header.php // Load the WordPress bootstrap require dirname( __FILE__ ) . '/wp-load.php'; // Do magic wp(); // Decide which template files to load ABSPATH . WPINC . '/template-loader.php';

Page 17: You Don't Know Query - WordCamp Portland 2011

Let's look in the bootstrap: $wp_the_query = new WP_Query(); $wp_query =& $wp_the_query;

Page 18: You Don't Know Query - WordCamp Portland 2011

Quick lesson on PHP references

$a = 4; $b =& $a; $b = 2; var_dump( $a ); // int(2) $a = 6; var_dump( $b ); // int(6)

Page 19: You Don't Know Query - WordCamp Portland 2011

So: So the real main query is in $wp_the_query. And a live copy of it is stored in $wp_query.

Page 20: You Don't Know Query - WordCamp Portland 2011

wp-blog-header.php // Load the WordPress bootstrap require dirname( __FILE__ ) . '/wp-load.php'; // Do magic wp(); // Decide which template files to load ABSPATH . WPINC . '/template-loader.php';

Page 21: You Don't Know Query - WordCamp Portland 2011

wp-blog-header.php // Load the WordPress bootstrap require dirname( __FILE__ ) . '/wp-load.php'; // Do magic wp( ); // Decide which template files to load ABSPATH . WPINC . '/template-loader.php';

Page 22: You Don't Know Query - WordCamp Portland 2011

What is that wp( ) call?

function wp( $query_vars = '' ) { global $wp;

$wp->main( $query_vars );

}

Page 23: You Don't Know Query - WordCamp Portland 2011

Holy $!@?, what just happened?

Page 24: You Don't Know Query - WordCamp Portland 2011

In the bootstrap:

$wp = new WP( ); So there's a wp( ) function, and a WP class.

Page 25: You Don't Know Query - WordCamp Portland 2011

class WP { . . . function main( ) { $this->init( ); $this->parse_request( ); $this->send_headers( ); $this->query_posts( ); $this->handle_404( ); $this->register_globals( ); . . .

Page 26: You Don't Know Query - WordCamp Portland 2011

class WP { . . . function main( ) { $this->init( ); $this->parse_request( ); $this->send_headers( ); $this->query_posts( ); $this->handle_404( ); $this->register_globals( ); . . .

Page 27: You Don't Know Query - WordCamp Portland 2011

WP::parse_request( ) — Parses the URL using WP_Rewrite — Sets up query variables for WP_Query WP::query_posts( ) {

global $wp_the_query; $wp_the_query->query( $this->query_vars );

}

Page 28: You Don't Know Query - WordCamp Portland 2011

Boom. SELECT SQL_CALC_FOUND_ROWS

wp_posts.* FROM wp_posts WHERE 1=1

AND wp_posts.post_type = 'post' AND wp_posts.post_status = 'publish'

ORDER BY wp_posts.post_date DESC LIMIT 0, 10

Page 29: You Don't Know Query - WordCamp Portland 2011

wp-blog-header.php

// Load WordPress. require dirname(__FILE__) . '/wp-load.php'; // Parse what to query, and query it. wp(); // Load the theme. ABSPATH . WPINC . '/template-loader.php';

Page 30: You Don't Know Query - WordCamp Portland 2011

Before we get to the theme, we have your posts.

Got it?

Page 31: You Don't Know Query - WordCamp Portland 2011

Then why do we do this?

query_posts( 'author=5' ); get_header( ); while( have_posts( ) ) : the_post( ); endwhile; get_footer( );

Page 32: You Don't Know Query - WordCamp Portland 2011

That's running 2* queries! One, the query WordPress thought we wanted. Two, this new one you're actually going to use.

Page 33: You Don't Know Query - WordCamp Portland 2011

* Actually, WP_Query doesn't run just one query. It usually runs four.

Page 34: You Don't Know Query - WordCamp Portland 2011

1. Get me my posts: SELECT SQL_CALC_FOUND_ROWS … FROM wp_posts LIMIT 0, 10

2. How many posts exist? SELECT FOUND_ROWS()

3. Slurp all metadata for these posts. 4. Slurp all terms for these posts.

Page 35: You Don't Know Query - WordCamp Portland 2011

PROTIP ‘Measure twice, cut once’ is bad for performance.

Page 36: You Don't Know Query - WordCamp Portland 2011

(A note, you can turn these off selectively…)

$my_query = new WP_Query( array( 'no_found_rows' => true, 'update_post_meta_cache' => false, 'update_post_term_cache' => false,

) );

Page 37: You Don't Know Query - WordCamp Portland 2011

So. Instead of this:

query_posts( 'author=5' ); get_header( ); while ( have_posts( ) ) : the_post( ); endwhile; get_footer( );

Page 38: You Don't Know Query - WordCamp Portland 2011

We can use this:

// In WP::parse_request() $this->query_vars =

apply_filters( 'request', $this->query_vars );

Page 39: You Don't Know Query - WordCamp Portland 2011

We can modify query variables in mid air:

function nacin_filter_out_author( $qvs ) { if ( ! isset( $qvs['author'] ) ) $qvs['author'] = '-5'; return $qvs;

}

Page 40: You Don't Know Query - WordCamp Portland 2011

Powerful, but lacks context.

Page 41: You Don't Know Query - WordCamp Portland 2011

Powerful, but lacks context.

Problem 1: Conditional tags don't work yet.

Page 42: You Don't Know Query - WordCamp Portland 2011

Powerful, but lacks context.

Problem 1: Conditional tags don't work yet. Problem 2: Only works on the main query.

Page 43: You Don't Know Query - WordCamp Portland 2011

Powerful, but lacks context.

Problem 1: Conditional tags don't work yet. Problem 2: Only works on the main query. Problem 3: WP_Query is waaay cooler.

Page 44: You Don't Know Query - WordCamp Portland 2011

Introducing pre_get_posts class WP_Query {

. . . function &get_posts() { $this->parse_query(); // Huzzah! Conditional tags are available. do_action_ref_array( 'pre_get_posts', array( &$this ) ); . . .

Page 45: You Don't Know Query - WordCamp Portland 2011

A truly awesome hook. function nacin_alter_home( $query ) {

if ( $query->is_home( ) ) $query->set( 'author', '-5' );

} add_action( 'pre_get_posts', 'nacin_alter_home' );

Page 46: You Don't Know Query - WordCamp Portland 2011

Still with us?

Good, ‘cause here’s where things get hairy.

Page 47: You Don't Know Query - WordCamp Portland 2011

'request' fires for the main query only. 'pre_get_posts' fires for every post query: — get_posts() — new WP_Query() — That random recent posts widget. — Everything.

Page 48: You Don't Know Query - WordCamp Portland 2011

What if I just want it on the main query?

Page 49: You Don't Know Query - WordCamp Portland 2011

$wp_the_query makes a triumphant return.

Page 50: You Don't Know Query - WordCamp Portland 2011

Main query only!

function nacin_alter_home ( $query ) { if ( $wp_the_query === $query && $query->is_home() ) $query->set( 'author', '-5' );

} add_action( 'pre_get_posts', 'nacin_alter_home' );

Page 51: You Don't Know Query - WordCamp Portland 2011

Hmm. How does this work? $wp_the_query should never be modified. It holds the main query, forever. $wp_query keeps a live reference to $wp_the_query, unless you use query_posts().

Page 52: You Don't Know Query - WordCamp Portland 2011

query_posts( 'author=-5' ); while ( have_posts( ) ) :

the_post( ); endwhile; wp_reset_query( );

Page 53: You Don't Know Query - WordCamp Portland 2011

query_posts( 'author=-5' ); while ( have_posts( ) ) :

the_post( ); endwhile; wp_reset_query( );

Page 54: You Don't Know Query - WordCamp Portland 2011

class WP_Query { . . . function &query_posts( $query ) { // Break the reference to $wp_the_query unset( $wp_query ); $wp_query =& new WP_Query( $query ); . . .

Page 55: You Don't Know Query - WordCamp Portland 2011

query_posts( 'author=-5' ); while ( have_posts( ) ) :

the_post( ); endwhile; wp_reset_query( );

Page 56: You Don't Know Query - WordCamp Portland 2011

class WP_Query { . . . function wp_reset_query( ) { // Restore the reference to

$wp_the_query unset( $wp_query ); $wp_query =& $wp_the_query;

// Reset the globals, too. wp_reset_postdata( ); . . .

Page 57: You Don't Know Query - WordCamp Portland 2011

Calling the_post( )? wp_reset_query( ) will reset $wp_query and and the globals.

Calling $my_query->the_post( )?

wp_reset_postdata( ) will reset the globals.

Page 58: You Don't Know Query - WordCamp Portland 2011

New thing for core in 3.3!

Rather than: $wp_the_query === $other_query_object

 You'll be able to call:

$other_query_object->is_main_query( )  is_main_query( ), the function, will act on $wp_query, like any other conditional tag.

Page 59: You Don't Know Query - WordCamp Portland 2011

Some Lessons

Every WP_Query object has methods that mimic the global conditional tags. The global conditional tags apply to $wp_query, the main or current query. $wp_query is always the main query, unless you use query_posts( ). Restore it with wp_reset_query( ).

Page 60: You Don't Know Query - WordCamp Portland 2011

request is a nice hook. pre_get_posts is more powerful and flexible. Just use it properly. Always check if you're modifying the main query using $query === $wp_the_query $query->is_main_query( ) in 3.3!

And Finally

Page 61: You Don't Know Query - WordCamp Portland 2011

Thanks! Questions?

@nacin