Make WordPress Core

Changeset 42994


Ignore:
Timestamp:
04/20/2018 12:18:35 PM (6 years ago)
Author:
azaozz
Message:

Privacy: add functionality to anonymize commenters.

Props xkon, fclaussen, allendav, birgire, azaozz.
See #43442.

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/js/xfn.js

    r42989 r42994  
    7373            var summaryMessage = strings.noDataFound;
    7474            var classes = 'notice-success';
    75             if ( 0 == removedCount ) {
    76                 if ( 0 == retainedCount ) {
     75            if ( 0 === removedCount ) {
     76                if ( 0 === retainedCount ) {
    7777                    summaryMessage = strings.noDataFound;
    7878                } else {
     
    8181                }
    8282            } else {
    83                 if ( 0 == retainedCount ) {
     83                if ( 0 === retainedCount ) {
    8484                    summaryMessage = strings.foundAndRemoved;
    8585                } else {
  • trunk/src/wp-includes/comment.php

    r42987 r42994  
    33793379    );
    33803380}
     3381
     3382/**
     3383 * Registers the personal data eraser for comments.
     3384 *
     3385 * @since 4.9.6
     3386 *
     3387 * @param  array $erasers An array of personal data erasers.
     3388 * @return array $erasers An array of personal data erasers.
     3389 */
     3390function wp_register_comment_personal_data_eraser( $erasers ) {
     3391    $erasers[] = array(
     3392        'eraser_friendly_name' => __( 'WordPress Comments' ),
     3393        'callback'             => 'wp_comments_personal_data_eraser',
     3394    );
     3395
     3396    return $erasers;
     3397}
     3398
     3399/**
     3400 * Erases personal data associated with an email address from the comments table.
     3401 *
     3402 * @since 4.9.6
     3403 *
     3404 * @param  string $email_address The comment author email address.
     3405 * @param  int    $page          Comment page.
     3406 * @return array
     3407 */
     3408function wp_comments_personal_data_eraser( $email_address, $page = 1 ) {
     3409    global $wpdb;
     3410
     3411    if ( empty( $email_address ) ) {
     3412        return array(
     3413            'num_items_removed'  => 0,
     3414            'num_items_retained' => 0,
     3415            'messages'           => array(),
     3416            'done'               => true,
     3417        );
     3418    }
     3419
     3420    // Limit us to 500 comments at a time to avoid timing out.
     3421    $number            = 500;
     3422    $page              = (int) $page;
     3423    $num_items_removed = 0;
     3424
     3425    $comments = get_comments(
     3426        array(
     3427            'author_email'       => $email_address,
     3428            'number'             => $number,
     3429            'paged'              => $page,
     3430            'order_by'           => 'comment_ID',
     3431            'order'              => 'ASC',
     3432            'include_unapproved' => true,
     3433        )
     3434    );
     3435
     3436    $anon_author = __( 'Anonymous' );
     3437    $messages    = array();
     3438
     3439    foreach ( (array) $comments as $comment ) {
     3440        $anonymized_comment                         = array();
     3441        $anonymized_comment['comment_agent']        = '';
     3442        $anonymized_comment['comment_author']       = $anon_author;
     3443        $anonymized_comment['comment_author_email'] = wp_privacy_anonymize_data( 'email', $comment->comment_author_email );
     3444        $anonymized_comment['comment_author_IP']    = wp_privacy_anonymize_data( 'ip', $comment->comment_author_IP );
     3445        $anonymized_comment['comment_author_url']   = wp_privacy_anonymize_data( 'url', $comment->comment_author_url );
     3446        $anonymized_comment['user_id']              = 0;
     3447
     3448        $comment_id = (int) $comment->comment_ID;
     3449
     3450        /**
     3451         * Filters whether to anonymize the comment.
     3452         *
     3453         * @since 4.9.6
     3454         *
     3455         * @param bool|string                    Whether to apply the comment anonymization (bool).
     3456         *                                       Custom prevention message (string). Default true.
     3457         * @param WP_Comment $comment            WP_Comment object.
     3458         * @param array      $anonymized_comment Anonymized comment data.
     3459         */
     3460        $anon_message = apply_filters( 'wp_anonymize_comment', true, $comment, $anonymized_comment );
     3461
     3462        if ( true !== $anon_message ) {
     3463            if ( $anon_message && is_string( $anon_message ) ) {
     3464                $messages[] = esc_html( $anon_message );
     3465            } else {
     3466                /* translators: %d: Comment ID */
     3467                $messages[] = sprintf( __( 'Comment %d contains personal data but could not be anonymized.' ), $comment_id );
     3468            }
     3469
     3470            continue;
     3471        }
     3472
     3473        $args = array(
     3474            'comment_ID' => $comment_id,
     3475        );
     3476
     3477        $updated = $wpdb->update( $wpdb->comments, $anonymized_comment, $args );
     3478
     3479        if ( $updated ) {
     3480            $num_items_removed++;
     3481            clean_comment_cache( $comment_id );
     3482        }
     3483    }
     3484
     3485    $done = count( $comments ) < $number;
     3486
     3487    return array(
     3488        'num_items_removed'  => $num_items_removed,
     3489        'num_items_retained' => count( $comments ) - $num_items_removed,
     3490        'messages'           => $messages,
     3491        'done'               => $done,
     3492    );
     3493}
  • trunk/src/wp-includes/default-filters.php

    r42980 r42994  
    330330add_action( 'set_comment_cookies', 'wp_set_comment_cookies', 10, 3 );
    331331add_filter( 'wp_privacy_personal_data_exporters', 'wp_register_comment_personal_data_exporter', 10 );
     332add_filter( 'wp_privacy_personal_data_erasers', 'wp_register_comment_personal_data_eraser', 10 );
    332333add_action( 'sanitize_comment_cookies', 'sanitize_comment_cookies' );
    333334add_action( 'admin_print_scripts', 'print_emoji_detection_script' );
  • trunk/tests/phpunit/tests/comment.php

    r42987 r42994  
    813813    }
    814814
     815    /**
     816     * The `wp_comments_personal_data_eraser()` function should erase user's comments.
     817     *
     818     * @ticket 43442
     819     */
     820    public function test_wp_comments_personal_data_eraser() {
     821
     822        $post_id = self::factory()->post->create();
     823        $user_id = self::factory()->user->create();
     824
     825        $args       = array(
     826            'user_id'              => $user_id,
     827            'comment_post_ID'      => $post_id,
     828            'comment_author'       => 'Comment Author',
     829            'comment_author_email' => 'personal@local.host',
     830            'comment_author_url'   => 'https://local.host/',
     831            'comment_author_IP'    => '192.168.0.1',
     832            'comment_date'         => '2018-04-14 17:20:00',
     833            'comment_agent'        => 'COMMENT_AGENT',
     834            'comment_content'      => 'Comment Content',
     835        );
     836        $comment_id = self::factory()->comment->create( $args );
     837
     838        wp_comments_personal_data_eraser( $args['comment_author_email'] );
     839
     840        $comment = get_comment( $comment_id );
     841
     842        $actual = array(
     843            'comment_ID'           => $comment->comment_ID,
     844            'user_id'              => $comment->user_id,
     845            'comment_author'       => $comment->comment_author,
     846            'comment_author_email' => $comment->comment_author_email,
     847            'comment_author_url'   => $comment->comment_author_url,
     848            'comment_author_IP'    => $comment->comment_author_IP,
     849            'comment_date'         => $comment->comment_date,
     850            'comment_date_gmt'     => $comment->comment_date_gmt,
     851            'comment_agent'        => $comment->comment_agent,
     852            'comment_content'      => $comment->comment_content,
     853        );
     854
     855        $expected = array(
     856            'comment_ID'           => (string) $comment_id,
     857            'user_id'              => '0', // Anonymized.
     858            'comment_author'       => 'Anonymous', // Anonymized.
     859            'comment_author_email' => 'deleted@site.invalid', // Anonymized.
     860            'comment_author_url'   => 'https://site.invalid', // Anonymized.
     861            'comment_author_IP'    => '192.168.0.0', // Anonymized.
     862            'comment_date'         => '2018-04-14 17:20:00',
     863            'comment_date_gmt'     => '2018-04-14 17:20:00',
     864            'comment_agent'        => '', // Anonymized.
     865            'comment_content'      => 'Comment Content',
     866        );
     867
     868        $this->assertSame( $expected, $actual );
     869    }
     870
     871    /**
     872     * Testing the `wp_comments_personal_data_eraser()` function's output on an empty first page.
     873     *
     874     * @ticket 43442
     875     */
     876    public function test_wp_comments_personal_data_eraser_empty_first_page_output() {
     877
     878        $actual   = wp_comments_personal_data_eraser( 'nocommentsfound@local.host' );
     879        $expected = array(
     880            'num_items_removed'  => 0,
     881            'num_items_retained' => 0,
     882            'messages'           => array(),
     883            'done'               => true,
     884        );
     885
     886        $this->assertSame( $expected, $actual );
     887    }
     888
     889    /**
     890     * Testing the `wp_comments_personal_data_eraser()` function's output, for the non-empty first page.
     891     *
     892     * @ticket 43442
     893     */
     894    public function test_wp_comments_personal_data_eraser_non_empty_first_page_output() {
     895
     896        $post_id = self::factory()->post->create();
     897        $args    = array(
     898            'comment_post_ID'      => $post_id,
     899            'comment_author'       => 'Comment Author',
     900            'comment_author_email' => 'personal@local.host',
     901            'comment_author_url'   => 'https://local.host/',
     902            'comment_author_IP'    => '192.168.0.1',
     903            'comment_date'         => '2018-04-14 17:20:00',
     904            'comment_agent'        => 'COMMENT_AGENT',
     905            'comment_content'      => 'Comment Content',
     906        );
     907        self::factory()->comment->create( $args );
     908
     909        $actual   = wp_comments_personal_data_eraser( $args['comment_author_email'] );
     910        $expected = array(
     911            'num_items_removed'  => 1,
     912            'num_items_retained' => 0,
     913            'messages'           => array(),
     914            'done'               => true,
     915        );
     916
     917        $this->assertSame( $expected, $actual );
     918    }
     919
     920    /**
     921     * Testing the `wp_comments_personal_data_eraser()` function's output, for an empty second page.
     922     *
     923     * @ticket 43442
     924     */
     925    public function test_wp_comments_personal_data_eraser_empty_second_page_output() {
     926
     927        $post_id = self::factory()->post->create();
     928        $args    = array(
     929            'comment_post_ID'      => $post_id,
     930            'comment_author'       => 'Comment Author',
     931            'comment_author_email' => 'personal@local.host',
     932            'comment_author_url'   => 'https://local.host/',
     933            'comment_author_IP'    => '192.168.0.1',
     934            'comment_date'         => '2018-04-14 17:20:00',
     935            'comment_agent'        => 'COMMENT_AGENT',
     936            'comment_content'      => 'Comment Content',
     937        );
     938        self::factory()->comment->create( $args );
     939
     940        $actual   = wp_comments_personal_data_eraser( $args['comment_author_email'], 2 );
     941        $expected = array(
     942            'num_items_removed'  => 0,
     943            'num_items_retained' => 0,
     944            'messages'           => array(),
     945            'done'               => true,
     946        );
     947
     948        $this->assertSame( $expected, $actual );
     949    }
     950
     951    /**
     952     * Testing the `wp_anonymize_comment` filter, to prevent comment anonymization.
     953     *
     954     * @ticket 43442
     955     */
     956    public function test_wp_anonymize_comment_filter_to_prevent_comment_anonymization() {
     957
     958        $post_id    = self::factory()->post->create();
     959        $args       = array(
     960            'comment_post_ID'      => $post_id,
     961            'comment_author'       => 'Comment Author',
     962            'comment_author_email' => 'personal@local.host',
     963            'comment_author_url'   => 'https://local.host/',
     964            'comment_author_IP'    => '192.168.0.1',
     965            'comment_date'         => '2018-04-14 17:20:00',
     966            'comment_agent'        => 'COMMENT_AGENT',
     967            'comment_content'      => 'Comment Content',
     968        );
     969        $comment_id = self::factory()->comment->create( $args );
     970
     971        add_filter( 'wp_anonymize_comment', '__return_false' );
     972        $actual = wp_comments_personal_data_eraser( $args['comment_author_email'] );
     973        remove_filter( 'wp_anonymize_comment', '__return_false' );
     974
     975        $message = sprintf( 'Comment %d contains personal data but could not be anonymized.', $comment_id );
     976
     977        $expected = array(
     978            'num_items_removed'  => 0,
     979            'num_items_retained' => 1,
     980            'messages'           => array( $message ),
     981            'done'               => true,
     982        );
     983
     984        $this->assertSame( $expected, $actual );
     985    }
     986
     987    /**
     988     * Testing the `wp_anonymize_comment` filter, to prevent comment anonymization, with a custom message.
     989     *
     990     * @ticket 43442
     991     */
     992    public function test_wp_anonymize_comment_filter_to_prevent_comment_anonymization_with_custom_message() {
     993
     994        $post_id    = self::factory()->post->create();
     995        $args       = array(
     996            'comment_post_ID'      => $post_id,
     997            'comment_author'       => 'Comment Author',
     998            'comment_author_email' => 'personal@local.host',
     999            'comment_author_url'   => 'https://local.host/',
     1000            'comment_author_IP'    => '192.168.0.1',
     1001            'comment_date'         => '2018-04-14 17:20:00',
     1002            'comment_agent'        => 'COMMENT_AGENT',
     1003            'comment_content'      => 'Comment Content',
     1004        );
     1005        $comment_id = self::factory()->comment->create( $args );
     1006
     1007        add_filter( 'wp_anonymize_comment', array( $this, 'wp_anonymize_comment_custom_message' ), 10, 3 );
     1008        $actual = wp_comments_personal_data_eraser( $args['comment_author_email'] );
     1009        remove_filter( 'wp_anonymize_comment', array( $this, 'wp_anonymize_comment_custom_message' ) );
     1010
     1011        $message = sprintf( 'Some custom message for comment %d.', $comment_id );
     1012
     1013        $expected = array(
     1014            'num_items_removed'  => 0,
     1015            'num_items_retained' => 1,
     1016            'messages'           => array( $message ),
     1017            'done'               => true,
     1018        );
     1019
     1020        $this->assertSame( $expected, $actual );
     1021    }
     1022
     1023    /**
     1024     * Callback for the `wp_anonymize_comment` filter.
     1025     *
     1026     * @param  bool|string $anonymize          Whether to apply the comment anonymization (bool).
     1027     *                                         Custom prevention message (string). Default true.
     1028     * @param  WP_Comment  $comment            WP_Comment object.
     1029     * @param  array       $anonymized_comment Anonymized comment data.
     1030     * @return string
     1031     */
     1032    public function wp_anonymize_comment_custom_message( $anonymize, $comment, $anonymized_comment ) {
     1033        return sprintf( 'Some custom message for comment %d.', $comment->comment_ID );
     1034    }
     1035
    8151036    public function test_update_should_invalidate_comment_cache() {
    8161037        global $wpdb;
Note: See TracChangeset for help on using the changeset viewer.