You Don't Know Query - WordCamp Portland 2011

  • View
    13.955

  • Download
    4

Embed Size (px)

DESCRIPTION

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

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

  • 1. WordCamp Portland 2011September 17, 2011

2. Andrew NacinCore Developer of WordPressTech Ninja at Audrey Capitalnacin@wordpress.org@nacin on Twitter 3. You Dont Know Query 4. What do you know? 5. Conditional Tagsis_author( ), is_home( ), etc. 6. Who has ever heard ofquery_posts( )? 7. Ways to queryquery_posts( )new WP_Query( )get_posts( ) 8. The loopif ( have_posts( ) ) while ( have_posts( ) ) :the_post( );endwhile( ); 9. What dont you know? 10. Every query object has itsown methodsis_author( ) is the same as calling$wp_query->is_author( ) 11. function is_author( ) {global $wp_query;return $wp_query->is_author( );} 12. 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( ); 13. But why do we call things likewp_reset_postdata( ) andwp_reset_query( )?What about using query_posts( )?How can you alter a query? Whatabout the main query? 14. What is the main query,and why should I care? 15. Lets dig in. 16. wp-blog-header.php// Load the WordPress bootstraprequire dirname( __FILE__ ) . /wp-load.php;// Do magicwp();// Decide which template les to loadABSPATH . WPINC . /template-loader.php; 17. Lets look in the bootstrap:$wp_the_query = new WP_Query();$wp_query =& $wp_the_query; 18. Quick lesson on PHP references$a = 4;$b =& $a;$b = 2;var_dump( $a ); // int(2)$a = 6;var_dump( $b ); // int(6) 19. So:So the real main query is in$wp_the_query.And a live copy of it is stored in$wp_query. 20. wp-blog-header.php// Load the WordPress bootstraprequire dirname( __FILE__ ) . /wp-load.php;// Do magicwp();// Decide which template les to loadABSPATH . WPINC . /template-loader.php; 21. wp-blog-header.php// Load the WordPress bootstraprequire dirname( __FILE__ ) . /wp-load.php;// Do magicwp( );// Decide which template les to loadABSPATH . WPINC . /template-loader.php; 22. What is that wp( ) call?function wp( $query_vars =) {global $wp;$wp->main( $query_vars );} 23. Holy $!@?, what justhappened? 24. In the bootstrap:$wp = new WP( );So theres a wp( ) function,and a WP class. 25. class WP {. . .function main( ) {$this->init( );$this->parse_request( );$this->send_headers( );$this->query_posts( );$this->handle_404( );$this->register_globals( ); . . . 26. class WP {. . .function main( ) {$this->init( );$this->parse_request( );$this->send_headers( );$this->query_posts( );$this->handle_404( );$this->register_globals( ); . . . 27. WP::parse_request( ) Parses the URL using WP_Rewrite Sets up query variables for WP_QueryWP::query_posts( ) {global $wp_the_query;$wp_the_query->query( $this->query_vars );} 28. Boom.SELECT SQL_CALC_FOUND_ROWSwp_posts.*FROM wp_postsWHERE 1=1AND wp_posts.post_type = postAND wp_posts.post_status = publishORDER BY wp_posts.post_date DESCLIMIT 0, 10 29. 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; 30. Before we get to the theme,we have your posts.Got it? 31. Then why do we do this?query_posts( author=5 );get_header( );while( have_posts( ) ) :the_post( );endwhile;get_footer( ); 32. Thats running 2* queries!One, the query WordPressthought we wanted.Two, this new one youreactually going to use. 33. * Actually, WP_Querydoesnt run just one query.It usually runs four. 34. 1. Get me my posts: SELECT SQL_CALC_FOUND_ROWS FROM wp_posts LIMIT 0, 102. How many posts exist? SELECT FOUND_ROWS()3. Slurp all metadata for these posts.4. Slurp all terms for these posts. 35. PROTIPMeasure twice, cut onceis bad for performance. 36. (A note, you can turn these o selectively)$my_query = new WP_Query( array( no_found_rows => true, update_post_meta_cache => false, update_post_term_cache => false,) ); 37. So. Instead of this:query_posts( author=5 );get_header( );while ( have_posts( ) ) :the_post( );endwhile;get_footer( ); 38. We can use this:// In WP::parse_request()$this->query_vars = apply_lters( request, $this->query_vars ); 39. We can modify queryvariables in mid air:function nacin_lter_out_author( $qvs ) {if ( ! isset( $qvs[author] ) )$qvs[author] = -5;return $qvs;} 40. Powerful, but lacks context. 41. Powerful, but lacks context.Problem 1: Conditional tags dont work yet. 42. Powerful, but lacks context.Problem 1: Conditional tags dont work yet.Problem 2: Only works on the main query. 43. Powerful, but lacks context.Problem 1: Conditional tags dont work yet.Problem 2: Only works on the main query.Problem 3: WP_Query is waaay cooler. 44. Introducing pre_get_postsclass WP_Query { . . . function &get_posts() { $this->parse_query(); // Huzzah! Conditional tags are available. do_action_ref_array( pre_get_posts,array( &$this ) ); . . . 45. 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 ); 46. Still with us?Good, cause heres wherethings get hairy. 47. request res for the main query only.pre_get_posts res for every post query: get_posts() new WP_Query() That random recent posts widget. Everything. 48. What if I just want it on themain query? 49. $wp_the_query makes atriumphant return. 50. 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 ); 51. Hmm. How does this work?$wp_the_query should never be modied. Itholds the main query, forever.$wp_query keeps a live reference to$wp_the_query, unless you use query_posts(). 52. query_posts( author=-5 );while ( have_posts( ) ) :the_post( );endwhile;wp_reset_query( ); 53. query_posts( author=-5 );while ( have_posts( ) ) :the_post( );endwhile;wp_reset_query( ); 54. class WP_Query { . . . function &query_posts( $query ) { // Break the reference to $wp_the_query unset( $wp_query ); $wp_query =& new WP_Query( $query ); . . . 55. query_posts( author=-5 );while ( have_posts( ) ) :the_post( );endwhile;wp_reset_query( ); 56. 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( ); . . . 57. Calling the_post( )?wp_reset_query( ) will reset $wp_queryand and the globals.Calling $my_query->the_post( )?wp_reset_postdata( ) will reset the globals. 58. New thing for core in 3.3!Rather than: $wp_the_query === $other_query_object Youll 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. 59. Some LessonsEvery WP_Query object has methods thatmimic the global conditional tags.The global conditional tags apply to$wp_query, the main or current query.$wp_query is always the main query, unlessyou use query_posts( ). Restore it withwp_reset_query( ). 60. And Finallyrequest is a nice hook. pre_get_posts is morepowerful and exible. Just use it properly.Always check if youre modifying the main queryusing $query === $wp_the_query$query->is_main_query( ) in 3.3! 61. Thanks! Questions?@nacin