diff -r 3d4e9c994f10 -r a86126ab1dd4 wp/wp-admin/includes/user.php --- a/wp/wp-admin/includes/user.php Tue Oct 22 16:11:46 2019 +0200 +++ b/wp/wp-admin/includes/user.php Tue Dec 15 13:49:49 2020 +0100 @@ -25,7 +25,7 @@ * @since 2.0.0 * * @param int $user_id Optional. User ID. - * @return int|WP_Error user id of the updated user. + * @return int|WP_Error User ID of the updated user. */ function edit_user( $user_id = 0 ) { $wp_roles = wp_roles(); @@ -41,10 +41,11 @@ } if ( ! $update && isset( $_POST['user_login'] ) ) { - $user->user_login = sanitize_user( $_POST['user_login'], true ); + $user->user_login = sanitize_user( wp_unslash( $_POST['user_login'] ), true ); } - $pass1 = $pass2 = ''; + $pass1 = ''; + $pass2 = ''; if ( isset( $_POST['pass1'] ) ) { $pass1 = $_POST['pass1']; } @@ -69,7 +70,7 @@ */ if ( ( is_multisite() && current_user_can( 'manage_network_users' ) ) || - $user_id !== get_current_user_id() || + get_current_user_id() !== $user_id || ( $potential_role && $potential_role->has_cap( 'promote_users' ) ) ) { $user->role = $new_role; @@ -80,7 +81,7 @@ $user->user_email = sanitize_text_field( wp_unslash( $_POST['email'] ) ); } if ( isset( $_POST['url'] ) ) { - if ( empty( $_POST['url'] ) || $_POST['url'] == 'http://' ) { + if ( empty( $_POST['url'] ) || 'http://' === $_POST['url'] ) { $user->user_url = ''; } else { $user->user_url = esc_url_raw( $_POST['url'] ); @@ -111,28 +112,27 @@ } } + if ( isset( $_POST['locale'] ) ) { + $locale = sanitize_text_field( $_POST['locale'] ); + if ( 'site-default' === $locale ) { + $locale = ''; + } elseif ( '' === $locale ) { + $locale = 'en_US'; + } elseif ( ! in_array( $locale, get_available_languages(), true ) ) { + $locale = ''; + } + + $user->locale = $locale; + } + if ( $update ) { $user->rich_editing = isset( $_POST['rich_editing'] ) && 'false' === $_POST['rich_editing'] ? 'false' : 'true'; $user->syntax_highlighting = isset( $_POST['syntax_highlighting'] ) && 'false' === $_POST['syntax_highlighting'] ? 'false' : 'true'; $user->admin_color = isset( $_POST['admin_color'] ) ? sanitize_text_field( $_POST['admin_color'] ) : 'fresh'; $user->show_admin_bar_front = isset( $_POST['admin_bar_front'] ) ? 'true' : 'false'; - $user->locale = ''; - - if ( isset( $_POST['locale'] ) ) { - $locale = sanitize_text_field( $_POST['locale'] ); - if ( 'site-default' === $locale ) { - $locale = ''; - } elseif ( '' === $locale ) { - $locale = 'en_US'; - } elseif ( ! in_array( $locale, get_available_languages(), true ) ) { - $locale = ''; - } - - $user->locale = $locale; - } } - $user->comment_shortcuts = isset( $_POST['comment_shortcuts'] ) && 'true' == $_POST['comment_shortcuts'] ? 'true' : ''; + $user->comment_shortcuts = isset( $_POST['comment_shortcuts'] ) && 'true' === $_POST['comment_shortcuts'] ? 'true' : ''; $user->use_ssl = 0; if ( ! empty( $_POST['use_ssl'] ) ) { @@ -142,13 +142,13 @@ $errors = new WP_Error(); /* checking that username has been typed */ - if ( $user->user_login == '' ) { - $errors->add( 'user_login', __( 'ERROR: Please enter a username.' ) ); + if ( '' === $user->user_login ) { + $errors->add( 'user_login', __( 'Error: Please enter a username.' ) ); } /* checking that nickname has been typed */ if ( $update && empty( $user->nickname ) ) { - $errors->add( 'nickname', __( 'ERROR: Please enter a nickname.' ) ); + $errors->add( 'nickname', __( 'Error: Please enter a nickname.' ) ); } /** @@ -164,17 +164,17 @@ // Check for blank password when adding a user. if ( ! $update && empty( $pass1 ) ) { - $errors->add( 'pass', __( 'ERROR: Please enter a password.' ), array( 'form-field' => 'pass1' ) ); + $errors->add( 'pass', __( 'Error: Please enter a password.' ), array( 'form-field' => 'pass1' ) ); } // Check for "\" in password. if ( false !== strpos( wp_unslash( $pass1 ), '\\' ) ) { - $errors->add( 'pass', __( 'ERROR: Passwords may not contain the character "\\".' ), array( 'form-field' => 'pass1' ) ); + $errors->add( 'pass', __( 'Error: Passwords may not contain the character "\\".' ), array( 'form-field' => 'pass1' ) ); } // Checking the password has been typed twice the same. if ( ( $update || ! empty( $pass1 ) ) && $pass1 != $pass2 ) { - $errors->add( 'pass', __( 'ERROR: Please enter the same password in both password fields.' ), array( 'form-field' => 'pass1' ) ); + $errors->add( 'pass', __( 'Error: Passwords don’t match. Please enter the same password in both password fields.' ), array( 'form-field' => 'pass1' ) ); } if ( ! empty( $pass1 ) ) { @@ -182,27 +182,30 @@ } if ( ! $update && isset( $_POST['user_login'] ) && ! validate_username( $_POST['user_login'] ) ) { - $errors->add( 'user_login', __( 'ERROR: This username is invalid because it uses illegal characters. Please enter a valid username.' ) ); + $errors->add( 'user_login', __( 'Error: This username is invalid because it uses illegal characters. Please enter a valid username.' ) ); } if ( ! $update && username_exists( $user->user_login ) ) { - $errors->add( 'user_login', __( 'ERROR: This username is already registered. Please choose another one.' ) ); + $errors->add( 'user_login', __( 'Error: This username is already registered. Please choose another one.' ) ); } /** This filter is documented in wp-includes/user.php */ $illegal_logins = (array) apply_filters( 'illegal_user_logins', array() ); - if ( in_array( strtolower( $user->user_login ), array_map( 'strtolower', $illegal_logins ) ) ) { - $errors->add( 'invalid_username', __( 'ERROR: Sorry, that username is not allowed.' ) ); + if ( in_array( strtolower( $user->user_login ), array_map( 'strtolower', $illegal_logins ), true ) ) { + $errors->add( 'invalid_username', __( 'Error: Sorry, that username is not allowed.' ) ); } /* checking email address */ if ( empty( $user->user_email ) ) { - $errors->add( 'empty_email', __( 'ERROR: Please enter an email address.' ), array( 'form-field' => 'email' ) ); + $errors->add( 'empty_email', __( 'Error: Please enter an email address.' ), array( 'form-field' => 'email' ) ); } elseif ( ! is_email( $user->user_email ) ) { - $errors->add( 'invalid_email', __( 'ERROR: The email address isn’t correct.' ), array( 'form-field' => 'email' ) ); - } elseif ( ( $owner_id = email_exists( $user->user_email ) ) && ( ! $update || ( $owner_id != $user->ID ) ) ) { - $errors->add( 'email_exists', __( 'ERROR: This email is already registered, please choose another one.' ), array( 'form-field' => 'email' ) ); + $errors->add( 'invalid_email', __( 'Error: The email address isn’t correct.' ), array( 'form-field' => 'email' ) ); + } else { + $owner_id = email_exists( $user->user_email ); + if ( $owner_id && ( ! $update || ( $owner_id != $user->ID ) ) ) { + $errors->add( 'email_exists', __( 'Error: This email is already registered. Please choose another one.' ), array( 'form-field' => 'email' ) ); + } } /** @@ -211,7 +214,7 @@ * @since 2.8.0 * * @param WP_Error $errors WP_Error object (passed by reference). - * @param bool $update Whether this is a user update. + * @param bool $update Whether this is a user update. * @param stdClass $user User object (passed by reference). */ do_action_ref_array( 'user_profile_update_errors', array( &$errors, $update, &$user ) ); @@ -355,12 +358,14 @@ * Fires immediately before a user is deleted from the database. * * @since 2.0.0 + * @since 5.5.0 Added the `$user` parameter. * * @param int $id ID of the user to delete. * @param int|null $reassign ID of the user to reassign posts and links to. * Default null, for no reassignment. + * @param WP_User $user WP_User object of the user to delete. */ - do_action( 'delete_user', $id, $reassign ); + do_action( 'delete_user', $id, $reassign, $user ); if ( null === $reassign ) { $post_types_to_delete = array(); @@ -389,7 +394,7 @@ } } - // Clean links + // Clean links. $link_ids = $wpdb->get_col( $wpdb->prepare( "SELECT link_id FROM $wpdb->links WHERE link_owner = %d", $id ) ); if ( $link_ids ) { @@ -414,7 +419,7 @@ } } - // FINALLY, delete user + // FINALLY, delete user. if ( is_multisite() ) { remove_user_from_blog( $id, get_current_blog_id() ); } else { @@ -432,12 +437,14 @@ * Fires immediately after a user is deleted from the database. * * @since 2.9.0 + * @since 5.5.0 Added the `$user` parameter. * * @param int $id ID of the deleted user. * @param int|null $reassign ID of the user to reassign posts and links to. * Default null, for no reassignment. + * @param WP_User $user WP_User object of the deleted user. */ - do_action( 'deleted_user', $id, $reassign ); + do_action( 'deleted_user', $id, $reassign, $user ); return true; } @@ -470,8 +477,10 @@ return; } - // get_user_setting = JS saved UI setting. else no-js-fallback code. - if ( 'hide' == get_user_setting( 'default_password_nag' ) || isset( $_GET['default_password_nag'] ) && '0' == $_GET['default_password_nag'] ) { + // get_user_setting() = JS-saved UI setting. Else no-js-fallback code. + if ( 'hide' === get_user_setting( 'default_password_nag' ) + || isset( $_GET['default_password_nag'] ) && '0' == $_GET['default_password_nag'] + ) { delete_user_setting( 'default_password_nag' ); update_user_option( $user_ID, 'default_password_nag', false, true ); } @@ -506,7 +515,7 @@ function default_password_nag() { global $pagenow; // Short-circuit it. - if ( 'profile.php' == $pagenow || ! get_user_option( 'default_password_nag' ) ) { + if ( 'profile.php' === $pagenow || ! get_user_option( 'default_password_nag' ) ) { return; } @@ -547,7 +556,7 @@ * * @since 2.7.0 * - * @param object $user User data object. + * @param WP_User $user User data object. */ function use_ssl_preference( $user ) { ?> @@ -559,14 +568,17 @@ } /** + * @since MU (3.0.0) + * * @param string $text * @return string */ function admin_created_user_email( $text ) { $roles = get_editable_roles(); $role = $roles[ $_REQUEST['role'] ]; - /* translators: 1: site name, 2: site URL, 3: role */ + return sprintf( + /* translators: 1: Site title, 2: Site URL, 3: User role. */ __( 'Hi, You\'ve been invited to join \'%1$s\' at @@ -582,1142 +594,3 @@ wp_specialchars_decode( translate_user_role( $role['name'] ) ) ); } - -/** - * Resend an existing request and return the result. - * - * @since 4.9.6 - * @access private - * - * @param int $request_id Request ID. - * @return bool|WP_Error Returns true/false based on the success of sending the email, or a WP_Error object. - */ -function _wp_privacy_resend_request( $request_id ) { - $request_id = absint( $request_id ); - $request = get_post( $request_id ); - - if ( ! $request || 'user_request' !== $request->post_type ) { - return new WP_Error( 'privacy_request_error', __( 'Invalid request.' ) ); - } - - $result = wp_send_user_request( $request_id ); - - if ( is_wp_error( $result ) ) { - return $result; - } elseif ( ! $result ) { - return new WP_Error( 'privacy_request_error', __( 'Unable to initiate confirmation request.' ) ); - } - - return true; -} - -/** - * Marks a request as completed by the admin and logs the current timestamp. - * - * @since 4.9.6 - * @access private - * - * @param int $request_id Request ID. - * @return int|WP_Error $result Request ID on success or WP_Error. - */ -function _wp_privacy_completed_request( $request_id ) { - $request_id = absint( $request_id ); - $request = wp_get_user_request_data( $request_id ); - - if ( ! $request ) { - return new WP_Error( 'privacy_request_error', __( 'Invalid request.' ) ); - } - - update_post_meta( $request_id, '_wp_user_request_completed_timestamp', time() ); - - $result = wp_update_post( - array( - 'ID' => $request_id, - 'post_status' => 'request-completed', - ) - ); - - return $result; -} - -/** - * Handle list table actions. - * - * @since 4.9.6 - * @access private - */ -function _wp_personal_data_handle_actions() { - if ( isset( $_POST['privacy_action_email_retry'] ) ) { - check_admin_referer( 'bulk-privacy_requests' ); - - $request_id = absint( current( array_keys( (array) wp_unslash( $_POST['privacy_action_email_retry'] ) ) ) ); - $result = _wp_privacy_resend_request( $request_id ); - - if ( is_wp_error( $result ) ) { - add_settings_error( - 'privacy_action_email_retry', - 'privacy_action_email_retry', - $result->get_error_message(), - 'error' - ); - } else { - add_settings_error( - 'privacy_action_email_retry', - 'privacy_action_email_retry', - __( 'Confirmation request sent again successfully.' ), - 'updated' - ); - } - } elseif ( isset( $_POST['action'] ) ) { - $action = isset( $_POST['action'] ) ? sanitize_key( wp_unslash( $_POST['action'] ) ) : ''; - - switch ( $action ) { - case 'add_export_personal_data_request': - case 'add_remove_personal_data_request': - check_admin_referer( 'personal-data-request' ); - - if ( ! isset( $_POST['type_of_action'], $_POST['username_or_email_for_privacy_request'] ) ) { - add_settings_error( - 'action_type', - 'action_type', - __( 'Invalid action.' ), - 'error' - ); - } - $action_type = sanitize_text_field( wp_unslash( $_POST['type_of_action'] ) ); - $username_or_email_address = sanitize_text_field( wp_unslash( $_POST['username_or_email_for_privacy_request'] ) ); - $email_address = ''; - - if ( ! in_array( $action_type, _wp_privacy_action_request_types(), true ) ) { - add_settings_error( - 'action_type', - 'action_type', - __( 'Invalid action.' ), - 'error' - ); - } - - if ( ! is_email( $username_or_email_address ) ) { - $user = get_user_by( 'login', $username_or_email_address ); - if ( ! $user instanceof WP_User ) { - add_settings_error( - 'username_or_email_for_privacy_request', - 'username_or_email_for_privacy_request', - __( 'Unable to add this request. A valid email address or username must be supplied.' ), - 'error' - ); - } else { - $email_address = $user->user_email; - } - } else { - $email_address = $username_or_email_address; - } - - if ( empty( $email_address ) ) { - break; - } - - $request_id = wp_create_user_request( $email_address, $action_type ); - - if ( is_wp_error( $request_id ) ) { - add_settings_error( - 'username_or_email_for_privacy_request', - 'username_or_email_for_privacy_request', - $request_id->get_error_message(), - 'error' - ); - break; - } elseif ( ! $request_id ) { - add_settings_error( - 'username_or_email_for_privacy_request', - 'username_or_email_for_privacy_request', - __( 'Unable to initiate confirmation request.' ), - 'error' - ); - break; - } - - wp_send_user_request( $request_id ); - - add_settings_error( - 'username_or_email_for_privacy_request', - 'username_or_email_for_privacy_request', - __( 'Confirmation request initiated successfully.' ), - 'updated' - ); - break; - } - } -} - -/** - * Cleans up failed and expired requests before displaying the list table. - * - * @since 4.9.6 - * @access private - */ -function _wp_personal_data_cleanup_requests() { - /** This filter is documented in wp-includes/user.php */ - $expires = (int) apply_filters( 'user_request_key_expiration', DAY_IN_SECONDS ); - - $requests_query = new WP_Query( - array( - 'post_type' => 'user_request', - 'posts_per_page' => -1, - 'post_status' => 'request-pending', - 'fields' => 'ids', - 'date_query' => array( - array( - 'column' => 'post_modified_gmt', - 'before' => $expires . ' seconds ago', - ), - ), - ) - ); - - $request_ids = $requests_query->posts; - - foreach ( $request_ids as $request_id ) { - wp_update_post( - array( - 'ID' => $request_id, - 'post_status' => 'request-failed', - 'post_password' => '', - ) - ); - } -} - -/** - * Personal data export. - * - * @since 4.9.6 - * @access private - */ -function _wp_personal_data_export_page() { - 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(); - _wp_personal_data_cleanup_requests(); - - // "Borrow" xfn.js for now so we don't have to create new files. - wp_enqueue_script( 'xfn' ); - - $requests_table = new WP_Privacy_Data_Export_Requests_Table( - array( - 'plural' => 'privacy_requests', - 'singular' => 'privacy_request', - 'screen' => 'export_personal_data', - ) - ); - - $requests_table->screen->set_screen_reader_content( - array( - 'heading_views' => __( 'Filter export personal data list' ), - 'heading_pagination' => __( 'Export personal data list navigation' ), - 'heading_list' => __( 'Export personal data list' ), - ) - ); - - $requests_table->process_bulk_action(); - $requests_table->prepare_items(); - ?> -
-

-
- - - -
-

-

- -
- - - -
- - - -
-
- - views(); ?> - -
- search_box( __( 'Search Requests' ), 'requests' ); ?> - - - - -
- -
- display(); - $requests_table->embed_scripts(); - ?> -
-
- 'privacy_requests', - 'singular' => 'privacy_request', - 'screen' => 'remove_personal_data', - ) - ); - - $requests_table->screen->set_screen_reader_content( - array( - 'heading_views' => __( 'Filter erase personal data list' ), - 'heading_pagination' => __( 'Erase personal data list navigation' ), - 'heading_list' => __( 'Erase personal data list' ), - ) - ); - - $requests_table->process_bulk_action(); - $requests_table->prepare_items(); - - ?> -
-

-
- - - -
-

-

- -
- - - -
- - - -
-
- - views(); ?> - -
- search_box( __( 'Search Requests' ), 'requests' ); ?> - - - - -
- -
- display(); - $requests_table->embed_scripts(); - ?> -
-
- action_name ) { - wp_send_json_error( __( 'Invalid request ID when processing eraser data.' ) ); - } - - /** This filter is documented in wp-admin/includes/ajax-actions.php */ - $erasers = apply_filters( 'wp_privacy_personal_data_erasers', array() ); - $is_last_eraser = count( $erasers ) === $eraser_index; - $eraser_done = $response['done']; - - if ( ! $is_last_eraser || ! $eraser_done ) { - return $response; - } - - _wp_privacy_completed_request( $request_id ); - - /** - * Fires immediately after a personal data erasure request has been marked completed. - * - * @since 4.9.6 - * - * @param int $request_id The privacy request post ID associated with this request. - */ - do_action( 'wp_privacy_personal_data_erased', $request_id ); - - return $response; -} - -/** - * Add requests pages. - * - * @since 4.9.6 - * @access private - */ -function _wp_privacy_hook_requests_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', __( 'Erase Personal Data' ), __( 'Erase Personal Data' ), 'erase_others_personal_data', 'remove_personal_data', '_wp_personal_data_removal_page' ); -} - -/** - * Add options for the privacy requests screens. - * - * @since 4.9.8 - * @access private - */ -function _wp_privacy_requests_screen_options() { - $args = array( - 'option' => str_replace( 'tools_page_', '', get_current_screen()->id ) . '_requests_per_page', - ); - add_screen_option( 'per_page', $args ); -} - -// TODO: move the following classes in new files. -if ( ! class_exists( 'WP_List_Table' ) ) { - require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' ); -} - -/** - * WP_Privacy_Requests_Table class. - * - * @since 4.9.6 - */ -abstract class WP_Privacy_Requests_Table extends WP_List_Table { - - /** - * Action name for the requests this table will work with. Classes - * which inherit from WP_Privacy_Requests_Table should define this. - * - * Example: 'export_personal_data'. - * - * @since 4.9.6 - * - * @var string $request_type Name of action. - */ - protected $request_type = 'INVALID'; - - /** - * Post type to be used. - * - * @since 4.9.6 - * - * @var string $post_type The post type. - */ - protected $post_type = 'INVALID'; - - /** - * Get columns to show in the list table. - * - * @since 4.9.6 - * - * @return array Array of columns. - */ - public function get_columns() { - $columns = array( - 'cb' => '', - 'email' => __( 'Requester' ), - 'status' => __( 'Status' ), - 'created_timestamp' => __( 'Requested' ), - 'next_steps' => __( 'Next Steps' ), - ); - return $columns; - } - - /** - * Get a list of sortable columns. - * - * @since 4.9.6 - * - * @return array Default sortable columns. - */ - protected function get_sortable_columns() { - // The initial sorting is by 'Requested' (post_date) and descending. - // With initial sorting, the first click on 'Requested' should be ascending. - // With 'Requester' sorting active, the next click on 'Requested' should be descending. - $desc_first = isset( $_GET['orderby'] ); - - return array( - 'email' => 'requester', - 'created_timestamp' => array( 'requested', $desc_first ), - ); - } - - /** - * Default primary column. - * - * @since 4.9.6 - * - * @return string Default primary column name. - */ - protected function get_default_primary_column_name() { - return 'email'; - } - - /** - * Count number of requests for each status. - * - * @since 4.9.6 - * - * @return object Number of posts for each status. - */ - protected function get_request_counts() { - global $wpdb; - - $cache_key = $this->post_type . '-' . $this->request_type; - $counts = wp_cache_get( $cache_key, 'counts' ); - - if ( false !== $counts ) { - return $counts; - } - - $query = " - SELECT post_status, COUNT( * ) AS num_posts - FROM {$wpdb->posts} - WHERE post_type = %s - AND post_name = %s - GROUP BY post_status"; - - $results = (array) $wpdb->get_results( $wpdb->prepare( $query, $this->post_type, $this->request_type ), ARRAY_A ); - $counts = array_fill_keys( get_post_stati(), 0 ); - - foreach ( $results as $row ) { - $counts[ $row['post_status'] ] = $row['num_posts']; - } - - $counts = (object) $counts; - wp_cache_set( $cache_key, $counts, 'counts' ); - - return $counts; - } - - /** - * Get an associative array ( id => link ) with the list of views available on this table. - * - * @since 4.9.6 - * - * @return array Associative array of views in the format of $view_name => $view_markup. - */ - protected function get_views() { - $current_status = isset( $_REQUEST['filter-status'] ) ? sanitize_text_field( $_REQUEST['filter-status'] ) : ''; - $statuses = _wp_privacy_statuses(); - $views = array(); - $admin_url = admin_url( 'tools.php?page=' . $this->request_type ); - $counts = $this->get_request_counts(); - $total_requests = absint( array_sum( (array) $counts ) ); - - $current_link_attributes = empty( $current_status ) ? ' class="current" aria-current="page"' : ''; - $status_label = sprintf( - /* translators: %s: all requests count */ - _nx( - 'All (%s)', - 'All (%s)', - $total_requests, - 'requests' - ), - number_format_i18n( $total_requests ) - ); - - $views['all'] = sprintf( - '%s', - esc_url( $admin_url ), - $current_link_attributes, - $status_label - ); - - foreach ( $statuses as $status => $label ) { - $post_status = get_post_status_object( $status ); - if ( ! $post_status ) { - continue; - } - - $current_link_attributes = $status === $current_status ? ' class="current" aria-current="page"' : ''; - $total_status_requests = absint( $counts->{$status} ); - $status_label = sprintf( - translate_nooped_plural( $post_status->label_count, $total_status_requests ), - number_format_i18n( $total_status_requests ) - ); - $status_link = add_query_arg( 'filter-status', $status, $admin_url ); - - $views[ $status ] = sprintf( - '%s', - esc_url( $status_link ), - $current_link_attributes, - $status_label - ); - } - - return $views; - } - - /** - * Get bulk actions. - * - * @since 4.9.6 - * - * @return array List of bulk actions. - */ - protected function get_bulk_actions() { - return array( - 'delete' => __( 'Remove' ), - 'resend' => __( 'Resend email' ), - ); - } - - /** - * Process bulk actions. - * - * @since 4.9.6 - */ - public function process_bulk_action() { - $action = $this->current_action(); - $request_ids = isset( $_REQUEST['request_id'] ) ? wp_parse_id_list( wp_unslash( $_REQUEST['request_id'] ) ) : array(); - - $count = 0; - - if ( $request_ids ) { - check_admin_referer( 'bulk-privacy_requests' ); - } - - switch ( $action ) { - case 'delete': - foreach ( $request_ids as $request_id ) { - if ( wp_delete_post( $request_id, true ) ) { - $count ++; - } - } - - add_settings_error( - 'bulk_action', - 'bulk_action', - /* translators: %d: number of requests */ - sprintf( _n( 'Deleted %d request', 'Deleted %d requests', $count ), $count ), - 'updated' - ); - break; - case 'resend': - foreach ( $request_ids as $request_id ) { - $resend = _wp_privacy_resend_request( $request_id ); - - if ( $resend && ! is_wp_error( $resend ) ) { - $count++; - } - } - - add_settings_error( - 'bulk_action', - 'bulk_action', - /* translators: %d: number of requests */ - sprintf( _n( 'Re-sent %d request', 'Re-sent %d requests', $count ), $count ), - 'updated' - ); - break; - } - } - - /** - * Prepare items to output. - * - * @since 4.9.6 - * @since 5.1.0 Added support for column sorting. - */ - public function prepare_items() { - global $wpdb; - - $this->items = array(); - $posts_per_page = $this->get_items_per_page( $this->request_type . '_requests_per_page' ); - $args = array( - 'post_type' => $this->post_type, - 'post_name__in' => array( $this->request_type ), - 'posts_per_page' => $posts_per_page, - 'offset' => isset( $_REQUEST['paged'] ) ? max( 0, absint( $_REQUEST['paged'] ) - 1 ) * $posts_per_page : 0, - 'post_status' => 'any', - 's' => isset( $_REQUEST['s'] ) ? sanitize_text_field( $_REQUEST['s'] ) : '', - ); - - $orderby_mapping = array( - 'requester' => 'post_title', - 'requested' => 'post_date', - ); - - if ( isset( $_REQUEST['orderby'] ) && isset( $orderby_mapping[ $_REQUEST['orderby'] ] ) ) { - $args['orderby'] = $orderby_mapping[ $_REQUEST['orderby'] ]; - } - - if ( isset( $_REQUEST['order'] ) && in_array( strtoupper( $_REQUEST['order'] ), array( 'ASC', 'DESC' ), true ) ) { - $args['order'] = strtoupper( $_REQUEST['order'] ); - } - - if ( ! empty( $_REQUEST['filter-status'] ) ) { - $filter_status = isset( $_REQUEST['filter-status'] ) ? sanitize_text_field( $_REQUEST['filter-status'] ) : ''; - $args['post_status'] = $filter_status; - } - - $requests_query = new WP_Query( $args ); - $requests = $requests_query->posts; - - foreach ( $requests as $request ) { - $this->items[] = wp_get_user_request_data( $request->ID ); - } - - $this->items = array_filter( $this->items ); - - $this->set_pagination_args( - array( - 'total_items' => $requests_query->found_posts, - 'per_page' => $posts_per_page, - ) - ); - } - - /** - * Checkbox column. - * - * @since 4.9.6 - * - * @param WP_User_Request $item Item being shown. - * @return string Checkbox column markup. - */ - public function column_cb( $item ) { - return sprintf( '', esc_attr( $item->ID ) ); - } - - /** - * Status column. - * - * @since 4.9.6 - * - * @param WP_User_Request $item Item being shown. - * @return string Status column markup. - */ - public function column_status( $item ) { - $status = get_post_status( $item->ID ); - $status_object = get_post_status_object( $status ); - - if ( ! $status_object || empty( $status_object->label ) ) { - return '-'; - } - - $timestamp = false; - - switch ( $status ) { - case 'request-confirmed': - $timestamp = $item->confirmed_timestamp; - break; - case 'request-completed': - $timestamp = $item->completed_timestamp; - break; - } - - echo ''; - echo esc_html( $status_object->label ); - - if ( $timestamp ) { - echo ' (' . $this->get_timestamp_as_date( $timestamp ) . ')'; - } - - echo ''; - } - - /** - * Convert timestamp for display. - * - * @since 4.9.6 - * - * @param int $timestamp Event timestamp. - * @return string Human readable date. - */ - protected function get_timestamp_as_date( $timestamp ) { - if ( empty( $timestamp ) ) { - return ''; - } - - $time_diff = time() - $timestamp; - - if ( $time_diff >= 0 && $time_diff < DAY_IN_SECONDS ) { - /* translators: human readable timestamp */ - return sprintf( __( '%s ago' ), human_time_diff( $timestamp ) ); - } - - return date_i18n( get_option( 'date_format' ), $timestamp ); - } - - /** - * Default column handler. - * - * @since 4.9.6 - * - * @param WP_User_Request $item Item being shown. - * @param string $column_name Name of column being shown. - * @return string Default column output. - */ - public function column_default( $item, $column_name ) { - $cell_value = $item->$column_name; - - if ( in_array( $column_name, array( 'created_timestamp' ), true ) ) { - return $this->get_timestamp_as_date( $cell_value ); - } - - return $cell_value; - } - - /** - * Actions column. Overridden by children. - * - * @since 4.9.6 - * - * @param WP_User_Request $item Item being shown. - * @return string Email column markup. - */ - public function column_email( $item ) { - return sprintf( '%2$s %3$s', esc_url( 'mailto:' . $item->email ), $item->email, $this->row_actions( array() ) ); - } - - /** - * Next steps column. Overridden by children. - * - * @since 4.9.6 - * - * @param WP_User_Request $item Item being shown. - */ - public function column_next_steps( $item ) {} - - /** - * Generates content for a single row of the table, - * - * @since 4.9.6 - * - * @param WP_User_Request $item The current item. - */ - public function single_row( $item ) { - $status = $item->status; - - echo ''; - $this->single_row_columns( $item ); - echo ''; - } - - /** - * Embed scripts used to perform actions. Overridden by children. - * - * @since 4.9.6 - */ - public function embed_scripts() {} -} - -/** - * WP_Privacy_Data_Export_Requests_Table class. - * - * @since 4.9.6 - */ -class WP_Privacy_Data_Export_Requests_Table extends WP_Privacy_Requests_Table { - /** - * Action name for the requests this table will work with. - * - * @since 4.9.6 - * - * @var string $request_type Name of action. - */ - protected $request_type = 'export_personal_data'; - - /** - * Post type for the requests. - * - * @since 4.9.6 - * - * @var string $post_type The post type. - */ - protected $post_type = 'user_request'; - - /** - * Actions column. - * - * @since 4.9.6 - * - * @param WP_User_Request $item Item being shown. - * @return string Email column markup. - */ - public function column_email( $item ) { - /** This filter is documented in wp-admin/includes/ajax-actions.php */ - $exporters = apply_filters( 'wp_privacy_personal_data_exporters', array() ); - $exporters_count = count( $exporters ); - $request_id = $item->ID; - $nonce = wp_create_nonce( 'wp-privacy-export-personal-data-' . $request_id ); - - $download_data_markup = '
'; - - $download_data_markup .= '' . - '' . - '' . - ''; - - $download_data_markup .= '
'; - - $row_actions = array( - 'download-data' => $download_data_markup, - ); - - return sprintf( '%2$s %3$s', esc_url( 'mailto:' . $item->email ), $item->email, $this->row_actions( $row_actions ) ); - } - - /** - * Displays the next steps column. - * - * @since 4.9.6 - * - * @param WP_User_Request $item Item being shown. - */ - public function column_next_steps( $item ) { - $status = $item->status; - - switch ( $status ) { - case 'request-pending': - esc_html_e( 'Waiting for confirmation' ); - break; - case 'request-confirmed': - /** This filter is documented in wp-admin/includes/ajax-actions.php */ - $exporters = apply_filters( 'wp_privacy_personal_data_exporters', array() ); - $exporters_count = count( $exporters ); - $request_id = $item->ID; - $nonce = wp_create_nonce( 'wp-privacy-export-personal-data-' . $request_id ); - - echo '
'; - - ?> - - - - - '; - break; - case 'request-failed': - submit_button( __( 'Retry' ), 'secondary', 'privacy_action_email_retry[' . $item->ID . ']', false ); - break; - case 'request-completed': - echo '' . esc_html__( 'Remove request' ) . ''; - break; - } - } -} - -/** - * WP_Privacy_Data_Removal_Requests_Table class. - * - * @since 4.9.6 - */ -class WP_Privacy_Data_Removal_Requests_Table extends WP_Privacy_Requests_Table { - /** - * Action name for the requests this table will work with. - * - * @since 4.9.6 - * - * @var string $request_type Name of action. - */ - protected $request_type = 'remove_personal_data'; - - /** - * Post type for the requests. - * - * @since 4.9.6 - * - * @var string $post_type The post type. - */ - protected $post_type = 'user_request'; - - /** - * Actions column. - * - * @since 4.9.6 - * - * @param WP_User_Request $item Item being shown. - * @return string Email column markup. - */ - public function column_email( $item ) { - $row_actions = array(); - - // Allow the administrator to "force remove" the personal data even if confirmation has not yet been received. - $status = $item->status; - if ( 'request-confirmed' !== $status ) { - /** This filter is documented in wp-admin/includes/ajax-actions.php */ - $erasers = apply_filters( 'wp_privacy_personal_data_erasers', array() ); - $erasers_count = count( $erasers ); - $request_id = $item->ID; - $nonce = wp_create_nonce( 'wp-privacy-erase-personal-data-' . $request_id ); - - $remove_data_markup = '
'; - - $remove_data_markup .= '' . - '' . - ''; - - $remove_data_markup .= '
'; - - $row_actions = array( - 'remove-data' => $remove_data_markup, - ); - } - - return sprintf( '%2$s %3$s', esc_url( 'mailto:' . $item->email ), $item->email, $this->row_actions( $row_actions ) ); - } - - /** - * Next steps column. - * - * @since 4.9.6 - * - * @param WP_User_Request $item Item being shown. - */ - public function column_next_steps( $item ) { - $status = $item->status; - - switch ( $status ) { - case 'request-pending': - esc_html_e( 'Waiting for confirmation' ); - break; - case 'request-confirmed': - /** This filter is documented in wp-admin/includes/ajax-actions.php */ - $erasers = apply_filters( 'wp_privacy_personal_data_erasers', array() ); - $erasers_count = count( $erasers ); - $request_id = $item->ID; - $nonce = wp_create_nonce( 'wp-privacy-erase-personal-data-' . $request_id ); - - echo '
'; - - ?> - - - - '; - - break; - case 'request-failed': - submit_button( __( 'Retry' ), 'secondary', 'privacy_action_email_retry[' . $item->ID . ']', false ); - break; - case 'request-completed': - echo '' . esc_html__( 'Remove request' ) . ''; - break; - } - } - -}