[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * List Table API: WP_Privacy_Requests_Table class 4 * 5 * @package WordPress 6 * @subpackage Administration 7 * @since 4.9.6 8 */ 9 10 abstract class WP_Privacy_Requests_Table extends WP_List_Table { 11 12 /** 13 * Action name for the requests this table will work with. Classes 14 * which inherit from WP_Privacy_Requests_Table should define this. 15 * 16 * Example: 'export_personal_data'. 17 * 18 * @since 4.9.6 19 * 20 * @var string $request_type Name of action. 21 */ 22 protected $request_type = 'INVALID'; 23 24 /** 25 * Post type to be used. 26 * 27 * @since 4.9.6 28 * 29 * @var string $post_type The post type. 30 */ 31 protected $post_type = 'INVALID'; 32 33 /** 34 * Gets columns to show in the list table. 35 * 36 * @since 4.9.6 37 * 38 * @return string[] Array of column titles keyed by their column name. 39 */ 40 public function get_columns() { 41 $columns = array( 42 'cb' => '<input type="checkbox" />', 43 'email' => __( 'Requester' ), 44 'status' => __( 'Status' ), 45 'created_timestamp' => __( 'Requested' ), 46 'next_steps' => __( 'Next steps' ), 47 ); 48 return $columns; 49 } 50 51 /** 52 * Normalizes the admin URL to the current page (by request_type). 53 * 54 * @since 5.3.0 55 * 56 * @return string URL to the current admin page. 57 */ 58 protected function get_admin_url() { 59 $pagenow = str_replace( '_', '-', $this->request_type ); 60 61 if ( 'remove-personal-data' === $pagenow ) { 62 $pagenow = 'erase-personal-data'; 63 } 64 65 return admin_url( $pagenow . '.php' ); 66 } 67 68 /** 69 * Gets a list of sortable columns. 70 * 71 * @since 4.9.6 72 * 73 * @return array Default sortable columns. 74 */ 75 protected function get_sortable_columns() { 76 /* 77 * The initial sorting is by 'Requested' (post_date) and descending. 78 * With initial sorting, the first click on 'Requested' should be ascending. 79 * With 'Requester' sorting active, the next click on 'Requested' should be descending. 80 */ 81 $desc_first = isset( $_GET['orderby'] ); 82 83 return array( 84 'email' => 'requester', 85 'created_timestamp' => array( 'requested', $desc_first ), 86 ); 87 } 88 89 /** 90 * Returns the default primary column. 91 * 92 * @since 4.9.6 93 * 94 * @return string Default primary column name. 95 */ 96 protected function get_default_primary_column_name() { 97 return 'email'; 98 } 99 100 /** 101 * Counts the number of requests for each status. 102 * 103 * @since 4.9.6 104 * 105 * @global wpdb $wpdb WordPress database abstraction object. 106 * 107 * @return object Number of posts for each status. 108 */ 109 protected function get_request_counts() { 110 global $wpdb; 111 112 $cache_key = $this->post_type . '-' . $this->request_type; 113 $counts = wp_cache_get( $cache_key, 'counts' ); 114 115 if ( false !== $counts ) { 116 return $counts; 117 } 118 119 $query = " 120 SELECT post_status, COUNT( * ) AS num_posts 121 FROM {$wpdb->posts} 122 WHERE post_type = %s 123 AND post_name = %s 124 GROUP BY post_status"; 125 126 $results = (array) $wpdb->get_results( $wpdb->prepare( $query, $this->post_type, $this->request_type ), ARRAY_A ); 127 $counts = array_fill_keys( get_post_stati(), 0 ); 128 129 foreach ( $results as $row ) { 130 $counts[ $row['post_status'] ] = $row['num_posts']; 131 } 132 133 $counts = (object) $counts; 134 wp_cache_set( $cache_key, $counts, 'counts' ); 135 136 return $counts; 137 } 138 139 /** 140 * Gets an associative array ( id => link ) with the list of views available on this table. 141 * 142 * @since 4.9.6 143 * 144 * @return string[] An array of HTML links keyed by their view. 145 */ 146 protected function get_views() { 147 $current_status = isset( $_REQUEST['filter-status'] ) ? sanitize_text_field( $_REQUEST['filter-status'] ) : ''; 148 $statuses = _wp_privacy_statuses(); 149 $views = array(); 150 $counts = $this->get_request_counts(); 151 $total_requests = absint( array_sum( (array) $counts ) ); 152 153 // Normalized admin URL. 154 $admin_url = $this->get_admin_url(); 155 156 $status_label = sprintf( 157 /* translators: %s: Number of requests. */ 158 _nx( 159 'All <span class="count">(%s)</span>', 160 'All <span class="count">(%s)</span>', 161 $total_requests, 162 'requests' 163 ), 164 number_format_i18n( $total_requests ) 165 ); 166 167 $views['all'] = array( 168 'url' => esc_url( $admin_url ), 169 'label' => $status_label, 170 'current' => empty( $current_status ), 171 ); 172 173 foreach ( $statuses as $status => $label ) { 174 $post_status = get_post_status_object( $status ); 175 if ( ! $post_status ) { 176 continue; 177 } 178 179 $total_status_requests = absint( $counts->{$status} ); 180 181 if ( ! $total_status_requests ) { 182 continue; 183 } 184 185 $status_label = sprintf( 186 translate_nooped_plural( $post_status->label_count, $total_status_requests ), 187 number_format_i18n( $total_status_requests ) 188 ); 189 190 $status_link = add_query_arg( 'filter-status', $status, $admin_url ); 191 192 $views[ $status ] = array( 193 'url' => esc_url( $status_link ), 194 'label' => $status_label, 195 'current' => $status === $current_status, 196 ); 197 } 198 199 return $this->get_views_links( $views ); 200 } 201 202 /** 203 * Gets bulk actions. 204 * 205 * @since 4.9.6 206 * 207 * @return array Array of bulk action labels keyed by their action. 208 */ 209 protected function get_bulk_actions() { 210 return array( 211 'resend' => __( 'Resend confirmation requests' ), 212 'complete' => __( 'Mark requests as completed' ), 213 'delete' => __( 'Delete requests' ), 214 ); 215 } 216 217 /** 218 * Process bulk actions. 219 * 220 * @since 4.9.6 221 * @since 5.6.0 Added support for the `complete` action. 222 */ 223 public function process_bulk_action() { 224 $action = $this->current_action(); 225 $request_ids = isset( $_REQUEST['request_id'] ) ? wp_parse_id_list( wp_unslash( $_REQUEST['request_id'] ) ) : array(); 226 227 if ( empty( $request_ids ) ) { 228 return; 229 } 230 231 $count = 0; 232 $failures = 0; 233 234 check_admin_referer( 'bulk-privacy_requests' ); 235 236 switch ( $action ) { 237 case 'resend': 238 foreach ( $request_ids as $request_id ) { 239 $resend = _wp_privacy_resend_request( $request_id ); 240 241 if ( $resend && ! is_wp_error( $resend ) ) { 242 ++$count; 243 } else { 244 ++$failures; 245 } 246 } 247 248 if ( $failures ) { 249 add_settings_error( 250 'bulk_action', 251 'bulk_action', 252 sprintf( 253 /* translators: %d: Number of requests. */ 254 _n( 255 '%d confirmation request failed to resend.', 256 '%d confirmation requests failed to resend.', 257 $failures 258 ), 259 $failures 260 ), 261 'error' 262 ); 263 } 264 265 if ( $count ) { 266 add_settings_error( 267 'bulk_action', 268 'bulk_action', 269 sprintf( 270 /* translators: %d: Number of requests. */ 271 _n( 272 '%d confirmation request re-sent successfully.', 273 '%d confirmation requests re-sent successfully.', 274 $count 275 ), 276 $count 277 ), 278 'success' 279 ); 280 } 281 282 break; 283 284 case 'complete': 285 foreach ( $request_ids as $request_id ) { 286 $result = _wp_privacy_completed_request( $request_id ); 287 288 if ( $result && ! is_wp_error( $result ) ) { 289 ++$count; 290 } 291 } 292 293 add_settings_error( 294 'bulk_action', 295 'bulk_action', 296 sprintf( 297 /* translators: %d: Number of requests. */ 298 _n( 299 '%d request marked as complete.', 300 '%d requests marked as complete.', 301 $count 302 ), 303 $count 304 ), 305 'success' 306 ); 307 break; 308 309 case 'delete': 310 foreach ( $request_ids as $request_id ) { 311 if ( wp_delete_post( $request_id, true ) ) { 312 ++$count; 313 } else { 314 ++$failures; 315 } 316 } 317 318 if ( $failures ) { 319 add_settings_error( 320 'bulk_action', 321 'bulk_action', 322 sprintf( 323 /* translators: %d: Number of requests. */ 324 _n( 325 '%d request failed to delete.', 326 '%d requests failed to delete.', 327 $failures 328 ), 329 $failures 330 ), 331 'error' 332 ); 333 } 334 335 if ( $count ) { 336 add_settings_error( 337 'bulk_action', 338 'bulk_action', 339 sprintf( 340 /* translators: %d: Number of requests. */ 341 _n( 342 '%d request deleted successfully.', 343 '%d requests deleted successfully.', 344 $count 345 ), 346 $count 347 ), 348 'success' 349 ); 350 } 351 352 break; 353 } 354 } 355 356 /** 357 * Prepares items to output. 358 * 359 * @since 4.9.6 360 * @since 5.1.0 Added support for column sorting. 361 */ 362 public function prepare_items() { 363 $this->items = array(); 364 $posts_per_page = $this->get_items_per_page( $this->request_type . '_requests_per_page' ); 365 $args = array( 366 'post_type' => $this->post_type, 367 'post_name__in' => array( $this->request_type ), 368 'posts_per_page' => $posts_per_page, 369 'offset' => isset( $_REQUEST['paged'] ) ? max( 0, absint( $_REQUEST['paged'] ) - 1 ) * $posts_per_page : 0, 370 'post_status' => 'any', 371 's' => isset( $_REQUEST['s'] ) ? sanitize_text_field( $_REQUEST['s'] ) : '', 372 ); 373 374 $orderby_mapping = array( 375 'requester' => 'post_title', 376 'requested' => 'post_date', 377 ); 378 379 if ( isset( $_REQUEST['orderby'] ) && isset( $orderby_mapping[ $_REQUEST['orderby'] ] ) ) { 380 $args['orderby'] = $orderby_mapping[ $_REQUEST['orderby'] ]; 381 } 382 383 if ( isset( $_REQUEST['order'] ) && in_array( strtoupper( $_REQUEST['order'] ), array( 'ASC', 'DESC' ), true ) ) { 384 $args['order'] = strtoupper( $_REQUEST['order'] ); 385 } 386 387 if ( ! empty( $_REQUEST['filter-status'] ) ) { 388 $filter_status = isset( $_REQUEST['filter-status'] ) ? sanitize_text_field( $_REQUEST['filter-status'] ) : ''; 389 $args['post_status'] = $filter_status; 390 } 391 392 $requests_query = new WP_Query( $args ); 393 $requests = $requests_query->posts; 394 395 foreach ( $requests as $request ) { 396 $this->items[] = wp_get_user_request( $request->ID ); 397 } 398 399 $this->items = array_filter( $this->items ); 400 401 $this->set_pagination_args( 402 array( 403 'total_items' => $requests_query->found_posts, 404 'per_page' => $posts_per_page, 405 ) 406 ); 407 } 408 409 /** 410 * Returns the markup for the Checkbox column. 411 * 412 * @since 4.9.6 413 * 414 * @param WP_User_Request $item Item being shown. 415 * @return string Checkbox column markup. 416 */ 417 public function column_cb( $item ) { 418 return sprintf( 419 '<input type="checkbox" name="request_id[]" id="requester_%1$s" value="%1$s" />' . 420 '<label for="requester_%1$s"><span class="screen-reader-text">%2$s</span></label><span class="spinner"></span>', 421 esc_attr( $item->ID ), 422 /* translators: Hidden accessibility text. %s: Email address. */ 423 sprintf( __( 'Select %s' ), $item->email ) 424 ); 425 } 426 427 /** 428 * Status column. 429 * 430 * @since 4.9.6 431 * 432 * @param WP_User_Request $item Item being shown. 433 * @return string|void Status column markup. Returns a string if no status is found, 434 * otherwise it displays the markup. 435 */ 436 public function column_status( $item ) { 437 $status = get_post_status( $item->ID ); 438 $status_object = get_post_status_object( $status ); 439 440 if ( ! $status_object || empty( $status_object->label ) ) { 441 return '-'; 442 } 443 444 $timestamp = false; 445 446 switch ( $status ) { 447 case 'request-confirmed': 448 $timestamp = $item->confirmed_timestamp; 449 break; 450 case 'request-completed': 451 $timestamp = $item->completed_timestamp; 452 break; 453 } 454 455 echo '<span class="status-label status-' . esc_attr( $status ) . '">'; 456 echo esc_html( $status_object->label ); 457 458 if ( $timestamp ) { 459 echo ' (' . $this->get_timestamp_as_date( $timestamp ) . ')'; 460 } 461 462 echo '</span>'; 463 } 464 465 /** 466 * Converts a timestamp for display. 467 * 468 * @since 4.9.6 469 * 470 * @param int $timestamp Event timestamp. 471 * @return string Human readable date. 472 */ 473 protected function get_timestamp_as_date( $timestamp ) { 474 if ( empty( $timestamp ) ) { 475 return ''; 476 } 477 478 $time_diff = time() - $timestamp; 479 480 if ( $time_diff >= 0 && $time_diff < DAY_IN_SECONDS ) { 481 /* translators: %s: Human-readable time difference. */ 482 return sprintf( __( '%s ago' ), human_time_diff( $timestamp ) ); 483 } 484 485 return date_i18n( get_option( 'date_format' ), $timestamp ); 486 } 487 488 /** 489 * Handles the default column. 490 * 491 * @since 4.9.6 492 * @since 5.7.0 Added `manage_{$this->screen->id}_custom_column` action. 493 * 494 * @param WP_User_Request $item Item being shown. 495 * @param string $column_name Name of column being shown. 496 */ 497 public function column_default( $item, $column_name ) { 498 /** 499 * Fires for each custom column of a specific request type in the Requests list table. 500 * 501 * Custom columns are registered using the {@see 'manage_export-personal-data_columns'} 502 * and the {@see 'manage_erase-personal-data_columns'} filters. 503 * 504 * @since 5.7.0 505 * 506 * @param string $column_name The name of the column to display. 507 * @param WP_User_Request $item The item being shown. 508 */ 509 do_action( "manage_{$this->screen->id}_custom_column", $column_name, $item ); 510 } 511 512 /** 513 * Returns the markup for the Created timestamp column. Overridden by children. 514 * 515 * @since 5.7.0 516 * 517 * @param WP_User_Request $item Item being shown. 518 * @return string Human readable date. 519 */ 520 public function column_created_timestamp( $item ) { 521 return $this->get_timestamp_as_date( $item->created_timestamp ); 522 } 523 524 /** 525 * Actions column. Overridden by children. 526 * 527 * @since 4.9.6 528 * 529 * @param WP_User_Request $item Item being shown. 530 * @return string Email column markup. 531 */ 532 public function column_email( $item ) { 533 return sprintf( '<a href="%1$s">%2$s</a> %3$s', esc_url( 'mailto:' . $item->email ), $item->email, $this->row_actions( array() ) ); 534 } 535 536 /** 537 * Returns the markup for the next steps column. Overridden by children. 538 * 539 * @since 4.9.6 540 * 541 * @param WP_User_Request $item Item being shown. 542 */ 543 public function column_next_steps( $item ) {} 544 545 /** 546 * Generates content for a single row of the table, 547 * 548 * @since 4.9.6 549 * 550 * @param WP_User_Request $item The current item. 551 */ 552 public function single_row( $item ) { 553 $status = $item->status; 554 555 echo '<tr id="request-' . esc_attr( $item->ID ) . '" class="status-' . esc_attr( $status ) . '">'; 556 $this->single_row_columns( $item ); 557 echo '</tr>'; 558 } 559 560 /** 561 * Embeds scripts used to perform actions. Overridden by children. 562 * 563 * @since 4.9.6 564 */ 565 public function embed_scripts() {} 566 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Tue Dec 3 08:20:01 2024 | Cross-referenced by PHPXref |