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.

git-svn-id: https://develop.svn.wordpress.org/trunk@29965 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Boone Gorges 2014-10-19 19:38:16 +00:00
parent 91733ae919
commit 348c8958da
3 changed files with 176 additions and 12 deletions

View File

@ -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.
*

View File

@ -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'] ) ) {

View File

@ -360,4 +360,129 @@ class Tests_Comment_Query extends WP_UnitTestCase {
$this->assertEqualSets( array( $c3, $c4 ), $comment_ids );
}
/**
* @ticket 19623
*/
public function test_get_comments_with_status_all() {
$comment_1 = $this->factory->comment->create( array( 'comment_post_ID' => $this->post_id, 'user_id' => 7, 'comment_approved' => '1' ) );
$comment_2 = $this->factory->comment->create( array( 'comment_post_ID' => $this->post_id, 'user_id' => 1, 'comment_approved' => '1' ) );
$comment_3 = $this->factory->comment->create( array( 'comment_post_ID' => $this->post_id, 'user_id' => 1, 'comment_approved' => '0' ) );
$comments_approved_1 = get_comments( array( 'status' => 'all' ) );
$comment_ids = get_comments( array( 'fields' => 'ids' ) );
$this->assertEqualSets( array( $comment_1, $comment_2, $comment_3 ), $comment_ids );
}
/**
* @ticket 19623
*/
public function test_get_comments_with_include_unapproved_user_id() {
$c1 = $this->factory->comment->create( array( 'comment_post_ID' => $this->post_id, 'user_id' => 7, 'comment_approved' => '1' ) );
$c2 = $this->factory->comment->create( array( 'comment_post_ID' => $this->post_id, 'user_id' => 1, 'comment_approved' => '1' ) );
$c3 = $this->factory->comment->create( array( 'comment_post_ID' => $this->post_id, 'user_id' => 1, 'comment_approved' => '0' ) );
$c4 = $this->factory->comment->create( array( 'comment_post_ID' => $this->post_id, 'user_id' => 6, 'comment_approved' => '0' ) );
$found = get_comments( array(
'fields' => 'ids',
'include_unapproved' => 1,
'status' => 'approve',
) );
$this->assertEqualSets( array( $c1, $c2, $c3 ), $found );
}
/**
* @ticket 19623
*/
public function test_get_comments_with_include_unapproved_user_id_array() {
$c1 = $this->factory->comment->create( array( 'comment_post_ID' => $this->post_id, 'user_id' => 7, 'comment_approved' => '1' ) );
$c2 = $this->factory->comment->create( array( 'comment_post_ID' => $this->post_id, 'user_id' => 1, 'comment_approved' => '1' ) );
$c3 = $this->factory->comment->create( array( 'comment_post_ID' => $this->post_id, 'user_id' => 1, 'comment_approved' => '0' ) );
$c4 = $this->factory->comment->create( array( 'comment_post_ID' => $this->post_id, 'user_id' => 6, 'comment_approved' => '0' ) );
$c5 = $this->factory->comment->create( array( 'comment_post_ID' => $this->post_id, 'user_id' => 8, 'comment_approved' => '0' ) );
$found = get_comments( array(
'fields' => 'ids',
'include_unapproved' => array( 1, 8 ),
'status' => 'approve',
) );
$this->assertEqualSets( array( $c1, $c2, $c3, $c5 ), $found );
}
/**
* @ticket 19623
*/
public function test_get_comments_with_include_unapproved_user_id_comma_separated() {
$c1 = $this->factory->comment->create( array( 'comment_post_ID' => $this->post_id, 'user_id' => 7, 'comment_approved' => '1' ) );
$c2 = $this->factory->comment->create( array( 'comment_post_ID' => $this->post_id, 'user_id' => 1, 'comment_approved' => '1' ) );
$c3 = $this->factory->comment->create( array( 'comment_post_ID' => $this->post_id, 'user_id' => 1, 'comment_approved' => '0' ) );
$c4 = $this->factory->comment->create( array( 'comment_post_ID' => $this->post_id, 'user_id' => 6, 'comment_approved' => '0' ) );
$c5 = $this->factory->comment->create( array( 'comment_post_ID' => $this->post_id, 'user_id' => 8, 'comment_approved' => '0' ) );
$found = get_comments( array(
'fields' => 'ids',
'include_unapproved' => '1,8',
'status' => 'approve',
) );
$this->assertEqualSets( array( $c1, $c2, $c3, $c5 ), $found );
}
/**
* @ticket 19623
*/
public function test_get_comments_with_include_unapproved_author_email() {
$c1 = $this->factory->comment->create( array( 'comment_post_ID' => $this->post_id, 'user_id' => 7, 'comment_approved' => '1' ) );
$c2 = $this->factory->comment->create( array( 'comment_post_ID' => $this->post_id, 'user_id' => 0, 'comment_approved' => '1', 'comment_author' => 'foo', 'comment_author_email' => 'foo@example.com' ) );
$c3 = $this->factory->comment->create( array( 'comment_post_ID' => $this->post_id, 'user_id' => 0, 'comment_approved' => '0', 'comment_author' => 'foo', 'comment_author_email' => 'foo@example.com' ) );
$c4 = $this->factory->comment->create( array( 'comment_post_ID' => $this->post_id, 'user_id' => 0, 'comment_approved' => '0', 'comment_author' => 'foo', 'comment_author_email' => 'bar@example.com' ) );
$found = get_comments( array(
'fields' => 'ids',
'include_unapproved' => 'foo@example.com',
'status' => 'approve',
) );
$this->assertEqualSets( array( $c1, $c2, $c3 ), $found );
}
/**
* @ticket 19623
*/
public function test_get_comments_with_include_unapproved_mixed_array() {
$c1 = $this->factory->comment->create( array( 'comment_post_ID' => $this->post_id, 'user_id' => 7, 'comment_approved' => '1' ) );
$c2 = $this->factory->comment->create( array( 'comment_post_ID' => $this->post_id, 'user_id' => 0, 'comment_approved' => '1', 'comment_author' => 'foo', 'comment_author_email' => 'foo@example.com' ) );
$c3 = $this->factory->comment->create( array( 'comment_post_ID' => $this->post_id, 'user_id' => 0, 'comment_approved' => '0', 'comment_author' => 'foo', 'comment_author_email' => 'foo@example.com' ) );
$c4 = $this->factory->comment->create( array( 'comment_post_ID' => $this->post_id, 'user_id' => 0, 'comment_approved' => '0', 'comment_author' => 'foo', 'comment_author_email' => 'bar@example.com' ) );
$c5 = $this->factory->comment->create( array( 'comment_post_ID' => $this->post_id, 'user_id' => 4, 'comment_approved' => '0', 'comment_author' => 'foo', 'comment_author_email' => 'bar@example.com' ) );
$found = get_comments( array(
'fields' => 'ids',
'include_unapproved' => array( 'foo@example.com', 4 ),
'status' => 'approve',
) );
$this->assertEqualSets( array( $c1, $c2, $c3, $c5 ), $found );
}
/**
* @ticket 19623
*/
public function test_get_comments_with_include_unapproved_mixed_comma_separated() {
$c1 = $this->factory->comment->create( array( 'comment_post_ID' => $this->post_id, 'user_id' => 7, 'comment_approved' => '1' ) );
$c2 = $this->factory->comment->create( array( 'comment_post_ID' => $this->post_id, 'user_id' => 0, 'comment_approved' => '1', 'comment_author' => 'foo', 'comment_author_email' => 'foo@example.com' ) );
$c3 = $this->factory->comment->create( array( 'comment_post_ID' => $this->post_id, 'user_id' => 0, 'comment_approved' => '0', 'comment_author' => 'foo', 'comment_author_email' => 'foo@example.com' ) );
$c4 = $this->factory->comment->create( array( 'comment_post_ID' => $this->post_id, 'user_id' => 0, 'comment_approved' => '0', 'comment_author' => 'foo', 'comment_author_email' => 'bar@example.com' ) );
$c5 = $this->factory->comment->create( array( 'comment_post_ID' => $this->post_id, 'user_id' => 4, 'comment_approved' => '0', 'comment_author' => 'foo', 'comment_author_email' => 'bar@example.com' ) );
$found = get_comments( array(
'fields' => 'ids',
'include_unapproved' => 'foo@example.com, 4',
'status' => 'approve',
) );
$this->assertEqualSets( array( $c1, $c2, $c3, $c5 ), $found );
}
}