Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Getting Crazy Creative
with WordPress Queries
Drew Jaynes
WordCamp Cape Town 2015
• Platform Engineer at 10up
• Docs Committer for WordPress core
• 4.2 Release Lead
• Developing with WordPress since 2009
...
• Basics
• No-Nos
• Optimizations
• Creative Querying
Topics
Query Basics
The Loop
if ( have_posts() ) :
while ( have_posts() ) :
the_post();
...
endwhile;
endif;
The Loop: Internals
if ( $wp_query->have_posts() ) :
while ( $wp_query->have_posts() ) :
$wp_query->the_post();
...
endwhi...
WP_Query
// Query for the 7 latest, published posts.
$query = new WP_Query( array(
'posts_per_page' => 7,
'post_status' =>...
WP_Query: SQL
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts
WHERE 1=1
AND wp_posts.post_type = 'post'
AND wp_posts....
• WP_Query wrapper
• Defaults: Filter suppression
• Defaults: No sticky posts
• Defaults: No found rows
• Array of results...
get_posts()
// Query for the 7 latest, published posts.
$query = get_posts( array(
'posts_per_page' => 7,
'post_status' =>...
get_posts(): SQL
SELECT wp_posts.ID FROM wp_posts
WHERE 1=1
AND wp_posts.post_type = 'post'
AND ( ( wp_posts.post_status =...
• Action, not a filter
• Fires before the query actually runs
• Use query methods intead of top-level functio
e.g. $query->...
pre_get_posts
/**
* Display both posts and pages in the home loop.
*
* @param WP_Query $query Main WP_Query instance.
*/
f...
pre_get_posts: Original SQL
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts
WHERE 1=1
AND wp_posts.post_type = 'post'...
pre_get_posts: SQL
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts
WHERE 1=1
AND wp_posts.post_type IN ( 'post', 'pag...
No-Nos
• Completely overrides the main query
• Very few valid use cases
• Custom page template archives
query_posts()
query_posts()
query_posts( array(
'post_type' => ‘page’,
‘post_per_page' => 4
) );
posts_per_page
get_posts( array(
‘posts_per_page’ => -1,
‘posts_per_page’ => 100
) );
Optimization
• update_post_term_cache
• update_post_meta_cache
• no_found_rows
• fields
• posts_per_page
Optimizing WP_Query
Optimizing WP_Query
$query = new WP_Query( array(
'update_post_term_cache' => false,
'update_post_meta_cache' => false,
'p...
Creative Querying
WP_Query
• posts_* filters
• pre_get_posts action
WP_Query hooks
WP_Query orderby
$posts = get_posts( array(
'posts_per_page' => 15,
'orderby' => array(
'post_date' => 'DESC',
'post_title...
WP_Query orderby: SQL
SELECT wp_posts.ID FROM wp_posts
WHERE 1=1
AND wp_posts.post_type = 'post'
AND ( ( wp_posts.post_sta...
• Available 4.2+
• Order by independent meta clauses
• WP_Meta_Query, WP_User_Query,
WP_Comment_Query
WP_Query orderby: me...
WP_Query orderby: meta clauses
$posts = get_posts( array(
'meta_query' => array(
'relation' => 'AND',
'state_clause' => ar...
WP_Query orderby: meta clauses
$posts = get_posts( array(
'meta_query' => array(
'relation' => 'AND',
'state_clause' => ar...
WP_Query orderby: SQL
SELECT wp_posts.ID FROM wp_posts
INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id )
INN...
WP_User_Query
WP_User_Query
// Query for users registered on a Tuesday.
$query = new WP_User_Query( array(
'date_query' => array(
array(...
Custom WP_Query Orderby
• Order results by a value in a custom table
• Adds an additional LEFT JOIN
WP_Query orderby with custom tables
Joining Custom Tables: JOIN
/**
* Join vote totals table to the 'books' custom post type query.
*
* @param string $join JO...
Joining Custom Tables: ORDERBY
/**
* Order by vote totals descending, then post date descending.
*
* @param string $orderb...
Joining Custom Tables: SQL
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts
WHERE 1=1
AND wp_posts.post_type = 'books'...
Joining Custom Tables: SQL
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts
LEFT JOIN wp_up_down_post_vote_totals
ON w...
• WordPress Code Reference
• WP_Query Reference (Codex)
• Trunk wp-includes/
Resources
Questions?
Drew Jaynes | @DrewAPicture
Slides: http://drewf.us/wcct
Upcoming SlideShare
Loading in …5
×

Getting Creative with WordPress Queries

3,392 views

Published on

We’re at a point now where we have these incredibly powerful query classes in WordPress core that allow you to really tailor down to whatever criterion you want. In this workshop, Drew will provide some real-world examples of some crazy stuff you can do with queries – it’s very much a “sky’s the limit” kind of situation. Queries are really interesting and powerful, and a lot of people are intimidated by advanced queries, even with the abstraction layers that WordPress has put in place.

Published in: Education
  • Be the first to comment

Getting Creative with WordPress Queries

  1. 1. Getting Crazy Creative with WordPress Queries Drew Jaynes WordCamp Cape Town 2015
  2. 2. • Platform Engineer at 10up • Docs Committer for WordPress core • 4.2 Release Lead • Developing with WordPress since 2009 • Slides: http://drewf.us/wcct Hi, I’m Drew.
  3. 3. • Basics • No-Nos • Optimizations • Creative Querying Topics
  4. 4. Query Basics
  5. 5. The Loop if ( have_posts() ) : while ( have_posts() ) : the_post(); ... endwhile; endif;
  6. 6. The Loop: Internals if ( $wp_query->have_posts() ) : while ( $wp_query->have_posts() ) : $wp_query->the_post(); ... endwhile; endif;
  7. 7. WP_Query // Query for the 7 latest, published posts. $query = new WP_Query( array( 'posts_per_page' => 7, 'post_status' => 'publish' ) );
  8. 8. WP_Query: SQL SELECT SQL_CALC_FOUND_ROWS wp_posts.ID 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, 7
  9. 9. • WP_Query wrapper • Defaults: Filter suppression • Defaults: No sticky posts • Defaults: No found rows • Array of results vs WP_Query instance get_posts()
  10. 10. get_posts() // Query for the 7 latest, published posts. $query = get_posts( array( 'posts_per_page' => 7, 'post_status' => 'publish' ) );
  11. 11. get_posts(): SQL SELECT wp_posts.ID 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, 7
  12. 12. • Action, not a filter • Fires before the query actually runs • Use query methods intead of top-level functio e.g. $query->is_main_query() pre_get_posts
  13. 13. pre_get_posts /** * Display both posts and pages in the home loop. * * @param WP_Query $query Main WP_Query instance. */ function pages_in_main_query( $query ) { if ( ! is_admin() && is_home() ) { $query->query_vars['post_type'] = array( 'post', 'page' ); } } add_action( 'pre_get_posts', 'pages_in_main_query' );
  14. 14. pre_get_posts: Original SQL SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND wp_posts.post_type = 'post' AND ( wp_posts.post_status = ‘publish' OR wp_posts.post_status = ‘private' ) ORDER BY wp_posts.post_date DESC LIMIT 0, 10
  15. 15. pre_get_posts: SQL SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND wp_posts.post_type IN ( 'post', 'page' ) AND ( wp_posts.post_status = ‘publish' OR wp_posts.post_status = ‘private' ) ORDER BY wp_posts.post_date DESC LIMIT 0, 10
  16. 16. No-Nos
  17. 17. • Completely overrides the main query • Very few valid use cases • Custom page template archives query_posts()
  18. 18. query_posts() query_posts( array( 'post_type' => ‘page’, ‘post_per_page' => 4 ) );
  19. 19. posts_per_page get_posts( array( ‘posts_per_page’ => -1, ‘posts_per_page’ => 100 ) );
  20. 20. Optimization
  21. 21. • update_post_term_cache • update_post_meta_cache • no_found_rows • fields • posts_per_page Optimizing WP_Query
  22. 22. Optimizing WP_Query $query = new WP_Query( array( 'update_post_term_cache' => false, 'update_post_meta_cache' => false, 'posts_per_page' => 100, 'no_found_rows' => true, 'fields' => 'ids' ) );
  23. 23. Creative Querying
  24. 24. WP_Query
  25. 25. • posts_* filters • pre_get_posts action WP_Query hooks
  26. 26. WP_Query orderby $posts = get_posts( array( 'posts_per_page' => 15, 'orderby' => array( 'post_date' => 'DESC', 'post_title' => 'ASC' ), ) );
  27. 27. WP_Query orderby: SQL SELECT wp_posts.ID 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, wp_posts.post_title ASC LIMIT 0, 15
  28. 28. • Available 4.2+ • Order by independent meta clauses • WP_Meta_Query, WP_User_Query, WP_Comment_Query WP_Query orderby: meta clauses
  29. 29. WP_Query orderby: meta clauses $posts = get_posts( array( 'meta_query' => array( 'relation' => 'AND', 'state_clause' => array( 'key' => 'state', 'value' => 'Colorado' ), 'city_clause' => array( 'key' => 'city', 'compare' => 'EXISTS' ) ), 'orderby' => array( 'state_clause' => 'ASC', 'city_clause' => 'DESC' ) ) );
  30. 30. WP_Query orderby: meta clauses $posts = get_posts( array( 'meta_query' => array( 'relation' => 'AND', 'state_clause' => array( 'key' => 'state', 'value' => 'Colorado' ), 'city_clause' => array( 'key' => 'city', 'compare' => 'EXISTS' ) ), 'orderby' => array( 'state_clause' => 'ASC', 'city_clause' => 'DESC' ) ) );
  31. 31. WP_Query orderby: SQL SELECT wp_posts.ID FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) INNER JOIN wp_postmeta AS mt1 ON ( wp_posts.ID = mt1.post_id ) WHERE 1=1 AND ( ( wp_postmeta.meta_key = ‘state’ AND CAST( wp_postmeta.meta_value AS CHAR ) = ‘Colorado' ) AND mt1.meta_key = ‘city' ) AND wp_posts.post_type = 'post' AND ( ( wp_posts.post_status = 'publish' ) ) GROUP BY wp_posts.ID ORDER BY CAST( mt1.meta_value AS CHAR ) ASC, CAST( wp_postmeta.meta_value AS CHAR ) DESC LIMIT 0, 5
  32. 32. WP_User_Query
  33. 33. WP_User_Query // Query for users registered on a Tuesday. $query = new WP_User_Query( array( 'date_query' => array( array( 'column' => 'user_registered', 'dayofweek' => 3 // Tuesday ) ), ) );
  34. 34. Custom WP_Query Orderby
  35. 35. • Order results by a value in a custom table • Adds an additional LEFT JOIN WP_Query orderby with custom tables
  36. 36. Joining Custom Tables: JOIN /** * Join vote totals table to the 'books' custom post type query. * * @param string $join JOIN query clauses. * @param WP_Query $query Current WP_Query instance. * @return string The filtered JOIN clauses. */ function join_votes_table( $join, $query ) { global $wpdb; if ( ! is_admin() ) { if ( isset( $query->query_vars['post_type'] ) && 'books' == $query->query_vars[‘post_type'] ) { $votes = $wpdb->prefix . 'up_down_post_vote_totals'; $join .= "LEFT JOIN $votes ON $wpdb->posts.ID = $votes.post_id "; } } return $join; } add_filter( 'posts_join', 'join_votes_table', 10, 2 );
  37. 37. Joining Custom Tables: ORDERBY /** * Order by vote totals descending, then post date descending. * * @param string $orderby ORDER BY query clauses. * @param WP_Query $query Current WP_Query instance. * @return string The filtered ORDER BY query clauses. */ function orderby_votes_and_date( $orderby, $query ) { global $wpdb; if ( ! is_admin() ) { if ( isset( $query->query_vars['post_type'] ) && 'books' == $query->query_vars[‘post_type'] ) { $votes = $wpdb->prefix . 'up_down_post_vote_totals'; $orderby = "$votes.vote_count_up DESC, $wpdb->posts.post_date DESC"; } } return $orderby; } add_filter( 'posts_orderby', 'orderby_votes_and_date', 10, 2 );
  38. 38. Joining Custom Tables: SQL SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND wp_posts.post_type = 'books' AND ( wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private' ) ORDER BY wp_posts.post_date DESC LIMIT 0, 10 Original SQL:
  39. 39. Joining Custom Tables: SQL SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts LEFT JOIN wp_up_down_post_vote_totals ON wp_posts.ID = wp_up_down_post_vote_totals.post_id WHERE 1=1 AND wp_posts.post_type = 'books' AND ( wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private' ) ORDER BY wp_up_down_post_vote_totals.vote_count_up DESC, wp_posts.post_date DESC LIMIT 0, 10 SQL with the JOIN:
  40. 40. • WordPress Code Reference • WP_Query Reference (Codex) • Trunk wp-includes/ Resources
  41. 41. Questions? Drew Jaynes | @DrewAPicture Slides: http://drewf.us/wcct

×