diff --git a/wp-admin/includes/ajax-actions.php b/wp-admin/includes/ajax-actions.php index 4c7b84a396..eb2532d4c3 100644 --- a/wp-admin/includes/ajax-actions.php +++ b/wp-admin/includes/ajax-actions.php @@ -4034,7 +4034,7 @@ function wp_ajax_wp_privacy_export_personal_data() { wp_send_json_error( __( 'Invalid request ID.' ) ); } - if ( ! current_user_can( 'manage_options' ) ) { + if ( ! current_user_can( 'export_others_personal_data' ) ) { wp_send_json_error( __( 'Invalid request.' ) ); } @@ -4212,7 +4212,8 @@ function wp_ajax_wp_privacy_erase_personal_data() { wp_send_json_error( __( 'Invalid request ID.' ) ); } - if ( ! current_user_can( 'delete_users' ) ) { + // Both capabilities are required to avoid confusion, see `_wp_personal_data_removal_page()`. + if ( ! current_user_can( 'erase_others_personal_data' ) || ! current_user_can( 'delete_users' ) ) { wp_send_json_error( __( 'Invalid request.' ) ); } diff --git a/wp-admin/includes/user.php b/wp-admin/includes/user.php index d0b81dfc82..3acc63429a 100644 --- a/wp-admin/includes/user.php +++ b/wp-admin/includes/user.php @@ -744,8 +744,8 @@ function _wp_personal_data_cleanup_requests() { * @access private */ function _wp_personal_data_export_page() { - if ( ! current_user_can( 'manage_options' ) ) { - wp_die( esc_html__( 'Sorry, you are not allowed to manage privacy on this site.' ) ); + if ( ! current_user_can( 'export_others_personal_data' ) ) { + wp_die( __( 'Sorry, you are not allowed to export personal data on this site.' ) ); } _wp_personal_data_handle_actions(); @@ -809,8 +809,14 @@ function _wp_personal_data_export_page() { * @access private */ function _wp_personal_data_removal_page() { - if ( ! current_user_can( 'delete_users' ) ) { - wp_die( esc_html__( 'Sorry, you are not allowed to manage privacy on this site.' ) ); + /* + * Require both caps in order to make it explicitly clear that delegating + * erasure from network admins to single-site admins will give them the + * ability to affect global users, rather than being limited to the site + * that they administer. + */ + if ( ! current_user_can( 'erase_others_personal_data' ) || ! current_user_can( 'delete_users' ) ) { + wp_die( __( 'Sorry, you are not allowed to erase data on this site.' ) ); } _wp_personal_data_handle_actions(); @@ -876,8 +882,8 @@ function _wp_personal_data_removal_page() { * @access private */ function _wp_privacy_hook_requests_page() { - add_submenu_page( 'tools.php', __( 'Export Personal Data' ), __( 'Export Personal Data' ), 'manage_options', 'export_personal_data', '_wp_personal_data_export_page' ); - add_submenu_page( 'tools.php', __( 'Remove Personal Data' ), __( 'Remove Personal Data' ), 'manage_options', 'remove_personal_data', '_wp_personal_data_removal_page' ); + add_submenu_page( 'tools.php', __( 'Export Personal Data' ), __( 'Export Personal Data' ), 'export_others_personal_data', 'export_personal_data', '_wp_personal_data_export_page' ); + add_submenu_page( 'tools.php', __( 'Remove Personal Data' ), __( 'Remove Personal Data' ), 'erase_others_personal_data', 'remove_personal_data', '_wp_personal_data_removal_page' ); } // TODO: move the following classes in new files. diff --git a/wp-includes/capabilities.php b/wp-includes/capabilities.php index c5a921b7cc..1f8e1c964c 100644 --- a/wp-includes/capabilities.php +++ b/wp-includes/capabilities.php @@ -539,6 +539,10 @@ function map_meta_cap( $cap, $user_id ) { $caps[] = 'manage_options'; } break; + case 'export_others_personal_data': + case 'erase_others_personal_data': + $caps[] = is_multisite() ? 'manage_network' : 'manage_options'; + break; default: // Handle meta capabilities for custom post types. global $post_type_meta_caps; diff --git a/wp-includes/version.php b/wp-includes/version.php index c222ffc7e2..0d0a7b0deb 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -4,7 +4,7 @@ * * @global string $wp_version */ -$wp_version = '4.9.6-alpha-43110'; +$wp_version = '4.9.6-alpha-43111'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.