Skip to content

Commit cdb3f04

Browse files
committed
Privacy: add means to erase personal data by username or email address. First run.
Props allendav, coreymckrill, ericdaams, azaozz. See #43637, #43602. git-svn-id: https://develop.svn.wordpress.org/trunk@42986 602fd350-edb4-49c9-b593-d223f7449a82
1 parent 7eb3daf commit cdb3f04

5 files changed

Lines changed: 451 additions & 56 deletions

File tree

src/wp-admin/admin-ajax.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@
130130
'get-community-events',
131131
'edit-theme-plugin-file',
132132
'wp-privacy-export-personal-data',
133+
'wp-privacy-erase-personal-data',
133134
);
134135

135136
// Deprecated

src/wp-admin/includes/ajax-actions.php

Lines changed: 198 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4328,10 +4328,10 @@ function wp_ajax_edit_theme_plugin_file() {
43284328
}
43294329

43304330
function wp_ajax_wp_privacy_export_personal_data() {
4331-
// check_ajax_referer( 'wp-privacy-export-personal-data', 'security' );
4331+
check_ajax_referer( 'wp-privacy-export-personal-data', 'security' );
43324332

43334333
if ( ! current_user_can( 'manage_options' ) ) {
4334-
wp_send_json_error( 'access denied' );
4334+
wp_send_json_error( __( 'Error: Invalid request.' ) );
43354335
}
43364336

43374337
$email_address = sanitize_text_field( $_POST['email'] );
@@ -4341,7 +4341,7 @@ function wp_ajax_wp_privacy_export_personal_data() {
43414341
/**
43424342
* Filters the array of exporter callbacks.
43434343
*
4344-
* @since 4.9.5.
4344+
* @since 4.9.6
43454345
*
43464346
* @param array $args {
43474347
* An array of callable exporters of personal data. Default empty array.
@@ -4429,7 +4429,7 @@ function wp_ajax_wp_privacy_export_personal_data() {
44294429
*
44304430
* Allows the export response to be consumed by destinations in addition to Ajax.
44314431
*
4432-
* @since 4.9.5
4432+
* @since 4.9.6
44334433
*
44344434
* @param array $response The personal data for the given exporter and page.
44354435
* @param int $exporter_index The index of the exporter that provided this data.
@@ -4443,3 +4443,197 @@ function wp_ajax_wp_privacy_export_personal_data() {
44434443

44444444
wp_send_json_success( $response );
44454445
}
4446+
4447+
/**
4448+
* Ajax handler for erasing personal data.
4449+
*
4450+
* @since 4.9.6
4451+
*/
4452+
function wp_ajax_wp_privacy_erase_personal_data() {
4453+
$request_id = (int) $_POST['id'];
4454+
4455+
if ( empty( $request_id ) ) {
4456+
wp_send_json_error( __( 'Error: Invalid request ID.' ) );
4457+
}
4458+
4459+
if ( ! current_user_can( 'delete_users' ) ) {
4460+
wp_send_json_error( __( 'Error: Invalid request.' ) );
4461+
}
4462+
4463+
check_ajax_referer( 'wp-privacy-erase-personal-data-' . $request_id, 'security' );
4464+
4465+
// Find the request CPT
4466+
$request = get_post( $request_id );
4467+
if ( 'user_remove_request' !== $request->post_type ) {
4468+
wp_send_json_error( __( 'Error: Invalid request ID.' ) );
4469+
}
4470+
4471+
$email_address = get_post_meta( $request_id, '_user_email', true );
4472+
4473+
if ( ! is_email( $email_address ) ) {
4474+
wp_send_json_error( __( 'Error: Invalid email address in request.' ) );
4475+
}
4476+
4477+
$eraser_index = (int) $_POST['eraser'];
4478+
$page = (int) $_POST['page'];
4479+
4480+
/**
4481+
* Filters the array of personal data eraser callbacks.
4482+
*
4483+
* @since 4.9.6
4484+
*
4485+
* @param array $args {
4486+
* An array of callable erasers of personal data. Default empty array.
4487+
* [
4488+
* callback string Callable eraser that accepts an email address and
4489+
* a page and returns an array with the number of items
4490+
* removed, the number of items retained and any messages
4491+
* from the eraser, as well as if additional pages are
4492+
* available.
4493+
* eraser_friendly_name string Translated user facing friendly name for the eraser.
4494+
* ]
4495+
* }
4496+
*/
4497+
$erasers = apply_filters( 'wp_privacy_personal_data_erasers', array() );
4498+
4499+
// Do we have any registered erasers?
4500+
if ( 0 < count( $erasers ) ) {
4501+
if ( $eraser_index < 1 ) {
4502+
wp_send_json_error( __( 'Error: Eraser index cannot be less than one.' ) );
4503+
}
4504+
4505+
if ( $eraser_index > count( $erasers ) ) {
4506+
wp_send_json_error( __( 'Error: Eraser index is out of range.' ) );
4507+
}
4508+
4509+
if ( $page < 1 ) {
4510+
wp_send_json_error( __( 'Error: Page index cannot be less than one.' ) );
4511+
}
4512+
4513+
$index = $eraser_index - 1; // Convert to zero based for eraser index
4514+
$eraser = $erasers[ $index ];
4515+
if ( ! is_array( $eraser ) ) {
4516+
wp_send_json_error(
4517+
sprintf(
4518+
__( 'Error: Expected an array describing the eraser at index %d.' ),
4519+
$eraser_index
4520+
)
4521+
);
4522+
}
4523+
if ( ! array_key_exists( 'callback', $eraser ) ) {
4524+
wp_send_json_error(
4525+
sprintf(
4526+
__( 'Error: Eraser array at index %d does not include a callback.' ),
4527+
$eraser_index
4528+
)
4529+
);
4530+
}
4531+
if ( ! is_callable( $eraser['callback'] ) ) {
4532+
wp_send_json_error(
4533+
sprintf(
4534+
__( 'Error: Eraser callback at index %d is not a valid callback.' ),
4535+
$eraser_index
4536+
)
4537+
);
4538+
}
4539+
if ( ! array_key_exists( 'eraser_friendly_name', $eraser ) ) {
4540+
wp_send_json_error(
4541+
sprintf(
4542+
__( 'Error: Eraser array at index %d does not include a friendly name.' ),
4543+
$eraser_index
4544+
)
4545+
);
4546+
}
4547+
4548+
$callback = $erasers[ $index ]['callback'];
4549+
$eraser_friendly_name = $erasers[ $index ]['eraser_friendly_name'];
4550+
4551+
$response = call_user_func( $callback, $email_address, $page );
4552+
if ( is_wp_error( $response ) ) {
4553+
wp_send_json_error( $response );
4554+
}
4555+
4556+
if ( ! is_array( $response ) ) {
4557+
wp_send_json_error(
4558+
sprintf(
4559+
__( 'Error: Did not receive array from %s eraser (index %d).' ),
4560+
$eraser_friendly_name,
4561+
$eraser_index
4562+
)
4563+
);
4564+
}
4565+
if ( ! array_key_exists( 'num_items_removed', $response ) ) {
4566+
wp_send_json_error(
4567+
sprintf(
4568+
__( 'Error: Expected num_items_removed key in response array from %s eraser (index %d).' ),
4569+
$eraser_friendly_name,
4570+
$eraser_index
4571+
)
4572+
);
4573+
}
4574+
if ( ! array_key_exists( 'num_items_retained', $response ) ) {
4575+
wp_send_json_error(
4576+
sprintf(
4577+
__( 'Error: Expected num_items_retained key in response array from %s eraser (index %d).' ),
4578+
$eraser_friendly_name,
4579+
$eraser_index
4580+
)
4581+
);
4582+
}
4583+
if ( ! array_key_exists( 'messages', $response ) ) {
4584+
wp_send_json_error(
4585+
sprintf(
4586+
__( 'Error: Expected messages key in response array from %s eraser (index %d).' ),
4587+
$eraser_friendly_name,
4588+
$eraser_index
4589+
)
4590+
);
4591+
}
4592+
if ( ! is_array( $response['messages'] ) ) {
4593+
wp_send_json_error(
4594+
sprintf(
4595+
__( 'Error: Expected messages key to reference an array in response array from %s eraser (index %d).' ),
4596+
$eraser_friendly_name,
4597+
$eraser_index
4598+
)
4599+
);
4600+
}
4601+
if ( ! array_key_exists( 'done', $response ) ) {
4602+
wp_send_json_error(
4603+
sprintf(
4604+
__( 'Error: Expected done flag in response array from %s eraser (index %d).' ),
4605+
$eraser_friendly_name,
4606+
$eraser_index
4607+
)
4608+
);
4609+
}
4610+
} else {
4611+
// No erasers, so we're done
4612+
$response = array(
4613+
'num_items_removed' => 0,
4614+
'num_items_retained' => 0,
4615+
'messages' => array(),
4616+
'done' => true,
4617+
);
4618+
}
4619+
4620+
/**
4621+
* Filters a page of personal data eraser data.
4622+
*
4623+
* Allows the erasure response to be consumed by destinations in addition to Ajax.
4624+
*
4625+
* @since 4.9.6
4626+
*
4627+
* @param array $response The personal data for the given exporter and page.
4628+
* @param int $exporter_index The index of the exporter that provided this data.
4629+
* @param string $email_address The email address associated with this personal data.
4630+
* @param int $page The zero-based page for this response.
4631+
* @param int $request_id The privacy request post ID associated with this request.
4632+
*/
4633+
$response = apply_filters( 'wp_privacy_personal_data_erasure_page', $response, $eraser_index, $email_address, $page, $request_id );
4634+
if ( is_wp_error( $response ) ) {
4635+
wp_send_json_error( $response );
4636+
}
4637+
4638+
wp_send_json_success( $response );
4639+
}

0 commit comments

Comments
 (0)