From d232910423ba5ca3d8c801c78de6c2bdb6640553 Mon Sep 17 00:00:00 2001 From: Jake Spurlock Date: Tue, 2 Jun 2020 20:10:02 +0000 Subject: [PATCH] Comments: Ensure that unmoderated comments won't be search indexed. After a comment is submitted, only allow a brief window where the comment is live on the site. Fixes #49956. Props: jonkolbert, ayeshrajans, Asif2BD, peterwilsoncc, imath, audrasjb, jonoaldersonwp, whyisjake. git-svn-id: https://develop.svn.wordpress.org/trunk@47887 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-comments-post.php | 4 +- src/wp-includes/class-walker-comment.php | 89 ++++++++++++++++------ src/wp-includes/class-wp-comment-query.php | 11 ++- src/wp-includes/class-wp.php | 4 + src/wp-includes/comment.php | 7 +- 5 files changed, 85 insertions(+), 30 deletions(-) diff --git a/src/wp-comments-post.php b/src/wp-comments-post.php index ebf658603d..59dacc2003 100644 --- a/src/wp-comments-post.php +++ b/src/wp-comments-post.php @@ -56,8 +56,8 @@ do_action( 'set_comment_cookies', $comment, $user, $cookies_consent ); $location = empty( $_POST['redirect_to'] ) ? get_comment_link( $comment ) : $_POST['redirect_to'] . '#comment-' . $comment->comment_ID; -// Add specific query arguments to display the awaiting moderation message. -if ( 'unapproved' === wp_get_comment_status( $comment ) && ! empty( $comment->comment_author_email ) ) { +// If user didn't consent to cookies, add specific query arguments to display the awaiting moderation message. +if ( ! $cookies_consent && 'unapproved' === wp_get_comment_status( $comment ) && ! empty( $comment->comment_author_email ) ) { $location = add_query_arg( array( 'unapproved' => $comment->comment_ID, diff --git a/src/wp-includes/class-walker-comment.php b/src/wp-includes/class-walker-comment.php index e7498b3dd6..ffe503d0fa 100644 --- a/src/wp-includes/class-walker-comment.php +++ b/src/wp-includes/class-walker-comment.php @@ -181,6 +181,10 @@ class Walker_Comment extends Walker { return; } + if ( 'comment' === $comment->comment_type ) { + add_filter( 'comment_text', array( $this, 'comment_text' ), 40, 2 ); + } + if ( ( 'pingback' === $comment->comment_type || 'trackback' === $comment->comment_type ) && $args['short_ping'] ) { ob_start(); $this->ping( $comment, $depth, $args ); @@ -194,6 +198,10 @@ class Walker_Comment extends Walker { $this->comment( $comment, $depth, $args ); $output .= ob_get_clean(); } + + if ( 'comment' === $comment->comment_type ) { + remove_filter( 'comment_text', array( $this, 'comment_text' ), 40, 2 ); + } } /** @@ -244,6 +252,26 @@ class Walker_Comment extends Walker { comment_approved && ! $show_pending_links ) { + return wp_kses( $comment_text, array() ); + } + + return $comment_text; + } + /** * Outputs a single comment. * @@ -264,7 +292,8 @@ class Walker_Comment extends Walker { $add_below = 'div-comment'; } - $commenter = wp_get_current_commenter(); + $commenter = wp_get_current_commenter(); + $show_pending_links = isset( $commenter['comment_author'] ) && $commenter['comment_author']; if ( $commenter['comment_author_email'] ) { $moderation_note = __( 'Your comment is awaiting moderation.' ); } else { @@ -279,14 +308,19 @@ class Walker_Comment extends Walker {
says:' ), - sprintf( '%s', get_comment_author_link( $comment ) ) - ); + $comment_author = get_comment_author_link( $comment ); + if ( '0' == $comment->comment_approved && ! $show_pending_links ) { + $comment_author = get_comment_author( $comment ); + } + printf( + /* translators: %s: Comment author link. */ + __( '%s says:' ), + sprintf( '%s', $comment_author ) + ); ?>
comment_approved ) : ?> @@ -354,7 +388,8 @@ class Walker_Comment extends Walker { protected function html5_comment( $comment, $depth, $args ) { $tag = ( 'div' === $args['style'] ) ? 'div' : 'li'; - $commenter = wp_get_current_commenter(); + $commenter = wp_get_current_commenter(); + $show_pending_links = ! empty( $commenter['comment_author'] ); if ( $commenter['comment_author_email'] ) { $moderation_note = __( 'Your comment is awaiting moderation.' ); } else { @@ -372,11 +407,15 @@ class Walker_Comment extends Walker { } ?> says:' ), - sprintf( '%s', get_comment_author_link( $comment ) ) - ); + $comment_author = get_comment_author_link( $comment ); + if ( '0' == $comment->comment_approved && ! $show_pending_links ) { + $comment_author = get_comment_author( $comment ); + } + printf( + /* translators: %s: Comment author link. */ + __( '%s says:' ), + sprintf( '%s', $comment_author ) + ); ?> @@ -402,18 +441,20 @@ class Walker_Comment extends Walker { 'div-comment', - 'depth' => $depth, - 'max_depth' => $args['max_depth'], - 'before' => '
', - 'after' => '
', + if ( '1' == $comment->comment_approved || $show_pending_links ) { + comment_reply_link( + array_merge( + $args, + array( + 'add_below' => 'div-comment', + 'depth' => $depth, + 'max_depth' => $args['max_depth'], + 'before' => '
', + 'after' => '
', + ) ) - ) - ); + ); + } ?> 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 ); + // Otherwise we match against email addresses. + if ( ! empty( $_GET['unapproved'] ) && ! empty( $_GET['moderation-hash'] ) ) { + // Only include requested comment. + $approved_clauses[] = $wpdb->prepare( "( comment_author_email = %s AND comment_approved = '0' AND comment_ID = %d )", $unapproved_identifier, (int) $_GET['unapproved'] ); + } else { + // Include all of the author's unapproved comments. + $approved_clauses[] = $wpdb->prepare( "( comment_author_email = %s AND comment_approved = '0' )", $unapproved_identifier ); + } } } } diff --git a/src/wp-includes/class-wp.php b/src/wp-includes/class-wp.php index 42ff3dba6d..e26e348563 100644 --- a/src/wp-includes/class-wp.php +++ b/src/wp-includes/class-wp.php @@ -404,6 +404,10 @@ class WP { if ( is_user_logged_in() ) { $headers = array_merge( $headers, wp_get_nocache_headers() ); + } elseif ( ! empty( $_GET['unapproved'] ) && ! empty( $_GET['moderation-hash'] ) ) { + // Unmoderated comments are only visible for one minute via the moderation hash. + $headers['Expires'] = gmdate( 'D, d M Y H:i:s', time() + MINUTE_IN_SECONDS ); + $headers['Cache-Control'] = 'max-age=60, must-revalidate'; } if ( ! empty( $this->query_vars['error'] ) ) { $status = (int) $this->query_vars['error']; diff --git a/src/wp-includes/comment.php b/src/wp-includes/comment.php index a57cf275f8..bf576d35b0 100644 --- a/src/wp-includes/comment.php +++ b/src/wp-includes/comment.php @@ -1852,7 +1852,12 @@ function wp_get_unapproved_comment_author_email() { $comment = get_comment( $comment_id ); if ( $comment && hash_equals( $_GET['moderation-hash'], wp_hash( $comment->comment_date_gmt ) ) ) { - $commenter_email = $comment->comment_author_email; + // The comment will only be viewable by the comment author for 1 minute. + $comment_preview_expires = strtotime( $comment->comment_date_gmt . '+1 minute' ); + + if ( time() < $comment_preview_expires ) { + $commenter_email = $comment->comment_author_email; + } } }