WordPress.org

Make WordPress Core

Ticket #43442: 43442.6.diff

File 43442.6.diff, 13.0 KB (added by birgire, 4 years ago)
  • src/wp-includes/comment.php

    diff --git src/wp-includes/comment.php src/wp-includes/comment.php
    index d3f8cc6..db2b9ed 100644
    function wp_comments_personal_data_exporter( $email_address, $page = 1 ) { 
    33783378                'done' => $done,
    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        // Limit us to 500 comments at a time to avoid timing out.
     3412        $number            = 500;
     3413        $page              = (int) $page;
     3414        $num_items_removed = 0;
     3415
     3416        $comments = get_comments(
     3417                array(
     3418                        'author_email'       => $email_address,
     3419                        'number'             => $number,
     3420                        'paged'              => $page,
     3421                        'order_by'           => 'comment_ID',
     3422                        'order'              => 'ASC',
     3423                        'include_unapproved' => true,
     3424                )
     3425        );
     3426
     3427        $anon_author = __( 'Anonymous' );
     3428        $messages    = array();
     3429
     3430        foreach ( (array) $comments as $comment ) {
     3431                $anonymized_comment                         = array();
     3432                $anonymized_comment['comment_agent']        = '';
     3433                $anonymized_comment['comment_author']       = $anon_author;
     3434                $anonymized_comment['comment_author_email'] = wp_privacy_anonymize_data( 'email', $comment->comment_author_email );
     3435                $anonymized_comment['comment_author_IP']    = wp_privacy_anonymize_data( 'ip', $comment->comment_author_IP );
     3436                $anonymized_comment['comment_author_url']   = wp_privacy_anonymize_data( 'url', $comment->comment_author_url );
     3437                $anonymized_comment['user_id']              = 0;
     3438
     3439                $comment_id = (int) $comment->comment_ID;
     3440
     3441                /**
     3442                 * Filters whether to anonymize the comment.
     3443                 *
     3444                 * @since 4.9.6
     3445                 *
     3446                 * @param bool|string                    Whether to apply the comment anonymization (bool).
     3447                 *                                       Custom prevention message (string). Default true.
     3448                 * @param WP_Comment $comment            WP_Comment object.
     3449                 * @param array      $anonymized_comment Anonymized comment data.
     3450                 */
     3451                $anon_message = apply_filters( 'wp_anonymize_comment', true, $comment, $anonymized_comment );
     3452
     3453                if ( true !== $anon_message ) {
     3454                        if ( $anon_message && is_string( $anon_message ) ) {
     3455                                $messages[] = esc_html( $anon_message );
     3456                        } else {
     3457                                /* translators: %d: Comment ID */
     3458                                $messages[] = sprintf( __( 'Comment %d contains personal data but could not be anonymized.' ), $comment_id );
     3459                        }
     3460
     3461                        continue;
     3462                }
     3463
     3464                $args = array(
     3465                        'comment_ID' => $comment_id,
     3466                );
     3467
     3468                $updated = $wpdb->update( $wpdb->comments, $anonymized_comment, $args );
     3469
     3470                if ( $updated ) {
     3471                        $num_items_removed++;
     3472                } else {
     3473                        $edit_url = admin_url( 'comment.php?action=editcomment&c=' . $comment_id );
     3474
     3475                        /* translators: %d: Comment ID */
     3476                        $msg = sprintf( __( 'An error occured while anonymizing comment %d.' ), $comment_id );
     3477
     3478                        /* translators: 1: Edit comment url, 2: Edit comment text, 3: accessibility text */
     3479                        $msg .= sprintf(
     3480                                '<a href="%1$s" target="_blank" class="external-link" rel="noreferrer noopener">%2$s<span class="screen-reader-text">%3$s</span></a>',
     3481                                esc_url( $edit_url ),
     3482                                __( 'Try to edit or delete it separately.' ),
     3483                                __( '(opens in a new tab)' )
     3484                        );
     3485
     3486                        $messages[] = $msg;
     3487                }
     3488
     3489                clean_comment_cache( $comment_id );
     3490        }
     3491
     3492        $done = count( $comments ) < $number;
     3493
     3494        return array(
     3495                'num_items_removed'  => $num_items_removed,
     3496                'num_items_retained' => count( $comments ) - $num_items_removed,
     3497                'messages'           => $messages,
     3498                'done'               => $done,
     3499        );
     3500}
  • src/wp-includes/default-filters.php

    diff --git src/wp-includes/default-filters.php src/wp-includes/default-filters.php
    index bd8500e..510a045 100644
    add_action( 'do_pings', 'do_all_pings', 10, 1 ); 
    329329add_action( 'do_robots', 'do_robots' );
    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' );
    334335add_action( 'admin_print_scripts', 'print_head_scripts', 20 );
  • tests/phpunit/tests/comment.php

    diff --git tests/phpunit/tests/comment.php tests/phpunit/tests/comment.php
    index 4193473..2945317 100644
    class Tests_Comment extends WP_UnitTestCase { 
    812812                }
    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;
    8171038