Privacy: add functionality to anonymize commenters.
Props xkon, fclaussen, allendav, birgire, azaozz. See #43442. git-svn-id: https://develop.svn.wordpress.org/trunk@42994 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
parent
ad13b8bbda
commit
7e26130f12
@ -72,15 +72,15 @@ jQuery( document ).ready( function( $ ) {
|
||||
set_action_state( $action, 'remove_personal_data_idle' );
|
||||
var summaryMessage = strings.noDataFound;
|
||||
var classes = 'notice-success';
|
||||
if ( 0 == removedCount ) {
|
||||
if ( 0 == retainedCount ) {
|
||||
if ( 0 === removedCount ) {
|
||||
if ( 0 === retainedCount ) {
|
||||
summaryMessage = strings.noDataFound;
|
||||
} else {
|
||||
summaryMessage = strings.noneRemoved;
|
||||
classes = 'notice-warning';
|
||||
}
|
||||
} else {
|
||||
if ( 0 == retainedCount ) {
|
||||
if ( 0 === retainedCount ) {
|
||||
summaryMessage = strings.foundAndRemoved;
|
||||
} else {
|
||||
summaryMessage = strings.someNotRemoved;
|
||||
|
@ -3378,3 +3378,116 @@ function wp_comments_personal_data_exporter( $email_address, $page = 1 ) {
|
||||
'done' => $done,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the personal data eraser for comments.
|
||||
*
|
||||
* @since 4.9.6
|
||||
*
|
||||
* @param array $erasers An array of personal data erasers.
|
||||
* @return array $erasers An array of personal data erasers.
|
||||
*/
|
||||
function wp_register_comment_personal_data_eraser( $erasers ) {
|
||||
$erasers[] = array(
|
||||
'eraser_friendly_name' => __( 'WordPress Comments' ),
|
||||
'callback' => 'wp_comments_personal_data_eraser',
|
||||
);
|
||||
|
||||
return $erasers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Erases personal data associated with an email address from the comments table.
|
||||
*
|
||||
* @since 4.9.6
|
||||
*
|
||||
* @param string $email_address The comment author email address.
|
||||
* @param int $page Comment page.
|
||||
* @return array
|
||||
*/
|
||||
function wp_comments_personal_data_eraser( $email_address, $page = 1 ) {
|
||||
global $wpdb;
|
||||
|
||||
if ( empty( $email_address ) ) {
|
||||
return array(
|
||||
'num_items_removed' => 0,
|
||||
'num_items_retained' => 0,
|
||||
'messages' => array(),
|
||||
'done' => true,
|
||||
);
|
||||
}
|
||||
|
||||
// Limit us to 500 comments at a time to avoid timing out.
|
||||
$number = 500;
|
||||
$page = (int) $page;
|
||||
$num_items_removed = 0;
|
||||
|
||||
$comments = get_comments(
|
||||
array(
|
||||
'author_email' => $email_address,
|
||||
'number' => $number,
|
||||
'paged' => $page,
|
||||
'order_by' => 'comment_ID',
|
||||
'order' => 'ASC',
|
||||
'include_unapproved' => true,
|
||||
)
|
||||
);
|
||||
|
||||
$anon_author = __( 'Anonymous' );
|
||||
$messages = array();
|
||||
|
||||
foreach ( (array) $comments as $comment ) {
|
||||
$anonymized_comment = array();
|
||||
$anonymized_comment['comment_agent'] = '';
|
||||
$anonymized_comment['comment_author'] = $anon_author;
|
||||
$anonymized_comment['comment_author_email'] = wp_privacy_anonymize_data( 'email', $comment->comment_author_email );
|
||||
$anonymized_comment['comment_author_IP'] = wp_privacy_anonymize_data( 'ip', $comment->comment_author_IP );
|
||||
$anonymized_comment['comment_author_url'] = wp_privacy_anonymize_data( 'url', $comment->comment_author_url );
|
||||
$anonymized_comment['user_id'] = 0;
|
||||
|
||||
$comment_id = (int) $comment->comment_ID;
|
||||
|
||||
/**
|
||||
* Filters whether to anonymize the comment.
|
||||
*
|
||||
* @since 4.9.6
|
||||
*
|
||||
* @param bool|string Whether to apply the comment anonymization (bool).
|
||||
* Custom prevention message (string). Default true.
|
||||
* @param WP_Comment $comment WP_Comment object.
|
||||
* @param array $anonymized_comment Anonymized comment data.
|
||||
*/
|
||||
$anon_message = apply_filters( 'wp_anonymize_comment', true, $comment, $anonymized_comment );
|
||||
|
||||
if ( true !== $anon_message ) {
|
||||
if ( $anon_message && is_string( $anon_message ) ) {
|
||||
$messages[] = esc_html( $anon_message );
|
||||
} else {
|
||||
/* translators: %d: Comment ID */
|
||||
$messages[] = sprintf( __( 'Comment %d contains personal data but could not be anonymized.' ), $comment_id );
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$args = array(
|
||||
'comment_ID' => $comment_id,
|
||||
);
|
||||
|
||||
$updated = $wpdb->update( $wpdb->comments, $anonymized_comment, $args );
|
||||
|
||||
if ( $updated ) {
|
||||
$num_items_removed++;
|
||||
clean_comment_cache( $comment_id );
|
||||
}
|
||||
}
|
||||
|
||||
$done = count( $comments ) < $number;
|
||||
|
||||
return array(
|
||||
'num_items_removed' => $num_items_removed,
|
||||
'num_items_retained' => count( $comments ) - $num_items_removed,
|
||||
'messages' => $messages,
|
||||
'done' => $done,
|
||||
);
|
||||
}
|
||||
|
@ -329,6 +329,7 @@ add_action( 'do_pings', 'do_all_pings', 10, 1 );
|
||||
add_action( 'do_robots', 'do_robots' );
|
||||
add_action( 'set_comment_cookies', 'wp_set_comment_cookies', 10, 3 );
|
||||
add_filter( 'wp_privacy_personal_data_exporters', 'wp_register_comment_personal_data_exporter', 10 );
|
||||
add_filter( 'wp_privacy_personal_data_erasers', 'wp_register_comment_personal_data_eraser', 10 );
|
||||
add_action( 'sanitize_comment_cookies', 'sanitize_comment_cookies' );
|
||||
add_action( 'admin_print_scripts', 'print_emoji_detection_script' );
|
||||
add_action( 'admin_print_scripts', 'print_head_scripts', 20 );
|
||||
|
@ -812,6 +812,227 @@ class Tests_Comment extends WP_UnitTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The `wp_comments_personal_data_eraser()` function should erase user's comments.
|
||||
*
|
||||
* @ticket 43442
|
||||
*/
|
||||
public function test_wp_comments_personal_data_eraser() {
|
||||
|
||||
$post_id = self::factory()->post->create();
|
||||
$user_id = self::factory()->user->create();
|
||||
|
||||
$args = array(
|
||||
'user_id' => $user_id,
|
||||
'comment_post_ID' => $post_id,
|
||||
'comment_author' => 'Comment Author',
|
||||
'comment_author_email' => 'personal@local.host',
|
||||
'comment_author_url' => 'https://local.host/',
|
||||
'comment_author_IP' => '192.168.0.1',
|
||||
'comment_date' => '2018-04-14 17:20:00',
|
||||
'comment_agent' => 'COMMENT_AGENT',
|
||||
'comment_content' => 'Comment Content',
|
||||
);
|
||||
$comment_id = self::factory()->comment->create( $args );
|
||||
|
||||
wp_comments_personal_data_eraser( $args['comment_author_email'] );
|
||||
|
||||
$comment = get_comment( $comment_id );
|
||||
|
||||
$actual = array(
|
||||
'comment_ID' => $comment->comment_ID,
|
||||
'user_id' => $comment->user_id,
|
||||
'comment_author' => $comment->comment_author,
|
||||
'comment_author_email' => $comment->comment_author_email,
|
||||
'comment_author_url' => $comment->comment_author_url,
|
||||
'comment_author_IP' => $comment->comment_author_IP,
|
||||
'comment_date' => $comment->comment_date,
|
||||
'comment_date_gmt' => $comment->comment_date_gmt,
|
||||
'comment_agent' => $comment->comment_agent,
|
||||
'comment_content' => $comment->comment_content,
|
||||
);
|
||||
|
||||
$expected = array(
|
||||
'comment_ID' => (string) $comment_id,
|
||||
'user_id' => '0', // Anonymized.
|
||||
'comment_author' => 'Anonymous', // Anonymized.
|
||||
'comment_author_email' => 'deleted@site.invalid', // Anonymized.
|
||||
'comment_author_url' => 'https://site.invalid', // Anonymized.
|
||||
'comment_author_IP' => '192.168.0.0', // Anonymized.
|
||||
'comment_date' => '2018-04-14 17:20:00',
|
||||
'comment_date_gmt' => '2018-04-14 17:20:00',
|
||||
'comment_agent' => '', // Anonymized.
|
||||
'comment_content' => 'Comment Content',
|
||||
);
|
||||
|
||||
$this->assertSame( $expected, $actual );
|
||||
}
|
||||
|
||||
/**
|
||||
* Testing the `wp_comments_personal_data_eraser()` function's output on an empty first page.
|
||||
*
|
||||
* @ticket 43442
|
||||
*/
|
||||
public function test_wp_comments_personal_data_eraser_empty_first_page_output() {
|
||||
|
||||
$actual = wp_comments_personal_data_eraser( 'nocommentsfound@local.host' );
|
||||
$expected = array(
|
||||
'num_items_removed' => 0,
|
||||
'num_items_retained' => 0,
|
||||
'messages' => array(),
|
||||
'done' => true,
|
||||
);
|
||||
|
||||
$this->assertSame( $expected, $actual );
|
||||
}
|
||||
|
||||
/**
|
||||
* Testing the `wp_comments_personal_data_eraser()` function's output, for the non-empty first page.
|
||||
*
|
||||
* @ticket 43442
|
||||
*/
|
||||
public function test_wp_comments_personal_data_eraser_non_empty_first_page_output() {
|
||||
|
||||
$post_id = self::factory()->post->create();
|
||||
$args = array(
|
||||
'comment_post_ID' => $post_id,
|
||||
'comment_author' => 'Comment Author',
|
||||
'comment_author_email' => 'personal@local.host',
|
||||
'comment_author_url' => 'https://local.host/',
|
||||
'comment_author_IP' => '192.168.0.1',
|
||||
'comment_date' => '2018-04-14 17:20:00',
|
||||
'comment_agent' => 'COMMENT_AGENT',
|
||||
'comment_content' => 'Comment Content',
|
||||
);
|
||||
self::factory()->comment->create( $args );
|
||||
|
||||
$actual = wp_comments_personal_data_eraser( $args['comment_author_email'] );
|
||||
$expected = array(
|
||||
'num_items_removed' => 1,
|
||||
'num_items_retained' => 0,
|
||||
'messages' => array(),
|
||||
'done' => true,
|
||||
);
|
||||
|
||||
$this->assertSame( $expected, $actual );
|
||||
}
|
||||
|
||||
/**
|
||||
* Testing the `wp_comments_personal_data_eraser()` function's output, for an empty second page.
|
||||
*
|
||||
* @ticket 43442
|
||||
*/
|
||||
public function test_wp_comments_personal_data_eraser_empty_second_page_output() {
|
||||
|
||||
$post_id = self::factory()->post->create();
|
||||
$args = array(
|
||||
'comment_post_ID' => $post_id,
|
||||
'comment_author' => 'Comment Author',
|
||||
'comment_author_email' => 'personal@local.host',
|
||||
'comment_author_url' => 'https://local.host/',
|
||||
'comment_author_IP' => '192.168.0.1',
|
||||
'comment_date' => '2018-04-14 17:20:00',
|
||||
'comment_agent' => 'COMMENT_AGENT',
|
||||
'comment_content' => 'Comment Content',
|
||||
);
|
||||
self::factory()->comment->create( $args );
|
||||
|
||||
$actual = wp_comments_personal_data_eraser( $args['comment_author_email'], 2 );
|
||||
$expected = array(
|
||||
'num_items_removed' => 0,
|
||||
'num_items_retained' => 0,
|
||||
'messages' => array(),
|
||||
'done' => true,
|
||||
);
|
||||
|
||||
$this->assertSame( $expected, $actual );
|
||||
}
|
||||
|
||||
/**
|
||||
* Testing the `wp_anonymize_comment` filter, to prevent comment anonymization.
|
||||
*
|
||||
* @ticket 43442
|
||||
*/
|
||||
public function test_wp_anonymize_comment_filter_to_prevent_comment_anonymization() {
|
||||
|
||||
$post_id = self::factory()->post->create();
|
||||
$args = array(
|
||||
'comment_post_ID' => $post_id,
|
||||
'comment_author' => 'Comment Author',
|
||||
'comment_author_email' => 'personal@local.host',
|
||||
'comment_author_url' => 'https://local.host/',
|
||||
'comment_author_IP' => '192.168.0.1',
|
||||
'comment_date' => '2018-04-14 17:20:00',
|
||||
'comment_agent' => 'COMMENT_AGENT',
|
||||
'comment_content' => 'Comment Content',
|
||||
);
|
||||
$comment_id = self::factory()->comment->create( $args );
|
||||
|
||||
add_filter( 'wp_anonymize_comment', '__return_false' );
|
||||
$actual = wp_comments_personal_data_eraser( $args['comment_author_email'] );
|
||||
remove_filter( 'wp_anonymize_comment', '__return_false' );
|
||||
|
||||
$message = sprintf( 'Comment %d contains personal data but could not be anonymized.', $comment_id );
|
||||
|
||||
$expected = array(
|
||||
'num_items_removed' => 0,
|
||||
'num_items_retained' => 1,
|
||||
'messages' => array( $message ),
|
||||
'done' => true,
|
||||
);
|
||||
|
||||
$this->assertSame( $expected, $actual );
|
||||
}
|
||||
|
||||
/**
|
||||
* Testing the `wp_anonymize_comment` filter, to prevent comment anonymization, with a custom message.
|
||||
*
|
||||
* @ticket 43442
|
||||
*/
|
||||
public function test_wp_anonymize_comment_filter_to_prevent_comment_anonymization_with_custom_message() {
|
||||
|
||||
$post_id = self::factory()->post->create();
|
||||
$args = array(
|
||||
'comment_post_ID' => $post_id,
|
||||
'comment_author' => 'Comment Author',
|
||||
'comment_author_email' => 'personal@local.host',
|
||||
'comment_author_url' => 'https://local.host/',
|
||||
'comment_author_IP' => '192.168.0.1',
|
||||
'comment_date' => '2018-04-14 17:20:00',
|
||||
'comment_agent' => 'COMMENT_AGENT',
|
||||
'comment_content' => 'Comment Content',
|
||||
);
|
||||
$comment_id = self::factory()->comment->create( $args );
|
||||
|
||||
add_filter( 'wp_anonymize_comment', array( $this, 'wp_anonymize_comment_custom_message' ), 10, 3 );
|
||||
$actual = wp_comments_personal_data_eraser( $args['comment_author_email'] );
|
||||
remove_filter( 'wp_anonymize_comment', array( $this, 'wp_anonymize_comment_custom_message' ) );
|
||||
|
||||
$message = sprintf( 'Some custom message for comment %d.', $comment_id );
|
||||
|
||||
$expected = array(
|
||||
'num_items_removed' => 0,
|
||||
'num_items_retained' => 1,
|
||||
'messages' => array( $message ),
|
||||
'done' => true,
|
||||
);
|
||||
|
||||
$this->assertSame( $expected, $actual );
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for the `wp_anonymize_comment` filter.
|
||||
*
|
||||
* @param bool|string $anonymize Whether to apply the comment anonymization (bool).
|
||||
* Custom prevention message (string). Default true.
|
||||
* @param WP_Comment $comment WP_Comment object.
|
||||
* @param array $anonymized_comment Anonymized comment data.
|
||||
* @return string
|
||||
*/
|
||||
public function wp_anonymize_comment_custom_message( $anonymize, $comment, $anonymized_comment ) {
|
||||
return sprintf( 'Some custom message for comment %d.', $comment->comment_ID );
|
||||
}
|
||||
|
||||
public function test_update_should_invalidate_comment_cache() {
|
||||
global $wpdb;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user