61
WordCamp Portland 2011 September 17, 2011

You Don't Know Query - WordCamp Portland 2011

Embed Size (px)

DESCRIPTION

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

Citation preview

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