Upload
l3rady
View
2.108
Download
3
Embed Size (px)
DESCRIPTION
How to alter the main WordPress query the correct way. No more query_posts() pwease!by Scott Cariss of Philosophy DesignPhilosophy is a thought-led brand and digital consultancy based in London.
Citation preview
You Don’t Know Query
WordPress LondonWordPress LondonMay 16, 2012
Scott Cariss aka BradyScott Cariss aka Brady
d d l hil h i• Lead developer at Philosophy Design.
• Moderator at WordPress Answers (http://wordpress.stackexchange.com/)( p p g )
• WordPress plugin developer and enthusiast• WordPress plugin developer and enthusiast
@ hil h d iscott@philosophydesign@l3rady on Twitter
You Don’t Know QueryYou Don t Know Query
What do you know?What do you know?
Conditional TagsConditional Tags
is_author(), is_home(), etc.
Who has ever heard of query posts()?Who has ever heard of query_posts()?
Ways to queryWays to query
query_posts()new WP Query()new WP_Query()get_posts()
The loopThe loop
if( have_posts() )while( have posts() ):while( have_posts() ):the_post();
endwhile();endwhile();
What don’t you know?What don t you know?
Every query object has its own methods
is_author() is the same as calling$wp query‐>is author()$wp_query >is_author()
function is_author(){{global $wp_query;
return $wp query‐>is author();return $wp_query >is_author();}
If you do: $my query = new WP Query( $query );$my_query new WP_Query( $query );
You can do: while ( $my query‐>have posts( ) ) :while ( $my_query >have_posts( ) ) :$my_query‐>the_post( ); endwhile;
wp_reset_postdata( );
h d ll hi likBut why do we call things likewp_reset_postdata( ) andp_ _p ( )wp_reset_query( )?
What about using query_posts( )?
How can you alter a query? What aboutHow can you alter a query? What aboutthe main query?
What is the main query, and why should I care?
Let's dig inLet s dig in.
wp blog header phpwp‐blog‐header.php
// d h d b i// Load the WordPress bootstrap requiredirname( __FILE__ ) . '/wp‐load.php'; ( __ __ ) p p p
// Decide which template files to load// Decide which template files to loadABSPATH . WPINC . '/template‐loader.php';
Let’s look in the bootstrap:Let s look in the bootstrap:
$wp_the_query = new WP_Query();$wp query =& $wp the query;$wp_query & $wp_the_query;
Quick lesson on PHP referencesQuick lesson on PHP references// R f i PHP t th i bl t t// References in PHP are a means to access the same variable content
by different names.
$a = 4;$b =& $a;
// It means that $a and $b now point to the same content.
$b 2$b = 2;var_dump( $a ); // int(2)
$a = 6;var_dump( $b ); // int(6)
So:So:
The real main query is in$wp the query.$wp_the_query.
And a live copy of it is stored in$wp query$wp_query
wp blog header phpwp‐blog‐header.php
// d h d b i// Load the WordPress bootstrap requiredirname( __FILE__ ) . '/wp‐load.php'; ( __ __ ) p p p
// Do magic// Do magicwp();
// Decide which template files to load// Decide which template files to loadABSPATH . WPINC . '/template‐loader.php';
What is that wp() call?What is that wp() call?
function wp( $query_vars = '' ){{global $wp;
$wp‐>main( $query vars );$wp >main( $query_vars );}
Holy $!@? what just happened?Holy $!@?, what just happened?
In the bootstrap:In the bootstrap:
$wp = new WP()
So there’s a wp() function, and a WP class.
class WPclass WP{...f ( )function main( ){ $this‐>init( );$this‐>parse_request( );$this‐>send_headers( );$this‐>query posts( );$ q y_p ( );$this‐>handle_404( );$this‐>register_globals( );
}}. . .
}
class WPclass WP{...f ( )function main( ){ $this‐>init( );$this‐>parse_request( );$this‐>send_headers( );$this‐>query posts( );$ q y_p ( );$this‐>handle_404( );$this‐>register_globals( );
}}. . .
}
WP t( )WP::parse_request( ) Parses the URL using WP_RewriteSets up query variables for WP_Query
WP::query_posts( ){global $wp_the_query;$wp the query‐>query( $this‐>query vars ); $ p_ _q y q y( $ q y_ );
}
What do we get?What do we get?
SELECT SQL_CALC_FOUND_ROWS wp posts.* FROMwp_posts. FROM
wp_posts WHERE 1=1 AND wp_posts.post_type = 'post‘AND wp posts post status = 'publish' ORDERAND wp_posts.post_status = publish ORDER
BY wp_posts.post_date DESC LIMIT 0, 10
wp blog header phpwp‐blog‐header.php
// d d// Load WordPressdirname( __FILE__ ) . '/wp‐load.php'; ( __ __ ) p p p
// Parse what to query and query it// Parse what to query, and query it. wp();
// Load the theme// Load the theme.ABSPATH . WPINC . '/template‐loader.php';
Before we get to the theme, we have your posts.
Are we clear so far?
Then why do we do this?Then why do we do this?
( ' h ' )query_posts( 'author=5' );get_header( );g _ ( )
while( have posts( ) ) :while( have_posts( ) ) : the_post( );
endwhile;
get_footer( );
That’s running 2* queries!That s running 2 queries!
One, the query WordPressthought we wanted.thought we wanted.
Two, this new one you’reactually going to useactually going to use.
* Actually, WP_Query doesn't run just onequery. It usually runs four.query. It usually runs four.
1. Get me my posts: SELECTSQL_CALC_FOUND_ROWS …_ _ _FROM wp_posts LIMIT 0, 10
2 How many posts exist?2. How many posts exist?SELECT FOUND_ROWS()
3. Pull down all metadata for these posts.4 Pull down all terms for these posts4. Pull down all terms for these posts.
Instead of query posts()?Instead of query_posts()?
We can use this:
// In WP::parse_request()
$this‐>query vars = apply filters( 'request'$this >query_vars = apply_filters( request , $this‐>query_vars );
We can modify query variables in mid air:
function brady_filter_out_author( $qvs ){{if( ! Isset( $qvs[‘author’] ) )$qvs[‘author’] = ‘‐5’;
return $qvs;}
Powerful but lacks contextPowerful, but lacks context.
Problems:
1. Conditional tags don’t work yet.
2 Only works on the main query2. Only works on the main query.
3. WP_Query is way cooler.
Introducing pre get postsIntroducing pre_get_postsl WP Qclass WP_Query{ . . .function &get_posts(){ {$this‐>parse_query(); // OMG! Conditional tags are available!!do_action_ref_array( 'pre_get_posts', array( &$this ) );
}. . .
}
Lets kill off query posts()!Lets kill off query_posts()!
function brady_alter_home( $query ){{if ( $query‐>is_home( ) ) $query‐>set( 'author', '‐5' );
}}add_action( 'pre_get_posts', ‘brady_alter_home' );
Still with us?Still with us?
Good ‘cause here’s where things get hairy.
‘ ’ fi f h i l‘request’ fires for the main query only.
‘pre_get_posts’ fires for every post query:
• get_posts()• new WP_Query()• That random recent posts widgetThat random recent posts widget.• Everything.
What if I just want it on themain query?
$wp_the_query makes atriumphant return.
Main query only!Main query only!
f i b d l h ( $ )function brady_alter_home( $query ){{if ( $query‐>is_home( ) &&
$wp the query === $query )$wp_the_query === $query ) $query‐>set( 'author', '‐5' );
}add action( 'pre get posts'add_action( pre_get_posts , ‘brady_alter_home' );
Hmm How does this work?Hmm. How does this work?
$wp_the_query should never be modified. It holds the main query, forever. q y
$ k li f$wp_query keeps a live reference to $wp_the_query, unless you use query_posts().
query_posts( 'author=‐5' ); while ( have posts( ) ) :while ( have_posts( ) ) : the_post( );
endwhile;wp reset query( );wp_reset_query( );
l WP Qclass WP_Query{ . . . function &query_posts( $query ){ // Break the reference to $wp the query// Break the reference to $wp_the_queryunset( $wp_query ); $wp_query =& new WP_Query( $query ); ...
}...
}
query_posts( 'author=‐5' ); while ( have posts( ) ) :while ( have_posts( ) ) : the_post( );
endwhile;wp reset query( );wp_reset_query( );
class WP Queryclass WP_Query{. . .f ( )function wp_reset_query( ){ // Restore the reference to $wp_the_queryunset( $wp_query );$wp_query =& $wp_the_query; // Reset the globals, too.// g ,wp_reset_postdata( );. . .
}}....
}
Calling the_post( )? wp_reset_query( ) will reset $wp_query and and the globals. p_q y g
C lli $ h ( )?Calling $my_query‐>the_post( )? wp_reset_postdata( ) will reset the globals.
Since WordPress 3 3!Since WordPress 3.3!
Rather than: $wp the query === $other query object$wp_the_query $other_query_object
You‘re able to call: $other query object‐>is main query( )$other_query_object >is_main_query( )
Some LessonsSome Lessons
Every WP_Query object has methods that mimic the global conditional tags.g g
Th l b l di i l l $The global conditional tags apply to $wp_query, the main or current query.
$ i l th i l$wp_query is always the main query, unless you use query_posts( ). Restore it with wp_reset_query( ).
And finallyAnd finally
request is a nice hook. pre_get_posts is more powerful and flexible. Just use it properly. p p p y
Al h k if ' dif i h iAlways check if you're modifying the main query using $query‐>is_main_query( )
$ $ th b f 3 3$query === $wp_the_query before 3.3
Thank you! Any questions?Thank you! Any questions?
Further in‐depth discussion on query_posts():• @l3rady on Twitter.@l3rady on Twitter.• Down the pub after presentations.