Make WordPress Core


Ignore:
Timestamp:
02/21/2023 01:43:33 AM (16 months ago)
Author:
peterwilsoncc
Message:

Comments: Prevent replying to unapproved comments.

Introduces client and server side validation to ensure the replytocom query string parameter can not be exploited to reply to an unapproved comment or display the name of an unapproved commenter.

This only affects commenting via the front end of the site. Comment replies via the dashboard continue their current behaviour of logging the reply and approving the parent comment.

Introduces the $post parameter, defaulting to the current global post, to get_cancel_comment_reply_link() and comment_form_title().

Introduces _get_comment_reply_id() for determining the comment reply ID based on the replytocom query string parameter.

Renames the parameter $post_id to $post in get_comment_id_fields() and comment_id_fields() to accept either a post ID or WP_Post object.

Adds a new WP_Error return state to wp_handle_comment_submission() to prevent replies to unapproved comments. The error code is comment_reply_to_unapproved_comment with the message Sorry, replies to unapproved comments are not allowed..

Props costdev, jrf, hellofromtonya, fasuto, boniu91, milana_cap.
Fixes #53962.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/comment-template.php

    r55346 r55369  
    19271927 *
    19281928 * @since 2.7.0
    1929  *
    1930  * @param string $text Optional. Text to display for cancel reply link. If empty,
    1931  *                     defaults to 'Click here to cancel reply'. Default empty.
     1929 * @since 6.2.0 Added the `$post` parameter.
     1930 *
     1931 * @param string           $text Optional. Text to display for cancel reply link. If empty,
     1932 *                               defaults to 'Click here to cancel reply'. Default empty.
     1933 * @param int|WP_Post|null $post Optional. The post the comment thread is being
     1934 *                               displayed for. Defaults to the current global post.
    19321935 * @return string
    19331936 */
    1934 function get_cancel_comment_reply_link( $text = '' ) {
     1937function get_cancel_comment_reply_link( $text = '', $post = null ) {
    19351938    if ( empty( $text ) ) {
    19361939        $text = __( 'Click here to cancel reply.' );
    19371940    }
    19381941
    1939     $style = isset( $_GET['replytocom'] ) ? '' : ' style="display:none;"';
    1940     $link  = esc_html( remove_query_arg( array( 'replytocom', 'unapproved', 'moderation-hash' ) ) ) . '#respond';
     1942    $post        = get_post( $post );
     1943    $reply_to_id = $post ? _get_comment_reply_id( $post->ID ) : 0;
     1944    $style       = 0 !== $reply_to_id ? '' : ' style="display:none;"';
     1945    $link        = esc_html( remove_query_arg( array( 'replytocom', 'unapproved', 'moderation-hash' ) ) ) . '#respond';
    19411946
    19421947    $formatted_link = '<a rel="nofollow" id="cancel-comment-reply-link" href="' . $link . '"' . $style . '>' . $text . '</a>';
     
    19701975 *
    19711976 * @since 3.0.0
    1972  *
    1973  * @param int $post_id Optional. Post ID. Defaults to the current post ID.
     1977 * @since 6.2.0 Renamed `$post_id` to `$post` and added WP_Post support.
     1978 *
     1979 * @param int|WP_Post|null $post Optional. The post the comment is being displayed for.
     1980 *                               Defaults to the current global post.
    19741981 * @return string Hidden input HTML for replying to comments.
    19751982 */
    1976 function get_comment_id_fields( $post_id = 0 ) {
    1977     if ( empty( $post_id ) ) {
    1978         $post_id = get_the_ID();
    1979     }
    1980 
    1981     $reply_to_id = isset( $_GET['replytocom'] ) ? (int) $_GET['replytocom'] : 0;
     1983function get_comment_id_fields( $post = null ) {
     1984    $post = get_post( $post );
     1985    if ( ! $post ) {
     1986        return '';
     1987    }
     1988
     1989    $post_id     = $post->ID;
     1990    $reply_to_id = _get_comment_reply_id( $post_id );
    19821991    $result      = "<input type='hidden' name='comment_post_ID' value='$post_id' id='comment_post_ID' />\n";
    19831992    $result     .= "<input type='hidden' name='comment_parent' id='comment_parent' value='$reply_to_id' />\n";
     
    20042013 *
    20052014 * @since 2.7.0
     2015 * @since 6.2.0 Renamed `$post_id` to `$post` and added WP_Post support.
    20062016 *
    20072017 * @see get_comment_id_fields()
    20082018 *
    2009  * @param int $post_id Optional. Post ID. Defaults to the current post ID.
    2010  */
    2011 function comment_id_fields( $post_id = 0 ) {
    2012     echo get_comment_id_fields( $post_id );
     2019 * @param int|WP_Post|null $post Optional. The post the comment is being displayed for.
     2020 *                               Defaults to the current global post.
     2021 */
     2022function comment_id_fields( $post = null ) {
     2023    echo get_comment_id_fields( $post );
    20132024}
    20142025
     
    20222033 *
    20232034 * @since 2.7.0
    2024  *
    2025  * @global WP_Comment $comment Global comment object.
    2026  *
    2027  * @param string|false $no_reply_text  Optional. Text to display when not replying to a comment.
    2028  *                                     Default false.
    2029  * @param string|false $reply_text     Optional. Text to display when replying to a comment.
    2030  *                                     Default false. Accepts "%s" for the author of the comment
    2031  *                                     being replied to.
    2032  * @param bool         $link_to_parent Optional. Boolean to control making the author's name a link
    2033  *                                     to their comment. Default true.
    2034  */
    2035 function comment_form_title( $no_reply_text = false, $reply_text = false, $link_to_parent = true ) {
    2036     global $comment;
    2037 
     2035 * @since 6.2.0 Added the `$post` parameter.
     2036 *
     2037 * @param string|false      $no_reply_text  Optional. Text to display when not replying to a comment.
     2038 *                                          Default false.
     2039 * @param string|false      $reply_text     Optional. Text to display when replying to a comment.
     2040 *                                          Default false. Accepts "%s" for the author of the comment
     2041 *                                          being replied to.
     2042 * @param bool              $link_to_parent Optional. Boolean to control making the author's name a link
     2043 *                                          to their comment. Default true.
     2044 * @param int|WP_Post|null  $post           Optional. The post that the comment form is being displayed for.
     2045 *                                          Defaults to the current global post.
     2046 */
     2047function comment_form_title( $no_reply_text = false, $reply_text = false, $link_to_parent = true, $post = null ) {
    20382048    if ( false === $no_reply_text ) {
    20392049        $no_reply_text = __( 'Leave a Reply' );
     
    20452055    }
    20462056
    2047     $reply_to_id = isset( $_GET['replytocom'] ) ? (int) $_GET['replytocom'] : 0;
    2048 
    2049     if ( 0 == $reply_to_id ) {
     2057    $post = get_post( $post );
     2058    if ( ! $post ) {
    20502059        echo $no_reply_text;
     2060        return;
     2061    }
     2062
     2063    $reply_to_id = _get_comment_reply_id( $post->ID );
     2064
     2065    if ( 0 === $reply_to_id ) {
     2066        echo $no_reply_text;
     2067        return;
     2068    }
     2069
     2070    if ( $link_to_parent ) {
     2071        $author = '<a href="#comment-' . get_comment_ID() . '">' . get_comment_author( $reply_to_id ) . '</a>';
    20512072    } else {
    2052         // Sets the global so that template tags can be used in the comment form.
    2053         $comment = get_comment( $reply_to_id );
    2054 
    2055         if ( $link_to_parent ) {
    2056             $author = '<a href="#comment-' . get_comment_ID() . '">' . get_comment_author( $comment ) . '</a>';
    2057         } else {
    2058             $author = get_comment_author( $comment );
    2059         }
    2060 
    2061         printf( $reply_text, $author );
    2062     }
     2073        $author = get_comment_author( $reply_to_id );
     2074    }
     2075
     2076    printf( $reply_text, $author );
     2077}
     2078
     2079/**
     2080 * Gets the comment's reply to ID from the $_GET['replytocom'].
     2081 *
     2082 * @since 6.2.0
     2083 *
     2084 * @access private
     2085 *
     2086 * @param int|WP_Post $post The post the comment is being displayed for.
     2087 *                          Defaults to the current global post.
     2088 * @return int Comment's reply to ID.
     2089 */
     2090function _get_comment_reply_id( $post = null ) {
     2091    $post = get_post( $post );
     2092
     2093    if ( ! $post || ! isset( $_GET['replytocom'] ) || ! is_numeric( $_GET['replytocom'] ) ) {
     2094        return 0;
     2095    }
     2096
     2097    $reply_to_id = (int) $_GET['replytocom'];
     2098
     2099    /*
     2100     * Validate the comment.
     2101     * Bail out if it does not exist, is not approved, or its
     2102     * `comment_post_ID` does not match the given post ID.
     2103     */
     2104    $comment = get_comment( $reply_to_id );
     2105
     2106    if (
     2107        ! $comment instanceof WP_Comment ||
     2108        0 === (int) $comment->comment_approved ||
     2109        $post->ID !== (int) $comment->comment_post_ID
     2110    ) {
     2111        return 0;
     2112    }
     2113
     2114    return $reply_to_id;
    20632115}
    20642116
     
    25712623        echo $args['title_reply_before'];
    25722624
    2573         comment_form_title( $args['title_reply'], $args['title_reply_to'] );
     2625        comment_form_title( $args['title_reply'], $args['title_reply_to'], true, $post_id );
    25742626
    25752627        if ( get_option( 'thread_comments' ) ) {
Note: See TracChangeset for help on using the changeset viewer.