From 304802d70debe1a365d8ada71cdf2f3dcb455f4f Mon Sep 17 00:00:00 2001 From: Boone Gorges Date: Sun, 19 Oct 2014 19:39:20 +0000 Subject: [PATCH] Use the comment API rather than direct SQL queries in `comments_template()`. `comments_template()` is used by most themes to display a post's comments. It shows all comments that have been approved, and also shows all pending comments by the current visitor (as determined by the comment cookies). However, the comments API previously had no way of querying for "all comments that are either approved, or are unapproved but written by foo@example.com". The workaround was a direct SQL query: uncached, not subject to the same filters as other comment queries, and just generally icky. The new `include_unapproved` parameter for `WP_Comment_Query` accepts an array of user IDs or email addresses. Pending comments associated with users in this array will be included in query results, regardless of the value of the 'status' parameter. In `comments_template()`, we leap from direct SQL queries to `get_comments()` plus `include_unapproved', striving to put right what once went wrong. Props boonebgorges, simonwheatley, hardy101, jesin. Fixes #19623. Built from https://develop.svn.wordpress.org/trunk@29965 git-svn-id: http://core.svn.wordpress.org/trunk@29712 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-includes/comment-template.php | 20 +++++++++------ wp-includes/comment.php | 43 ++++++++++++++++++++++++++++---- 2 files changed, 51 insertions(+), 12 deletions(-) diff --git a/wp-includes/comment-template.php b/wp-includes/comment-template.php index 41b1133573..9bd0596581 100644 --- a/wp-includes/comment-template.php +++ b/wp-includes/comment-template.php @@ -1112,15 +1112,21 @@ function comments_template( $file = '/comments.php', $separate_comments = false */ $comment_author_url = esc_url($commenter['comment_author_url']); - /** @todo Use API instead of SELECTs. */ - if ( $user_ID) { - $comments = $wpdb->get_results($wpdb->prepare("SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND (comment_approved = '1' OR ( user_id = %d AND comment_approved = '0' ) ) ORDER BY comment_date_gmt", $post->ID, $user_ID)); - } else if ( empty($comment_author) ) { - $comments = get_comments( array('post_id' => $post->ID, 'status' => 'approve', 'order' => 'ASC') ); - } else { - $comments = $wpdb->get_results($wpdb->prepare("SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND ( comment_approved = '1' OR ( comment_author = %s AND comment_author_email = %s AND comment_approved = '0' ) ) ORDER BY comment_date_gmt", $post->ID, wp_specialchars_decode($comment_author,ENT_QUOTES), $comment_author_email)); + $comment_args = array( + 'order' => 'ASC', + 'orderby' => 'comment_date_gmt', + 'status' => 'approve', + 'post_id' => $post->ID, + ); + + if ( $user_ID ) { + $comment_args['include_unapproved'] = array( $user_ID ); + } else if ( ! empty( $comment_author ) ) { + $comment_args['include_unapproved'] = array( $comment_author_email ); } + $comments = get_comments( $comment_args ); + /** * Filter the comments array. * diff --git a/wp-includes/comment.php b/wp-includes/comment.php index c84ecc2320..f3746750a2 100644 --- a/wp-includes/comment.php +++ b/wp-includes/comment.php @@ -259,7 +259,7 @@ class WP_Comment_Query { * @since 3.1.0 * @since 4.1.0 Introduced 'comment__in', 'comment__not_in', 'post_author__in', * 'post_author__not_in', 'author__in', 'author__not_in', - * 'post__in', and 'post__not_in' to $query_vars. + * 'post__in', 'post__not_in', and 'include_unapproved' to $query_vars. * * @param string|array $query_vars * @return int|array @@ -271,6 +271,7 @@ class WP_Comment_Query { 'author_email' => '', 'author__in' => '', 'author__not_in' => '', + 'include_unapproved' => '', 'fields' => '', 'ID' => '', 'comment__in' => '', @@ -333,16 +334,48 @@ class WP_Comment_Query { return $cache; } + // Assemble clauses related to 'comment_approved'. + $approved_clauses = array(); $status = $this->query_vars['status']; if ( 'hold' == $status ) { - $approved = "comment_approved = '0'"; + $approved_clauses[] = "comment_approved = '0'"; } elseif ( 'approve' == $status ) { - $approved = "comment_approved = '1'"; + $approved_clauses[] = "comment_approved = '1'"; } elseif ( ! empty( $status ) && 'all' != $status ) { - $approved = $wpdb->prepare( "comment_approved = %s", $status ); + $approved_clauses[] = $wpdb->prepare( "comment_approved = %s", $status ); } else { - $approved = "( comment_approved = '0' OR comment_approved = '1' )"; + $approved_clauses[] = "( comment_approved = '0' OR comment_approved = '1' )"; } + + // User IDs or emails whose unapproved comments are included, regardless of $status. + if ( ! empty( $this->query_vars['include_unapproved'] ) ) { + $include_unapproved = $this->query_vars['include_unapproved']; + + // Accepts arrays or comma-separated strings. + if ( ! is_array( $include_unapproved ) ) { + $include_unapproved = preg_split( '/[\s,]+/', $include_unapproved ); + } + + $unapproved_ids = $unapproved_emails = array(); + foreach ( $include_unapproved as $unapproved_identifier ) { + // Numeric values are assumed to be user ids. + if ( is_numeric( $unapproved_identifier ) ) { + $approved_clauses[] = $wpdb->prepare( "( user_id = %d AND comment_approved = '0' )", $unapproved_identifier ); + + // Otherwise we match against email addresses. + } else { + $approved_clauses[] = $wpdb->prepare( "( comment_author_email = %s AND comment_approved = '0' )", $unapproved_identifier ); + } + } + } + + // Collapse comment_approved clauses into a single OR-separated clause. + if ( 1 === count( $approved_clauses ) ) { + $approved = $approved_clauses[0]; + } else { + $approved = '( ' . implode( ' OR ', $approved_clauses ) . ' )'; + } + $order = ( 'ASC' == strtoupper( $this->query_vars['order'] ) ) ? 'ASC' : 'DESC'; if ( ! empty( $this->query_vars['orderby'] ) ) {