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.
5. The Loop
if ( have_posts() ) :
while ( have_posts() ) :
the_post();
...
endwhile;
endif;
6. The Loop: Internals
if ( $wp_query->have_posts() ) :
while ( $wp_query->have_posts() ) :
$wp_query->the_post();
...
endwhile;
endif;
7. WP_Query
// Query for the 7 latest, published posts.
$query = new WP_Query( array(
'posts_per_page' => 7,
'post_status' => 'publish'
) );
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. • WP_Query wrapper
• Defaults: Filter suppression
• Defaults: No sticky posts
• Defaults: No found rows
• Array of results vs WP_Query instance
get_posts()
10. get_posts()
// Query for the 7 latest, published posts.
$query = get_posts( array(
'posts_per_page' => 7,
'post_status' => 'publish'
) );
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. • 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. 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. 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. 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
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
35. • Order results by a value in a custom table
• Adds an additional LEFT JOIN
WP_Query orderby with custom tables
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. 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. 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. 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: