wordpress queries - the right way
DESCRIPTION
This is a presentation for the November WordPress Melbourne meetup. It shows how to modify your main WordPress query the right way, using the pre_get_posts hook, rather than using query_posts() or even WP_Query().TRANSCRIPT
WordPress Queries-the right way
#wpmelbAnthony Hortin
@maddisondesigns
How you’re probably querying
query_posts()
get_posts()
new WP_Query()
You’re doing it wrong!
if ( have_posts() ) :
while ( have_posts() ) :
the_post();
endwhile;
endif;
The Loop
if ( have_posts() ) // Determines if there’s anything to iterate while ( have_posts() ) :
the_post();
endwhile;
endif;
The Loop
if ( have_posts() )
while ( have_posts() ) : // Sets up globals & continues iteration the_post();
endwhile;
endif;
The Loop
Anatomy of a WordPress Page
The Main Query
// Loads the WordPress bootstrap// ie. Sets the ABSPATH constant.// Loads the wp-config.php file etc.
require_once( dirname(__FILE__) . '/wp-load.php' );
wp();
// Decide which template files to load// ie. archive.php, index.php etc
require_once( ABSPATH . WPINC . '/template-loader.php' );
wp-blog-header.php
// Loads the WordPress bootstrap// ie. Sets the ABSPATH constant.// Loads the wp-config.php file etc.
require_once( dirname(__FILE__) . '/wp-load.php' );
wp();
// Decide which template files to load// ie. archive.php, index.php etc
require_once( ABSPATH . WPINC . '/template-loader.php' );
wp-blog-header.php
// Loads the WordPress bootstrap// ie. Sets the ABSPATH constant.// Loads the wp-config.php file etc.
require_once( dirname(__FILE__) . '/wp-load.php' );
wp();
// Decide which template files to load// ie. archive.php, index.php etc
require_once( ABSPATH . WPINC . '/template-loader.php' );
wp-blog-header.php
// Loads the WordPress bootstrap// ie. Sets the ABSPATH constant.// Loads the wp-config.php file etc.
require_once( dirname(__FILE__) . '/wp-load.php' );
// Does ALL THE THINGS!
wp();
// Decide which template files to load// ie. archive.php, index.php etc
require_once( ABSPATH . WPINC . '/template-loader.php' );
wp-blog-header.php
What is wp()?
wp();
- Parses the URL & runs it through WP_Rewrite
- Sets up query variables for WP_Query
- Runs the query
What is wp()?
wp();
- Parses the URL & runs it through WP_Rewrite
- Sets up query variables for WP_Query
- Runs the query
What is wp()?
wp();
- Parses the URL & runs it through WP_Rewrite
- Sets up query variables for WP_Query
- Runs the query
What is wp()?
wp();
- Parses the URL & runs it through WP_Rewrite
- Sets up query variables for WP_Query
- Runs the query
So, what does this mean?
It means...
Before the theme is even loaded,
WordPress already has your Posts!
Mind == Blown!
In the bootstrap
$wp_the_query = new WP_Query();
$wp_query =& $wp_the_query;
In the bootstrap
// Holds the real main query.// It should never be modified
$wp_the_query
// A live reference to the main query
$wp_query
In the bootstrap
// Holds the real main query.// It should never be modified
$wp_the_query
// A live reference to the main query
$wp_query
Back to our queries...
query_posts()
get_posts()
new WP_Query()
All three create new WP_Query objects
query_posts()goes one step further though
query_posts()
function &query_posts($query) {
unset($GLOBALS['wp_query']);
$GLOBALS['wp_query'] = new WP_Query();
return $GLOBALS['wp_query']->query($query);
}
query_posts()
function &query_posts($query) { // Destroys the Global $wp_query variable! unset($GLOBALS['wp_query']);
$GLOBALS['wp_query'] = new WP_Query();
return $GLOBALS['wp_query']->query($query);
}
query_posts()
function &query_posts($query) {
unset($GLOBALS['wp_query']); // Creates new $wp_query variable $GLOBALS['wp_query'] = new WP_Query();
return $GLOBALS['wp_query']->query($query);
}
I’m sure you’ve all done this...
get_header();
query_posts( 'cat=-1,-2,-3' );
while( have_posts() ) :
the_post();
endwhile;
wp_reset_query();
get_footer();
That’s running 2* queries!
It’s running the query WordPress
thinks you want.
It’s then running your new query
you actually want.
That’s running 2* queries!
In actual fact, WP_Querydoesn’t just run one query.It runs four!
So, that means your template
is actually running eight queries!
*
Don’t forget to reset
// Restores the $wp_query reference to $wp_the_query
// Resets the globals
wp_reset_query();
// Resets the globals
wp_reset_postdata();
There’s a better way
Say hello to pre_get_posts
[From the Codex]
The pre_get_posts action gives developers access to the $query object by reference.(any changes you make to $query are made directly to the original object)
Say hello to pre_get_posts
What this means is we can change our main query before it’s run
pre_get_posts
pre_get_posts fires for every post query:
— get_posts()— new WP_Query()— Sidebar widgets— Admin screen queries— Everything!
How do we use it?
function my_pre_get_posts( $query ) {
// Check if the main query and home and not admin
if ( $query->is_main_query() && is_home() && !is_admin() ) {
// Display only posts that belong to a certain Category
$query->set( 'category_name', 'fatuity' );
// Display only 3 posts per page
$query->set( 'posts_per_page', '3' );
return;
}
}
// Add our function to the pre_get_posts hook
add_action( 'pre_get_posts', 'my_pre_get_posts' );
In functions.php[example 1]
function my_pre_get_posts( $query ) {
// Check if the main query and home and not admin
if ( $query->is_main_query() && is_home() && !is_admin() ) {
// Display only posts that belong to a certain Category
$query->set( 'category_name', 'fatuity' );
// Display only 3 posts per page
$query->set( 'posts_per_page', '3' );
return;
}
}
// Add our function to the pre_get_posts hook
add_action( 'pre_get_posts', 'my_pre_get_posts' );
In functions.php[example 1]
function my_pre_get_posts( $query ) {
// Check if the main query and home and not admin
if ( $query->is_main_query() && is_home() && !is_admin() ) {
// Display only posts that belong to a certain Category
$query->set( 'category_name', 'fatuity' );
// Display only 3 posts per page
$query->set( 'posts_per_page', '3' );
return;
}
}
// Add our function to the pre_get_posts hook
add_action( 'pre_get_posts', 'my_pre_get_posts' );
In functions.php[example 1]
function my_pre_get_posts( $query ) {
// Check if the main query and home and not admin
if ( $query->is_main_query() && is_home() && !is_admin() ) {
// Display only posts that belong to a certain Category
$query->set( 'category_name', 'fatuity' );
// Display only 3 posts per page
$query->set( 'posts_per_page', '3' );
return;
}
}
// Add our function to the pre_get_posts hook
add_action( 'pre_get_posts', 'my_pre_get_posts' );
In functions.php[example 1]
In functions.php[example 1]function my_pre_get_posts( $query ) {
// Check if the main query and home and not admin
if ( $query->is_main_query() && is_home() && !is_admin() ) {
// Display only posts that belong to a certain Category
$query->set( 'category_name', 'fatuity' );
// Display only 3 posts per page
$query->set( 'posts_per_page', '3' );
return;
}
}
// Add our function to the pre_get_posts hook
add_action( 'pre_get_posts', 'my_pre_get_posts' );
In functions.php[example 2]function my_pre_get_posts( $query ) {
// Check if the main query and movie CPT archive and not admin
if($query->is_main_query() && is_post_type_archive('movie') && !is_admin()){
// Display only posts from a certain taxonomies
$query->set( 'tax_query', array( array( 'taxonomy' => 'genre', 'field' => 'slug', 'terms' => array ( 'fantasy', 'sci-fi' ) ) ) );
return; }
}
// Add our function to the pre_get_posts hook
add_action( 'pre_get_posts', 'my_pre_get_posts' );
In functions.php[example 2]function my_pre_get_posts( $query ) {
// Check if the main query and movie CPT archive and not admin
if($query->is_main_query() && is_post_type_archive('movie') && !is_admin()){
// Display only posts from a certain taxonomies
$query->set( 'tax_query', array( array( 'taxonomy' => 'genre', 'field' => 'slug', 'terms' => array ( 'fantasy', 'sci-fi' ) ) ) );
return; }
}
// Add our function to the pre_get_posts hook
add_action( 'pre_get_posts', 'my_pre_get_posts' );
In functions.php[example 2]function my_pre_get_posts( $query ) {
// Check if the main query and movie CPT archive and not admin
if($query->is_main_query() && is_post_type_archive('movie') && !is_admin()){
// Display only posts from a certain taxonomies
$query->set( 'tax_query', array( array( 'taxonomy' => 'genre', 'field' => 'slug', 'terms' => array ( 'fantasy', 'sci-fi' ) ) ) );
return; }
}
// Add our function to the pre_get_posts hook
add_action( 'pre_get_posts', 'my_pre_get_posts' );
In functions.php[example 2]function my_pre_get_posts( $query ) {
// Check if the main query and movie CPT archive and not admin
if($query->is_main_query() && is_post_type_archive('movie') && !is_admin()){
// Display only posts from a certain taxonomies
$query->set( 'tax_query', array( array( 'taxonomy' => 'genre', 'field' => 'slug', 'terms' => array ( 'fantasy', 'sci-fi' ) ) ) );
return; }
}
// Add our function to the pre_get_posts hook
add_action( 'pre_get_posts', 'my_pre_get_posts' );
Remember...
Do:— Use pre_get_posts— Check if it’s the main query by using is_main_query()— Check it’s not an admin query by using is_admin()— Check for specific templates using is_home(), etc..— Set up your query using same parameters as WP_Query()
Don’t:— Use query_posts()unless you have a very good reason AND you use wp_reset_query()
( if you really need a secondary query, use new WP_Query() )
References
// You Don’t Know Query - Andrew Nacinhttp://wordpress.tv/2012/06/15/andrew-nacin-wp_query
http://www.slideshare.net/andrewnacin/you-dont-know-query-wordcamp-portland-2011
// Make sense of WP Query functionshttp://bit.ly/wpsequery
// Querying Posts Without query_postshttp://developer.wordpress.com/2012/05/14/querying-posts-without-query_posts
// pre_get_posts on the WordPress Codexhttp://codex.wordpress.org/Plugin_API/Action_Reference/pre_get_posts
// Example code on Githubhttps://github.com/maddisondesigns/wpmelb-nov
That’s all folks!☺
Thanks! Questions?