Getting Creative with WordPress Queries

41
Getting Crazy Creative with WordPress Queries Drew Jaynes WordCamp Cape Town 2015

Transcript of Getting Creative with WordPress Queries

Page 1: Getting Creative with WordPress Queries

Getting Crazy Creative with WordPress QueriesDrew Jaynes WordCamp Cape Town 2015

Page 2: Getting Creative with WordPress Queries

• 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.

Page 3: Getting Creative with WordPress Queries

• Basics • No-Nos • Optimizations • Creative Querying

Topics

Page 4: Getting Creative with WordPress Queries

Query Basics

Page 5: Getting Creative with WordPress Queries

The Loop

if ( have_posts() ) : while ( have_posts() ) : the_post(); ... endwhile; endif;

Page 6: Getting Creative with WordPress Queries

The Loop: Internals

if ( $wp_query->have_posts() ) : while ( $wp_query->have_posts() ) : $wp_query->the_post(); ... endwhile; endif;

Page 7: Getting Creative with WordPress Queries

WP_Query

// Query for the 7 latest, published posts. $query = new WP_Query( array( 'posts_per_page' => 7, 'post_status' => 'publish' ) );

Page 8: Getting Creative with WordPress Queries

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

Page 9: Getting Creative with WordPress Queries

• WP_Query wrapper • Defaults: Filter suppression • Defaults: No sticky posts • Defaults: No found rows • Array of results vs WP_Query instance

get_posts()

Page 10: Getting Creative with WordPress Queries

get_posts()

// Query for the 7 latest, published posts. $query = get_posts( array( 'posts_per_page' => 7, 'post_status' => 'publish' ) );

Page 11: Getting Creative with WordPress Queries

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

Page 12: Getting Creative with WordPress Queries

• Action, not a filter • Fires before the query actually runs • Use query methods intead of top-level functions,

e.g. $query->is_main_query()

pre_get_posts

Page 13: Getting Creative with WordPress Queries

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' );

Page 14: Getting Creative with WordPress Queries

pre_get_posts: Original SQLSELECT 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

Page 15: Getting Creative with WordPress Queries

pre_get_posts: SQLSELECT 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

Page 16: Getting Creative with WordPress Queries

No-Nos

Page 17: Getting Creative with WordPress Queries

• Completely overrides the main query • Very few valid use cases • Custom page template archives

query_posts()

Page 18: Getting Creative with WordPress Queries

query_posts()query_posts( array( 'post_type' => ‘page’, ‘post_per_page' => 4 ) );

Page 19: Getting Creative with WordPress Queries

posts_per_pageget_posts( array( ‘posts_per_page’ => -1, ‘posts_per_page’ => 100 ) );

Page 20: Getting Creative with WordPress Queries

Optimization

Page 21: Getting Creative with WordPress Queries

• update_post_term_cache • update_post_meta_cache • no_found_rows • fields • posts_per_page

Optimizing WP_Query

Page 22: Getting Creative with WordPress Queries

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' ) );

Page 23: Getting Creative with WordPress Queries

Creative Querying

Page 24: Getting Creative with WordPress Queries

WP_Query

Page 25: Getting Creative with WordPress Queries

• posts_* filters • pre_get_posts action

WP_Query hooks

Page 26: Getting Creative with WordPress Queries

WP_Query orderby

$posts = get_posts( array( 'posts_per_page' => 15, 'orderby' => array( 'post_date' => 'DESC', 'post_title' => 'ASC' ), ) );

Page 27: Getting Creative with WordPress Queries

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

Page 28: Getting Creative with WordPress Queries

• Available 4.2+ • Order by independent meta clauses • WP_Meta_Query, WP_User_Query,

WP_Comment_Query

WP_Query orderby: meta clauses

Page 29: Getting Creative with WordPress Queries

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' ) ) );

Page 30: Getting Creative with WordPress Queries

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' ) ) );

Page 31: Getting Creative with WordPress Queries

WP_Query orderby: SQLSELECT 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

Page 32: Getting Creative with WordPress Queries

WP_User_Query

Page 33: Getting Creative with WordPress Queries

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 ) ), ) );

Page 34: Getting Creative with WordPress Queries

Custom WP_Query Orderby

Page 35: Getting Creative with WordPress Queries

• Order results by a value in a custom table • Adds an additional LEFT JOIN

WP_Query orderby with custom tables

Page 36: Getting Creative with WordPress Queries

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 );

Page 37: Getting Creative with WordPress Queries

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 );

Page 38: Getting Creative with WordPress Queries

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:

Page 39: Getting Creative with WordPress Queries

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:

Page 41: Getting Creative with WordPress Queries

Questions?

Drew Jaynes | @DrewAPictureSlides: http://drewf.us/wcct