Make WordPress Core

Changeset 43080


Ignore:
Timestamp:
05/02/2018 12:20:31 AM (8 years ago)
Author:
SergeyBiryukov
Message:

Privacy: add functionality to anonymize commenters.

Props xkon, fclaussen, allendav, birgire, azaozz.
Merges [42994] to the 4.9 branch.
See #43442.

Location:
branches/4.9
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • branches/4.9

  • branches/4.9/src/wp-admin/js/xfn.js

    r43078 r43080  
    6868                        var summaryMessage = strings.noDataFound;
    6969                        var classes = 'notice-success';
    70                         if ( 0 == removedCount ) {
    71                                 if ( 0 == retainedCount ) {
     70                        if ( 0 === removedCount ) {
     71                                if ( 0 === retainedCount ) {
    7272                                        summaryMessage = strings.noDataFound;
    7373                                } else {
     
    7676                                }
    7777                        } else {
    78                                 if ( 0 == retainedCount ) {
     78                                if ( 0 === retainedCount ) {
    7979                                        summaryMessage = strings.foundAndRemoved;
    8080                                } else {
  • branches/4.9/src/wp-includes/comment.php

    r43079 r43080  
    32503250        );
    32513251}
     3252
     3253/**
     3254 * Registers the personal data eraser for comments.
     3255 *
     3256 * @since 4.9.6
     3257 *
     3258 * @param  array $erasers An array of personal data erasers.
     3259 * @return array $erasers An array of personal data erasers.
     3260 */
     3261function wp_register_comment_personal_data_eraser( $erasers ) {
     3262        $erasers[] = array(
     3263                'eraser_friendly_name' => __( 'WordPress Comments' ),
     3264                'callback'             => 'wp_comments_personal_data_eraser',
     3265        );
     3266
     3267        return $erasers;
     3268}
     3269
     3270/**
     3271 * Erases personal data associated with an email address from the comments table.
     3272 *
     3273 * @since 4.9.6
     3274 *
     3275 * @param  string $email_address The comment author email address.
     3276 * @param  int    $page          Comment page.
     3277 * @return array
     3278 */
     3279function wp_comments_personal_data_eraser( $email_address, $page = 1 ) {
     3280        global $wpdb;
     3281
     3282        if ( empty( $email_address ) ) {
     3283                return array(
     3284                        'num_items_removed'  => 0,
     3285                        'num_items_retained' => 0,
     3286                        'messages'           => array(),
     3287                        'done'               => true,
     3288                );
     3289        }
     3290
     3291        // Limit us to 500 comments at a time to avoid timing out.
     3292        $number            = 500;
     3293        $page              = (int) $page;
     3294        $num_items_removed = 0;
     3295
     3296        $comments = get_comments(
     3297                array(
     3298                        'author_email'       => $email_address,
     3299                        'number'             => $number,
     3300                        'paged'              => $page,
     3301                        'order_by'           => 'comment_ID',
     3302                        'order'              => 'ASC',
     3303                        'include_unapproved' => true,
     3304                )
     3305        );
     3306
     3307        $anon_author = __( 'Anonymous' );
     3308        $messages    = array();
     3309
     3310        foreach ( (array) $comments as $comment ) {
     3311                $anonymized_comment                         = array();
     3312                $anonymized_comment['comment_agent']        = '';
     3313                $anonymized_comment['comment_author']       = $anon_author;
     3314                $anonymized_comment['comment_author_email'] = wp_privacy_anonymize_data( 'email', $comment->comment_author_email );
     3315                $anonymized_comment['comment_author_IP']    = wp_privacy_anonymize_data( 'ip', $comment->comment_author_IP );
     3316                $anonymized_comment['comment_author_url']   = wp_privacy_anonymize_data( 'url', $comment->comment_author_url );
     3317                $anonymized_comment['user_id']              = 0;
     3318
     3319                $comment_id = (int) $comment->comment_ID;
     3320
     3321                /**
     3322                 * Filters whether to anonymize the comment.
     3323                 *
     3324                 * @since 4.9.6
     3325                 *
     3326                 * @param bool|string                    Whether to apply the comment anonymization (bool).
     3327                 *                                       Custom prevention message (string). Default true.
     3328                 * @param WP_Comment $comment            WP_Comment object.
     3329                 * @param array      $anonymized_comment Anonymized comment data.
     3330                 */
     3331                $anon_message = apply_filters( 'wp_anonymize_comment', true, $comment, $anonymized_comment );
     3332
     3333                if ( true !== $anon_message ) {
     3334                        if ( $anon_message && is_string( $anon_message ) ) {
     3335                                $messages[] = esc_html( $anon_message );
     3336                        } else {
     3337                                /* translators: %d: Comment ID */
     3338                                $messages[] = sprintf( __( 'Comment %d contains personal data but could not be anonymized.' ), $comment_id );
     3339                        }
     3340
     3341                        continue;
     3342                }
     3343
     3344                $args = array(
     3345                        'comment_ID' => $comment_id,
     3346                );
     3347
     3348                $updated = $wpdb->update( $wpdb->comments, $anonymized_comment, $args );
     3349
     3350                if ( $updated ) {
     3351                        $num_items_removed++;
     3352                        clean_comment_cache( $comment_id );
     3353                }
     3354        }
     3355
     3356        $done = count( $comments ) < $number;
     3357
     3358        return array(
     3359                'num_items_removed'  => $num_items_removed,
     3360                'num_items_retained' => count( $comments ) - $num_items_removed,
     3361                'messages'           => $messages,
     3362                'done'               => $done,
     3363        );
     3364}
  • branches/4.9/src/wp-includes/default-filters.php

    r43076 r43080  
    303303add_action( 'set_comment_cookies',        'wp_set_comment_cookies',                  10, 2 );
    304304add_filter( 'wp_privacy_personal_data_exporters', 'wp_register_comment_personal_data_exporter', 10 );
     305add_filter( 'wp_privacy_personal_data_erasers', 'wp_register_comment_personal_data_eraser', 10 );
    305306add_action( 'sanitize_comment_cookies',   'sanitize_comment_cookies'                       );
    306307add_action( 'admin_print_scripts',        'print_emoji_detection_script'                   );
  • branches/4.9/tests/phpunit/tests/comment.php

    r43077 r43080  
    701701        }
    702702
     703        /**
     704         * The `wp_comments_personal_data_eraser()` function should erase user's comments.
     705         *
     706         * @ticket 43442
     707         */
     708        public function test_wp_comments_personal_data_eraser() {
     709
     710                $post_id = self::factory()->post->create();
     711                $user_id = self::factory()->user->create();
     712
     713                $args       = array(
     714                        'user_id'              => $user_id,
     715                        'comment_post_ID'      => $post_id,
     716                        'comment_author'       => 'Comment Author',
     717                        'comment_author_email' => 'personal@local.host',
     718                        'comment_author_url'   => 'https://local.host/',
     719                        'comment_author_IP'    => '192.168.0.1',
     720                        'comment_date'         => '2018-04-14 17:20:00',
     721                        'comment_agent'        => 'COMMENT_AGENT',
     722                        'comment_content'      => 'Comment Content',
     723                );
     724                $comment_id = self::factory()->comment->create( $args );
     725
     726                wp_comments_personal_data_eraser( $args['comment_author_email'] );
     727
     728                $comment = get_comment( $comment_id );
     729
     730                $actual = array(
     731                        'comment_ID'           => $comment->comment_ID,
     732                        'user_id'              => $comment->user_id,
     733                        'comment_author'       => $comment->comment_author,
     734                        'comment_author_email' => $comment->comment_author_email,
     735                        'comment_author_url'   => $comment->comment_author_url,
     736                        'comment_author_IP'    => $comment->comment_author_IP,
     737                        'comment_date'         => $comment->comment_date,
     738                        'comment_date_gmt'     => $comment->comment_date_gmt,
     739                        'comment_agent'        => $comment->comment_agent,
     740                        'comment_content'      => $comment->comment_content,
     741                );
     742
     743                $expected = array(
     744                        'comment_ID'           => (string) $comment_id,
     745                        'user_id'              => '0', // Anonymized.
     746                        'comment_author'       => 'Anonymous', // Anonymized.
     747                        'comment_author_email' => 'deleted@site.invalid', // Anonymized.
     748                        'comment_author_url'   => 'https://site.invalid', // Anonymized.
     749                        'comment_author_IP'    => '192.168.0.0', // Anonymized.
     750                        'comment_date'         => '2018-04-14 17:20:00',
     751                        'comment_date_gmt'     => '2018-04-14 17:20:00',
     752                        'comment_agent'        => '', // Anonymized.
     753                        'comment_content'      => 'Comment Content',
     754                );
     755
     756                $this->assertSame( $expected, $actual );
     757        }
     758
     759        /**
     760         * Testing the `wp_comments_personal_data_eraser()` function's output on an empty first page.
     761         *
     762         * @ticket 43442
     763         */
     764        public function test_wp_comments_personal_data_eraser_empty_first_page_output() {
     765
     766                $actual   = wp_comments_personal_data_eraser( 'nocommentsfound@local.host' );
     767                $expected = array(
     768                        'num_items_removed'  => 0,
     769                        'num_items_retained' => 0,
     770                        'messages'           => array(),
     771                        'done'               => true,
     772                );
     773
     774                $this->assertSame( $expected, $actual );
     775        }
     776
     777        /**
     778         * Testing the `wp_comments_personal_data_eraser()` function's output, for the non-empty first page.
     779         *
     780         * @ticket 43442
     781         */
     782        public function test_wp_comments_personal_data_eraser_non_empty_first_page_output() {
     783
     784                $post_id = self::factory()->post->create();
     785                $args    = array(
     786                        'comment_post_ID'      => $post_id,
     787                        'comment_author'       => 'Comment Author',
     788                        'comment_author_email' => 'personal@local.host',
     789                        'comment_author_url'   => 'https://local.host/',
     790                        'comment_author_IP'    => '192.168.0.1',
     791                        'comment_date'         => '2018-04-14 17:20:00',
     792                        'comment_agent'        => 'COMMENT_AGENT',
     793                        'comment_content'      => 'Comment Content',
     794                );
     795                self::factory()->comment->create( $args );
     796
     797                $actual   = wp_comments_personal_data_eraser( $args['comment_author_email'] );
     798                $expected = array(
     799                        'num_items_removed'  => 1,
     800                        'num_items_retained' => 0,
     801                        'messages'           => array(),
     802                        'done'               => true,
     803                );
     804
     805                $this->assertSame( $expected, $actual );
     806        }
     807
     808        /**
     809         * Testing the `wp_comments_personal_data_eraser()` function's output, for an empty second page.
     810         *
     811         * @ticket 43442
     812         */
     813        public function test_wp_comments_personal_data_eraser_empty_second_page_output() {
     814
     815                $post_id = self::factory()->post->create();
     816                $args    = array(
     817                        'comment_post_ID'      => $post_id,
     818                        'comment_author'       => 'Comment Author',
     819                        'comment_author_email' => 'personal@local.host',
     820                        'comment_author_url'   => 'https://local.host/',
     821                        'comment_author_IP'    => '192.168.0.1',
     822                        'comment_date'         => '2018-04-14 17:20:00',
     823                        'comment_agent'        => 'COMMENT_AGENT',
     824                        'comment_content'      => 'Comment Content',
     825                );
     826                self::factory()->comment->create( $args );
     827
     828                $actual   = wp_comments_personal_data_eraser( $args['comment_author_email'], 2 );
     829                $expected = array(
     830                        'num_items_removed'  => 0,
     831                        'num_items_retained' => 0,
     832                        'messages'           => array(),
     833                        'done'               => true,
     834                );
     835
     836                $this->assertSame( $expected, $actual );
     837        }
     838
     839        /**
     840         * Testing the `wp_anonymize_comment` filter, to prevent comment anonymization.
     841         *
     842         * @ticket 43442
     843         */
     844        public function test_wp_anonymize_comment_filter_to_prevent_comment_anonymization() {
     845
     846                $post_id    = self::factory()->post->create();
     847                $args       = array(
     848                        'comment_post_ID'      => $post_id,
     849                        'comment_author'       => 'Comment Author',
     850                        'comment_author_email' => 'personal@local.host',
     851                        'comment_author_url'   => 'https://local.host/',
     852                        'comment_author_IP'    => '192.168.0.1',
     853                        'comment_date'         => '2018-04-14 17:20:00',
     854                        'comment_agent'        => 'COMMENT_AGENT',
     855                        'comment_content'      => 'Comment Content',
     856                );
     857                $comment_id = self::factory()->comment->create( $args );
     858
     859                add_filter( 'wp_anonymize_comment', '__return_false' );
     860                $actual = wp_comments_personal_data_eraser( $args['comment_author_email'] );
     861                remove_filter( 'wp_anonymize_comment', '__return_false' );
     862
     863                $message = sprintf( 'Comment %d contains personal data but could not be anonymized.', $comment_id );
     864
     865                $expected = array(
     866                        'num_items_removed'  => 0,
     867                        'num_items_retained' => 1,
     868                        'messages'           => array( $message ),
     869                        'done'               => true,
     870                );
     871
     872                $this->assertSame( $expected, $actual );
     873        }
     874
     875        /**
     876         * Testing the `wp_anonymize_comment` filter, to prevent comment anonymization, with a custom message.
     877         *
     878         * @ticket 43442
     879         */
     880        public function test_wp_anonymize_comment_filter_to_prevent_comment_anonymization_with_custom_message() {
     881
     882                $post_id    = self::factory()->post->create();
     883                $args       = array(
     884                        'comment_post_ID'      => $post_id,
     885                        'comment_author'       => 'Comment Author',
     886                        'comment_author_email' => 'personal@local.host',
     887                        'comment_author_url'   => 'https://local.host/',
     888                        'comment_author_IP'    => '192.168.0.1',
     889                        'comment_date'         => '2018-04-14 17:20:00',
     890                        'comment_agent'        => 'COMMENT_AGENT',
     891                        'comment_content'      => 'Comment Content',
     892                );
     893                $comment_id = self::factory()->comment->create( $args );
     894
     895                add_filter( 'wp_anonymize_comment', array( $this, 'wp_anonymize_comment_custom_message' ), 10, 3 );
     896                $actual = wp_comments_personal_data_eraser( $args['comment_author_email'] );
     897                remove_filter( 'wp_anonymize_comment', array( $this, 'wp_anonymize_comment_custom_message' ) );
     898
     899                $message = sprintf( 'Some custom message for comment %d.', $comment_id );
     900
     901                $expected = array(
     902                        'num_items_removed'  => 0,
     903                        'num_items_retained' => 1,
     904                        'messages'           => array( $message ),
     905                        'done'               => true,
     906                );
     907
     908                $this->assertSame( $expected, $actual );
     909        }
     910
     911        /**
     912         * Callback for the `wp_anonymize_comment` filter.
     913         *
     914         * @param  bool|string $anonymize          Whether to apply the comment anonymization (bool).
     915         *                                         Custom prevention message (string). Default true.
     916         * @param  WP_Comment  $comment            WP_Comment object.
     917         * @param  array       $anonymized_comment Anonymized comment data.
     918         * @return string
     919         */
     920        public function wp_anonymize_comment_custom_message( $anonymize, $comment, $anonymized_comment ) {
     921                return sprintf( 'Some custom message for comment %d.', $comment->comment_ID );
     922        }
     923
    703924        public function test_update_should_invalidate_comment_cache() {
    704925                global $wpdb;
Note: See TracChangeset for help on using the changeset viewer.