Changeset 45448 for trunk/src/wp-admin/includes/user.php
- Timestamp:
- 05/26/2019 08:49:04 PM (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-admin/includes/user.php
r45194 r45448 583 583 ); 584 584 } 585 586 /**587 * Resend an existing request and return the result.588 *589 * @since 4.9.6590 * @access private591 *592 * @param int $request_id Request ID.593 * @return bool|WP_Error Returns true/false based on the success of sending the email, or a WP_Error object.594 */595 function _wp_privacy_resend_request( $request_id ) {596 $request_id = absint( $request_id );597 $request = get_post( $request_id );598 599 if ( ! $request || 'user_request' !== $request->post_type ) {600 return new WP_Error( 'privacy_request_error', __( 'Invalid request.' ) );601 }602 603 $result = wp_send_user_request( $request_id );604 605 if ( is_wp_error( $result ) ) {606 return $result;607 } elseif ( ! $result ) {608 return new WP_Error( 'privacy_request_error', __( 'Unable to initiate confirmation request.' ) );609 }610 611 return true;612 }613 614 /**615 * Marks a request as completed by the admin and logs the current timestamp.616 *617 * @since 4.9.6618 * @access private619 *620 * @param int $request_id Request ID.621 * @return int|WP_Error $result Request ID on success or WP_Error.622 */623 function _wp_privacy_completed_request( $request_id ) {624 $request_id = absint( $request_id );625 $request = wp_get_user_request_data( $request_id );626 627 if ( ! $request ) {628 return new WP_Error( 'privacy_request_error', __( 'Invalid request.' ) );629 }630 631 update_post_meta( $request_id, '_wp_user_request_completed_timestamp', time() );632 633 $result = wp_update_post(634 array(635 'ID' => $request_id,636 'post_status' => 'request-completed',637 )638 );639 640 return $result;641 }642 643 /**644 * Handle list table actions.645 *646 * @since 4.9.6647 * @access private648 */649 function _wp_personal_data_handle_actions() {650 if ( isset( $_POST['privacy_action_email_retry'] ) ) {651 check_admin_referer( 'bulk-privacy_requests' );652 653 $request_id = absint( current( array_keys( (array) wp_unslash( $_POST['privacy_action_email_retry'] ) ) ) );654 $result = _wp_privacy_resend_request( $request_id );655 656 if ( is_wp_error( $result ) ) {657 add_settings_error(658 'privacy_action_email_retry',659 'privacy_action_email_retry',660 $result->get_error_message(),661 'error'662 );663 } else {664 add_settings_error(665 'privacy_action_email_retry',666 'privacy_action_email_retry',667 __( 'Confirmation request sent again successfully.' ),668 'updated'669 );670 }671 } elseif ( isset( $_POST['action'] ) ) {672 $action = isset( $_POST['action'] ) ? sanitize_key( wp_unslash( $_POST['action'] ) ) : '';673 674 switch ( $action ) {675 case 'add_export_personal_data_request':676 case 'add_remove_personal_data_request':677 check_admin_referer( 'personal-data-request' );678 679 if ( ! isset( $_POST['type_of_action'], $_POST['username_or_email_for_privacy_request'] ) ) {680 add_settings_error(681 'action_type',682 'action_type',683 __( 'Invalid action.' ),684 'error'685 );686 }687 $action_type = sanitize_text_field( wp_unslash( $_POST['type_of_action'] ) );688 $username_or_email_address = sanitize_text_field( wp_unslash( $_POST['username_or_email_for_privacy_request'] ) );689 $email_address = '';690 691 if ( ! in_array( $action_type, _wp_privacy_action_request_types(), true ) ) {692 add_settings_error(693 'action_type',694 'action_type',695 __( 'Invalid action.' ),696 'error'697 );698 }699 700 if ( ! is_email( $username_or_email_address ) ) {701 $user = get_user_by( 'login', $username_or_email_address );702 if ( ! $user instanceof WP_User ) {703 add_settings_error(704 'username_or_email_for_privacy_request',705 'username_or_email_for_privacy_request',706 __( 'Unable to add this request. A valid email address or username must be supplied.' ),707 'error'708 );709 } else {710 $email_address = $user->user_email;711 }712 } else {713 $email_address = $username_or_email_address;714 }715 716 if ( empty( $email_address ) ) {717 break;718 }719 720 $request_id = wp_create_user_request( $email_address, $action_type );721 722 if ( is_wp_error( $request_id ) ) {723 add_settings_error(724 'username_or_email_for_privacy_request',725 'username_or_email_for_privacy_request',726 $request_id->get_error_message(),727 'error'728 );729 break;730 } elseif ( ! $request_id ) {731 add_settings_error(732 'username_or_email_for_privacy_request',733 'username_or_email_for_privacy_request',734 __( 'Unable to initiate confirmation request.' ),735 'error'736 );737 break;738 }739 740 wp_send_user_request( $request_id );741 742 add_settings_error(743 'username_or_email_for_privacy_request',744 'username_or_email_for_privacy_request',745 __( 'Confirmation request initiated successfully.' ),746 'updated'747 );748 break;749 }750 }751 }752 753 /**754 * Cleans up failed and expired requests before displaying the list table.755 *756 * @since 4.9.6757 * @access private758 */759 function _wp_personal_data_cleanup_requests() {760 /** This filter is documented in wp-includes/user.php */761 $expires = (int) apply_filters( 'user_request_key_expiration', DAY_IN_SECONDS );762 763 $requests_query = new WP_Query(764 array(765 'post_type' => 'user_request',766 'posts_per_page' => -1,767 'post_status' => 'request-pending',768 'fields' => 'ids',769 'date_query' => array(770 array(771 'column' => 'post_modified_gmt',772 'before' => $expires . ' seconds ago',773 ),774 ),775 )776 );777 778 $request_ids = $requests_query->posts;779 780 foreach ( $request_ids as $request_id ) {781 wp_update_post(782 array(783 'ID' => $request_id,784 'post_status' => 'request-failed',785 'post_password' => '',786 )787 );788 }789 }790 791 /**792 * Personal data export.793 *794 * @since 4.9.6795 * @access private796 */797 function _wp_personal_data_export_page() {798 if ( ! current_user_can( 'export_others_personal_data' ) ) {799 wp_die( __( 'Sorry, you are not allowed to export personal data on this site.' ) );800 }801 802 _wp_personal_data_handle_actions();803 _wp_personal_data_cleanup_requests();804 805 // "Borrow" xfn.js for now so we don't have to create new files.806 wp_enqueue_script( 'xfn' );807 808 $requests_table = new WP_Privacy_Data_Export_Requests_Table(809 array(810 'plural' => 'privacy_requests',811 'singular' => 'privacy_request',812 'screen' => 'export_personal_data',813 )814 );815 816 $requests_table->screen->set_screen_reader_content(817 array(818 'heading_views' => __( 'Filter export personal data list' ),819 'heading_pagination' => __( 'Export personal data list navigation' ),820 'heading_list' => __( 'Export personal data list' ),821 )822 );823 824 $requests_table->process_bulk_action();825 $requests_table->prepare_items();826 ?>827 <div class="wrap nosubsub">828 <h1><?php esc_html_e( 'Export Personal Data' ); ?></h1>829 <hr class="wp-header-end" />830 831 <?php settings_errors(); ?>832 833 <form action="<?php echo esc_url( admin_url( 'tools.php?page=export_personal_data' ) ); ?>" method="post" class="wp-privacy-request-form">834 <h2><?php esc_html_e( 'Add Data Export Request' ); ?></h2>835 <p><?php esc_html_e( 'An email will be sent to the user at this email address asking them to verify the request.' ); ?></p>836 837 <div class="wp-privacy-request-form-field">838 <label for="username_or_email_for_privacy_request"><?php esc_html_e( 'Username or email address' ); ?></label>839 <input type="text" required class="regular-text" id="username_or_email_for_privacy_request" name="username_or_email_for_privacy_request" />840 <?php submit_button( __( 'Send Request' ), 'secondary', 'submit', false ); ?>841 </div>842 <?php wp_nonce_field( 'personal-data-request' ); ?>843 <input type="hidden" name="action" value="add_export_personal_data_request" />844 <input type="hidden" name="type_of_action" value="export_personal_data" />845 </form>846 <hr />847 848 <?php $requests_table->views(); ?>849 850 <form class="search-form wp-clearfix">851 <?php $requests_table->search_box( __( 'Search Requests' ), 'requests' ); ?>852 <input type="hidden" name="page" value="export_personal_data" />853 <input type="hidden" name="filter-status" value="<?php echo isset( $_REQUEST['filter-status'] ) ? esc_attr( sanitize_text_field( $_REQUEST['filter-status'] ) ) : ''; ?>" />854 <input type="hidden" name="orderby" value="<?php echo isset( $_REQUEST['orderby'] ) ? esc_attr( sanitize_text_field( $_REQUEST['orderby'] ) ) : ''; ?>" />855 <input type="hidden" name="order" value="<?php echo isset( $_REQUEST['order'] ) ? esc_attr( sanitize_text_field( $_REQUEST['order'] ) ) : ''; ?>" />856 </form>857 858 <form method="post">859 <?php860 $requests_table->display();861 $requests_table->embed_scripts();862 ?>863 </form>864 </div>865 <?php866 }867 868 /**869 * Personal data anonymization.870 *871 * @since 4.9.6872 * @access private873 */874 function _wp_personal_data_removal_page() {875 /*876 * Require both caps in order to make it explicitly clear that delegating877 * erasure from network admins to single-site admins will give them the878 * ability to affect global users, rather than being limited to the site879 * that they administer.880 */881 if ( ! current_user_can( 'erase_others_personal_data' ) || ! current_user_can( 'delete_users' ) ) {882 wp_die( __( 'Sorry, you are not allowed to erase data on this site.' ) );883 }884 885 _wp_personal_data_handle_actions();886 _wp_personal_data_cleanup_requests();887 888 // "Borrow" xfn.js for now so we don't have to create new files.889 wp_enqueue_script( 'xfn' );890 891 $requests_table = new WP_Privacy_Data_Removal_Requests_Table(892 array(893 'plural' => 'privacy_requests',894 'singular' => 'privacy_request',895 'screen' => 'remove_personal_data',896 )897 );898 899 $requests_table->screen->set_screen_reader_content(900 array(901 'heading_views' => __( 'Filter erase personal data list' ),902 'heading_pagination' => __( 'Erase personal data list navigation' ),903 'heading_list' => __( 'Erase personal data list' ),904 )905 );906 907 $requests_table->process_bulk_action();908 $requests_table->prepare_items();909 910 ?>911 <div class="wrap nosubsub">912 <h1><?php esc_html_e( 'Erase Personal Data' ); ?></h1>913 <hr class="wp-header-end" />914 915 <?php settings_errors(); ?>916 917 <form action="<?php echo esc_url( admin_url( 'tools.php?page=remove_personal_data' ) ); ?>" method="post" class="wp-privacy-request-form">918 <h2><?php esc_html_e( 'Add Data Erasure Request' ); ?></h2>919 <p><?php esc_html_e( 'An email will be sent to the user at this email address asking them to verify the request.' ); ?></p>920 921 <div class="wp-privacy-request-form-field">922 <label for="username_or_email_for_privacy_request"><?php esc_html_e( 'Username or email address' ); ?></label>923 <input type="text" required class="regular-text" id="username_or_email_for_privacy_request" name="username_or_email_for_privacy_request" />924 <?php submit_button( __( 'Send Request' ), 'secondary', 'submit', false ); ?>925 </div>926 <?php wp_nonce_field( 'personal-data-request' ); ?>927 <input type="hidden" name="action" value="add_remove_personal_data_request" />928 <input type="hidden" name="type_of_action" value="remove_personal_data" />929 </form>930 <hr />931 932 <?php $requests_table->views(); ?>933 934 <form class="search-form wp-clearfix">935 <?php $requests_table->search_box( __( 'Search Requests' ), 'requests' ); ?>936 <input type="hidden" name="page" value="remove_personal_data" />937 <input type="hidden" name="filter-status" value="<?php echo isset( $_REQUEST['filter-status'] ) ? esc_attr( sanitize_text_field( $_REQUEST['filter-status'] ) ) : ''; ?>" />938 <input type="hidden" name="orderby" value="<?php echo isset( $_REQUEST['orderby'] ) ? esc_attr( sanitize_text_field( $_REQUEST['orderby'] ) ) : ''; ?>" />939 <input type="hidden" name="order" value="<?php echo isset( $_REQUEST['order'] ) ? esc_attr( sanitize_text_field( $_REQUEST['order'] ) ) : ''; ?>" />940 </form>941 942 <form method="post">943 <?php944 $requests_table->display();945 $requests_table->embed_scripts();946 ?>947 </form>948 </div>949 <?php950 }951 952 /**953 * Mark erasure requests as completed after processing is finished.954 *955 * This intercepts the Ajax responses to personal data eraser page requests, and956 * monitors the status of a request. Once all of the processing has finished, the957 * request is marked as completed.958 *959 * @since 4.9.6960 *961 * @see wp_privacy_personal_data_erasure_page962 *963 * @param array $response The response from the personal data eraser for964 * the given page.965 * @param int $eraser_index The index of the personal data eraser. Begins966 * at 1.967 * @param string $email_address The email address of the user whose personal968 * data this is.969 * @param int $page The page of personal data for this eraser.970 * Begins at 1.971 * @param int $request_id The request ID for this personal data erasure.972 * @return array The filtered response.973 */974 function wp_privacy_process_personal_data_erasure_page( $response, $eraser_index, $email_address, $page, $request_id ) {975 /*976 * If the eraser response is malformed, don't attempt to consume it; let it977 * pass through, so that the default Ajax processing will generate a warning978 * to the user.979 */980 if ( ! is_array( $response ) ) {981 return $response;982 }983 984 if ( ! array_key_exists( 'done', $response ) ) {985 return $response;986 }987 988 if ( ! array_key_exists( 'items_removed', $response ) ) {989 return $response;990 }991 992 if ( ! array_key_exists( 'items_retained', $response ) ) {993 return $response;994 }995 996 if ( ! array_key_exists( 'messages', $response ) ) {997 return $response;998 }999 1000 $request = wp_get_user_request_data( $request_id );1001 1002 if ( ! $request || 'remove_personal_data' !== $request->action_name ) {1003 wp_send_json_error( __( 'Invalid request ID when processing eraser data.' ) );1004 }1005 1006 /** This filter is documented in wp-admin/includes/ajax-actions.php */1007 $erasers = apply_filters( 'wp_privacy_personal_data_erasers', array() );1008 $is_last_eraser = count( $erasers ) === $eraser_index;1009 $eraser_done = $response['done'];1010 1011 if ( ! $is_last_eraser || ! $eraser_done ) {1012 return $response;1013 }1014 1015 _wp_privacy_completed_request( $request_id );1016 1017 /**1018 * Fires immediately after a personal data erasure request has been marked completed.1019 *1020 * @since 4.9.61021 *1022 * @param int $request_id The privacy request post ID associated with this request.1023 */1024 do_action( 'wp_privacy_personal_data_erased', $request_id );1025 1026 return $response;1027 }1028 1029 /**1030 * Add requests pages.1031 *1032 * @since 4.9.61033 * @access private1034 */1035 function _wp_privacy_hook_requests_page() {1036 add_submenu_page( 'tools.php', __( 'Export Personal Data' ), __( 'Export Personal Data' ), 'export_others_personal_data', 'export_personal_data', '_wp_personal_data_export_page' );1037 add_submenu_page( 'tools.php', __( 'Erase Personal Data' ), __( 'Erase Personal Data' ), 'erase_others_personal_data', 'remove_personal_data', '_wp_personal_data_removal_page' );1038 }1039 1040 /**1041 * Add options for the privacy requests screens.1042 *1043 * @since 4.9.81044 * @access private1045 */1046 function _wp_privacy_requests_screen_options() {1047 $args = array(1048 'option' => str_replace( 'tools_page_', '', get_current_screen()->id ) . '_requests_per_page',1049 );1050 add_screen_option( 'per_page', $args );1051 }1052 1053 // TODO: move the following classes in new files.1054 if ( ! class_exists( 'WP_List_Table' ) ) {1055 require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );1056 }1057 1058 /**1059 * WP_Privacy_Requests_Table class.1060 *1061 * @since 4.9.61062 */1063 abstract class WP_Privacy_Requests_Table extends WP_List_Table {1064 1065 /**1066 * Action name for the requests this table will work with. Classes1067 * which inherit from WP_Privacy_Requests_Table should define this.1068 *1069 * Example: 'export_personal_data'.1070 *1071 * @since 4.9.61072 *1073 * @var string $request_type Name of action.1074 */1075 protected $request_type = 'INVALID';1076 1077 /**1078 * Post type to be used.1079 *1080 * @since 4.9.61081 *1082 * @var string $post_type The post type.1083 */1084 protected $post_type = 'INVALID';1085 1086 /**1087 * Get columns to show in the list table.1088 *1089 * @since 4.9.61090 *1091 * @return array Array of columns.1092 */1093 public function get_columns() {1094 $columns = array(1095 'cb' => '<input type="checkbox" />',1096 'email' => __( 'Requester' ),1097 'status' => __( 'Status' ),1098 'created_timestamp' => __( 'Requested' ),1099 'next_steps' => __( 'Next Steps' ),1100 );1101 return $columns;1102 }1103 1104 /**1105 * Get a list of sortable columns.1106 *1107 * @since 4.9.61108 *1109 * @return array Default sortable columns.1110 */1111 protected function get_sortable_columns() {1112 // The initial sorting is by 'Requested' (post_date) and descending.1113 // With initial sorting, the first click on 'Requested' should be ascending.1114 // With 'Requester' sorting active, the next click on 'Requested' should be descending.1115 $desc_first = isset( $_GET['orderby'] );1116 1117 return array(1118 'email' => 'requester',1119 'created_timestamp' => array( 'requested', $desc_first ),1120 );1121 }1122 1123 /**1124 * Default primary column.1125 *1126 * @since 4.9.61127 *1128 * @return string Default primary column name.1129 */1130 protected function get_default_primary_column_name() {1131 return 'email';1132 }1133 1134 /**1135 * Count number of requests for each status.1136 *1137 * @since 4.9.61138 *1139 * @return object Number of posts for each status.1140 */1141 protected function get_request_counts() {1142 global $wpdb;1143 1144 $cache_key = $this->post_type . '-' . $this->request_type;1145 $counts = wp_cache_get( $cache_key, 'counts' );1146 1147 if ( false !== $counts ) {1148 return $counts;1149 }1150 1151 $query = "1152 SELECT post_status, COUNT( * ) AS num_posts1153 FROM {$wpdb->posts}1154 WHERE post_type = %s1155 AND post_name = %s1156 GROUP BY post_status";1157 1158 $results = (array) $wpdb->get_results( $wpdb->prepare( $query, $this->post_type, $this->request_type ), ARRAY_A );1159 $counts = array_fill_keys( get_post_stati(), 0 );1160 1161 foreach ( $results as $row ) {1162 $counts[ $row['post_status'] ] = $row['num_posts'];1163 }1164 1165 $counts = (object) $counts;1166 wp_cache_set( $cache_key, $counts, 'counts' );1167 1168 return $counts;1169 }1170 1171 /**1172 * Get an associative array ( id => link ) with the list of views available on this table.1173 *1174 * @since 4.9.61175 *1176 * @return array Associative array of views in the format of $view_name => $view_markup.1177 */1178 protected function get_views() {1179 $current_status = isset( $_REQUEST['filter-status'] ) ? sanitize_text_field( $_REQUEST['filter-status'] ) : '';1180 $statuses = _wp_privacy_statuses();1181 $views = array();1182 $admin_url = admin_url( 'tools.php?page=' . $this->request_type );1183 $counts = $this->get_request_counts();1184 $total_requests = absint( array_sum( (array) $counts ) );1185 1186 $current_link_attributes = empty( $current_status ) ? ' class="current" aria-current="page"' : '';1187 $status_label = sprintf(1188 /* translators: %s: all requests count */1189 _nx(1190 'All <span class="count">(%s)</span>',1191 'All <span class="count">(%s)</span>',1192 $total_requests,1193 'requests'1194 ),1195 number_format_i18n( $total_requests )1196 );1197 1198 $views['all'] = sprintf(1199 '<a href="%s"%s>%s</a>',1200 esc_url( $admin_url ),1201 $current_link_attributes,1202 $status_label1203 );1204 1205 foreach ( $statuses as $status => $label ) {1206 $post_status = get_post_status_object( $status );1207 if ( ! $post_status ) {1208 continue;1209 }1210 1211 $current_link_attributes = $status === $current_status ? ' class="current" aria-current="page"' : '';1212 $total_status_requests = absint( $counts->{$status} );1213 $status_label = sprintf(1214 translate_nooped_plural( $post_status->label_count, $total_status_requests ),1215 number_format_i18n( $total_status_requests )1216 );1217 $status_link = add_query_arg( 'filter-status', $status, $admin_url );1218 1219 $views[ $status ] = sprintf(1220 '<a href="%s"%s>%s</a>',1221 esc_url( $status_link ),1222 $current_link_attributes,1223 $status_label1224 );1225 }1226 1227 return $views;1228 }1229 1230 /**1231 * Get bulk actions.1232 *1233 * @since 4.9.61234 *1235 * @return array List of bulk actions.1236 */1237 protected function get_bulk_actions() {1238 return array(1239 'delete' => __( 'Remove' ),1240 'resend' => __( 'Resend email' ),1241 );1242 }1243 1244 /**1245 * Process bulk actions.1246 *1247 * @since 4.9.61248 */1249 public function process_bulk_action() {1250 $action = $this->current_action();1251 $request_ids = isset( $_REQUEST['request_id'] ) ? wp_parse_id_list( wp_unslash( $_REQUEST['request_id'] ) ) : array();1252 1253 $count = 0;1254 1255 if ( $request_ids ) {1256 check_admin_referer( 'bulk-privacy_requests' );1257 }1258 1259 switch ( $action ) {1260 case 'delete':1261 foreach ( $request_ids as $request_id ) {1262 if ( wp_delete_post( $request_id, true ) ) {1263 $count ++;1264 }1265 }1266 1267 add_settings_error(1268 'bulk_action',1269 'bulk_action',1270 /* translators: %d: number of requests */1271 sprintf( _n( 'Deleted %d request', 'Deleted %d requests', $count ), $count ),1272 'updated'1273 );1274 break;1275 case 'resend':1276 foreach ( $request_ids as $request_id ) {1277 $resend = _wp_privacy_resend_request( $request_id );1278 1279 if ( $resend && ! is_wp_error( $resend ) ) {1280 $count++;1281 }1282 }1283 1284 add_settings_error(1285 'bulk_action',1286 'bulk_action',1287 /* translators: %d: number of requests */1288 sprintf( _n( 'Re-sent %d request', 'Re-sent %d requests', $count ), $count ),1289 'updated'1290 );1291 break;1292 }1293 }1294 1295 /**1296 * Prepare items to output.1297 *1298 * @since 4.9.61299 * @since 5.1.0 Added support for column sorting.1300 */1301 public function prepare_items() {1302 global $wpdb;1303 1304 $this->items = array();1305 $posts_per_page = $this->get_items_per_page( $this->request_type . '_requests_per_page' );1306 $args = array(1307 'post_type' => $this->post_type,1308 'post_name__in' => array( $this->request_type ),1309 'posts_per_page' => $posts_per_page,1310 'offset' => isset( $_REQUEST['paged'] ) ? max( 0, absint( $_REQUEST['paged'] ) - 1 ) * $posts_per_page : 0,1311 'post_status' => 'any',1312 's' => isset( $_REQUEST['s'] ) ? sanitize_text_field( $_REQUEST['s'] ) : '',1313 );1314 1315 $orderby_mapping = array(1316 'requester' => 'post_title',1317 'requested' => 'post_date',1318 );1319 1320 if ( isset( $_REQUEST['orderby'] ) && isset( $orderby_mapping[ $_REQUEST['orderby'] ] ) ) {1321 $args['orderby'] = $orderby_mapping[ $_REQUEST['orderby'] ];1322 }1323 1324 if ( isset( $_REQUEST['order'] ) && in_array( strtoupper( $_REQUEST['order'] ), array( 'ASC', 'DESC' ), true ) ) {1325 $args['order'] = strtoupper( $_REQUEST['order'] );1326 }1327 1328 if ( ! empty( $_REQUEST['filter-status'] ) ) {1329 $filter_status = isset( $_REQUEST['filter-status'] ) ? sanitize_text_field( $_REQUEST['filter-status'] ) : '';1330 $args['post_status'] = $filter_status;1331 }1332 1333 $requests_query = new WP_Query( $args );1334 $requests = $requests_query->posts;1335 1336 foreach ( $requests as $request ) {1337 $this->items[] = wp_get_user_request_data( $request->ID );1338 }1339 1340 $this->items = array_filter( $this->items );1341 1342 $this->set_pagination_args(1343 array(1344 'total_items' => $requests_query->found_posts,1345 'per_page' => $posts_per_page,1346 )1347 );1348 }1349 1350 /**1351 * Checkbox column.1352 *1353 * @since 4.9.61354 *1355 * @param WP_User_Request $item Item being shown.1356 * @return string Checkbox column markup.1357 */1358 public function column_cb( $item ) {1359 return sprintf( '<input type="checkbox" name="request_id[]" value="%1$s" /><span class="spinner"></span>', esc_attr( $item->ID ) );1360 }1361 1362 /**1363 * Status column.1364 *1365 * @since 4.9.61366 *1367 * @param WP_User_Request $item Item being shown.1368 * @return string Status column markup.1369 */1370 public function column_status( $item ) {1371 $status = get_post_status( $item->ID );1372 $status_object = get_post_status_object( $status );1373 1374 if ( ! $status_object || empty( $status_object->label ) ) {1375 return '-';1376 }1377 1378 $timestamp = false;1379 1380 switch ( $status ) {1381 case 'request-confirmed':1382 $timestamp = $item->confirmed_timestamp;1383 break;1384 case 'request-completed':1385 $timestamp = $item->completed_timestamp;1386 break;1387 }1388 1389 echo '<span class="status-label status-' . esc_attr( $status ) . '">';1390 echo esc_html( $status_object->label );1391 1392 if ( $timestamp ) {1393 echo ' (' . $this->get_timestamp_as_date( $timestamp ) . ')';1394 }1395 1396 echo '</span>';1397 }1398 1399 /**1400 * Convert timestamp for display.1401 *1402 * @since 4.9.61403 *1404 * @param int $timestamp Event timestamp.1405 * @return string Human readable date.1406 */1407 protected function get_timestamp_as_date( $timestamp ) {1408 if ( empty( $timestamp ) ) {1409 return '';1410 }1411 1412 $time_diff = time() - $timestamp;1413 1414 if ( $time_diff >= 0 && $time_diff < DAY_IN_SECONDS ) {1415 /* translators: human readable timestamp */1416 return sprintf( __( '%s ago' ), human_time_diff( $timestamp ) );1417 }1418 1419 return date_i18n( get_option( 'date_format' ), $timestamp );1420 }1421 1422 /**1423 * Default column handler.1424 *1425 * @since 4.9.61426 *1427 * @param WP_User_Request $item Item being shown.1428 * @param string $column_name Name of column being shown.1429 * @return string Default column output.1430 */1431 public function column_default( $item, $column_name ) {1432 $cell_value = $item->$column_name;1433 1434 if ( in_array( $column_name, array( 'created_timestamp' ), true ) ) {1435 return $this->get_timestamp_as_date( $cell_value );1436 }1437 1438 return $cell_value;1439 }1440 1441 /**1442 * Actions column. Overridden by children.1443 *1444 * @since 4.9.61445 *1446 * @param WP_User_Request $item Item being shown.1447 * @return string Email column markup.1448 */1449 public function column_email( $item ) {1450 return sprintf( '<a href="%1$s">%2$s</a> %3$s', esc_url( 'mailto:' . $item->email ), $item->email, $this->row_actions( array() ) );1451 }1452 1453 /**1454 * Next steps column. Overridden by children.1455 *1456 * @since 4.9.61457 *1458 * @param WP_User_Request $item Item being shown.1459 */1460 public function column_next_steps( $item ) {}1461 1462 /**1463 * Generates content for a single row of the table,1464 *1465 * @since 4.9.61466 *1467 * @param WP_User_Request $item The current item.1468 */1469 public function single_row( $item ) {1470 $status = $item->status;1471 1472 echo '<tr id="request-' . esc_attr( $item->ID ) . '" class="status-' . esc_attr( $status ) . '">';1473 $this->single_row_columns( $item );1474 echo '</tr>';1475 }1476 1477 /**1478 * Embed scripts used to perform actions. Overridden by children.1479 *1480 * @since 4.9.61481 */1482 public function embed_scripts() {}1483 }1484 1485 /**1486 * WP_Privacy_Data_Export_Requests_Table class.1487 *1488 * @since 4.9.61489 */1490 class WP_Privacy_Data_Export_Requests_Table extends WP_Privacy_Requests_Table {1491 /**1492 * Action name for the requests this table will work with.1493 *1494 * @since 4.9.61495 *1496 * @var string $request_type Name of action.1497 */1498 protected $request_type = 'export_personal_data';1499 1500 /**1501 * Post type for the requests.1502 *1503 * @since 4.9.61504 *1505 * @var string $post_type The post type.1506 */1507 protected $post_type = 'user_request';1508 1509 /**1510 * Actions column.1511 *1512 * @since 4.9.61513 *1514 * @param WP_User_Request $item Item being shown.1515 * @return string Email column markup.1516 */1517 public function column_email( $item ) {1518 /** This filter is documented in wp-admin/includes/ajax-actions.php */1519 $exporters = apply_filters( 'wp_privacy_personal_data_exporters', array() );1520 $exporters_count = count( $exporters );1521 $request_id = $item->ID;1522 $nonce = wp_create_nonce( 'wp-privacy-export-personal-data-' . $request_id );1523 1524 $download_data_markup = '<div class="export-personal-data" ' .1525 'data-exporters-count="' . esc_attr( $exporters_count ) . '" ' .1526 'data-request-id="' . esc_attr( $request_id ) . '" ' .1527 'data-nonce="' . esc_attr( $nonce ) .1528 '">';1529 1530 $download_data_markup .= '<span class="export-personal-data-idle"><button type="button" class="button-link export-personal-data-handle">' . __( 'Download Personal Data' ) . '</button></span>' .1531 '<span style="display:none" class="export-personal-data-processing" >' . __( 'Downloading Data...' ) . '</span>' .1532 '<span style="display:none" class="export-personal-data-success"><button type="button" class="button-link export-personal-data-handle">' . __( 'Download Personal Data Again' ) . '</button></span>' .1533 '<span style="display:none" class="export-personal-data-failed">' . __( 'Download failed.' ) . ' <button type="button" class="button-link">' . __( 'Retry' ) . '</button></span>';1534 1535 $download_data_markup .= '</div>';1536 1537 $row_actions = array(1538 'download-data' => $download_data_markup,1539 );1540 1541 return sprintf( '<a href="%1$s">%2$s</a> %3$s', esc_url( 'mailto:' . $item->email ), $item->email, $this->row_actions( $row_actions ) );1542 }1543 1544 /**1545 * Displays the next steps column.1546 *1547 * @since 4.9.61548 *1549 * @param WP_User_Request $item Item being shown.1550 */1551 public function column_next_steps( $item ) {1552 $status = $item->status;1553 1554 switch ( $status ) {1555 case 'request-pending':1556 esc_html_e( 'Waiting for confirmation' );1557 break;1558 case 'request-confirmed':1559 /** This filter is documented in wp-admin/includes/ajax-actions.php */1560 $exporters = apply_filters( 'wp_privacy_personal_data_exporters', array() );1561 $exporters_count = count( $exporters );1562 $request_id = $item->ID;1563 $nonce = wp_create_nonce( 'wp-privacy-export-personal-data-' . $request_id );1564 1565 echo '<div class="export-personal-data" ' .1566 'data-send-as-email="1" ' .1567 'data-exporters-count="' . esc_attr( $exporters_count ) . '" ' .1568 'data-request-id="' . esc_attr( $request_id ) . '" ' .1569 'data-nonce="' . esc_attr( $nonce ) .1570 '">';1571 1572 ?>1573 <span class="export-personal-data-idle"><button type="button" class="button export-personal-data-handle"><?php _e( 'Send Export Link' ); ?></button></span>1574 <span style="display:none" class="export-personal-data-processing button updating-message" ><?php _e( 'Sending Email...' ); ?></span>1575 <span style="display:none" class="export-personal-data-success success-message" ><?php _e( 'Email sent.' ); ?></span>1576 <span style="display:none" class="export-personal-data-failed"><?php _e( 'Email could not be sent.' ); ?> <button type="button" class="button export-personal-data-handle"><?php _e( 'Retry' ); ?></button></span>1577 <?php1578 1579 echo '</div>';1580 break;1581 case 'request-failed':1582 submit_button( __( 'Retry' ), 'secondary', 'privacy_action_email_retry[' . $item->ID . ']', false );1583 break;1584 case 'request-completed':1585 echo '<a href="' . esc_url(1586 wp_nonce_url(1587 add_query_arg(1588 array(1589 'action' => 'delete',1590 'request_id' => array( $item->ID ),1591 ),1592 admin_url( 'tools.php?page=export_personal_data' )1593 ),1594 'bulk-privacy_requests'1595 )1596 ) . '" class="button">' . esc_html__( 'Remove request' ) . '</a>';1597 break;1598 }1599 }1600 }1601 1602 /**1603 * WP_Privacy_Data_Removal_Requests_Table class.1604 *1605 * @since 4.9.61606 */1607 class WP_Privacy_Data_Removal_Requests_Table extends WP_Privacy_Requests_Table {1608 /**1609 * Action name for the requests this table will work with.1610 *1611 * @since 4.9.61612 *1613 * @var string $request_type Name of action.1614 */1615 protected $request_type = 'remove_personal_data';1616 1617 /**1618 * Post type for the requests.1619 *1620 * @since 4.9.61621 *1622 * @var string $post_type The post type.1623 */1624 protected $post_type = 'user_request';1625 1626 /**1627 * Actions column.1628 *1629 * @since 4.9.61630 *1631 * @param WP_User_Request $item Item being shown.1632 * @return string Email column markup.1633 */1634 public function column_email( $item ) {1635 $row_actions = array();1636 1637 // Allow the administrator to "force remove" the personal data even if confirmation has not yet been received.1638 $status = $item->status;1639 if ( 'request-confirmed' !== $status ) {1640 /** This filter is documented in wp-admin/includes/ajax-actions.php */1641 $erasers = apply_filters( 'wp_privacy_personal_data_erasers', array() );1642 $erasers_count = count( $erasers );1643 $request_id = $item->ID;1644 $nonce = wp_create_nonce( 'wp-privacy-erase-personal-data-' . $request_id );1645 1646 $remove_data_markup = '<div class="remove-personal-data force-remove-personal-data" ' .1647 'data-erasers-count="' . esc_attr( $erasers_count ) . '" ' .1648 'data-request-id="' . esc_attr( $request_id ) . '" ' .1649 'data-nonce="' . esc_attr( $nonce ) .1650 '">';1651 1652 $remove_data_markup .= '<span class="remove-personal-data-idle"><button type="button" class="button-link remove-personal-data-handle">' . __( 'Force Erase Personal Data' ) . '</button></span>' .1653 '<span style="display:none" class="remove-personal-data-processing" >' . __( 'Erasing Data...' ) . '</span>' .1654 '<span style="display:none" class="remove-personal-data-failed">' . __( 'Force Erase has failed.' ) . ' <button type="button" class="button-link remove-personal-data-handle">' . __( 'Retry' ) . '</button></span>';1655 1656 $remove_data_markup .= '</div>';1657 1658 $row_actions = array(1659 'remove-data' => $remove_data_markup,1660 );1661 }1662 1663 return sprintf( '<a href="%1$s">%2$s</a> %3$s', esc_url( 'mailto:' . $item->email ), $item->email, $this->row_actions( $row_actions ) );1664 }1665 1666 /**1667 * Next steps column.1668 *1669 * @since 4.9.61670 *1671 * @param WP_User_Request $item Item being shown.1672 */1673 public function column_next_steps( $item ) {1674 $status = $item->status;1675 1676 switch ( $status ) {1677 case 'request-pending':1678 esc_html_e( 'Waiting for confirmation' );1679 break;1680 case 'request-confirmed':1681 /** This filter is documented in wp-admin/includes/ajax-actions.php */1682 $erasers = apply_filters( 'wp_privacy_personal_data_erasers', array() );1683 $erasers_count = count( $erasers );1684 $request_id = $item->ID;1685 $nonce = wp_create_nonce( 'wp-privacy-erase-personal-data-' . $request_id );1686 1687 echo '<div class="remove-personal-data" ' .1688 'data-force-erase="1" ' .1689 'data-erasers-count="' . esc_attr( $erasers_count ) . '" ' .1690 'data-request-id="' . esc_attr( $request_id ) . '" ' .1691 'data-nonce="' . esc_attr( $nonce ) .1692 '">';1693 1694 ?>1695 <span class="remove-personal-data-idle"><button type="button" class="button remove-personal-data-handle"><?php _e( 'Erase Personal Data' ); ?></button></span>1696 <span style="display:none" class="remove-personal-data-processing button updating-message" ><?php _e( 'Erasing Data...' ); ?></span>1697 <span style="display:none" class="remove-personal-data-failed"><?php _e( 'Erasing Data has failed.' ); ?> <button type="button" class="button remove-personal-data-handle"><?php _e( 'Retry' ); ?></button></span>1698 <?php1699 1700 echo '</div>';1701 1702 break;1703 case 'request-failed':1704 submit_button( __( 'Retry' ), 'secondary', 'privacy_action_email_retry[' . $item->ID . ']', false );1705 break;1706 case 'request-completed':1707 echo '<a href="' . esc_url(1708 wp_nonce_url(1709 add_query_arg(1710 array(1711 'action' => 'delete',1712 'request_id' => array( $item->ID ),1713 ),1714 admin_url( 'tools.php?page=remove_personal_data' )1715 ),1716 'bulk-privacy_requests'1717 )1718 ) . '" class="button">' . esc_html__( 'Remove request' ) . '</a>';1719 break;1720 }1721 }1722 1723 }
Note: See TracChangeset
for help on using the changeset viewer.