PluginProbe
TablePress – Tables in WordPress made easy / 2.2.5
TablePress – Tables in WordPress made easy v2.2.5
3.4 3.3.4 3.3.3 3.3.2 3.3.1 trunk 1.12 1.14 1.9.2 2.0.4 2.1.7 2.1.8 2.2 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.3 2.3.1 2.3.2 2.4 2.4.1 2.4.2 2.4.3 All 45 releases
tablepress / views / class-all-tables-list-table.php

class-all-tables-list-table.php in TablePress – Tables in WordPress made easy 2.2.5, at views/class-all-tables-list-table.php

636 lines 23.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * List Tables View List Table
4 *
5 * @package TablePress
6 * @subpackage Views
7 * @author Tobias Bäthge
8 * @since 2.0.0
9 */
10
11 // Prohibit direct script loading.
12 defined( 'ABSPATH' ) || die( 'No direct script access allowed!' );
13
14 /**
15 * TablePress All Tables List Table class
16 *
17 * @package TablePress
18 * @subpackage Views
19 * @author Tobias Bäthge
20 * @since 1.0.0
21 */
22 class TablePress_All_Tables_List_Table extends WP_List_Table {
23
24 /**
25 * Number of items of the initial data set (before sort, search, and pagination).
26 *
27 * @since 1.0.0
28 * @var int
29 */
30 protected $items_count = 0;
31
32 /**
33 * Cached bulk actions.
34 *
35 * This property has to be declared here, as it's `private` in the parent class
36 * and thus can't be inherited.
37 *
38 * @since 1.0.0
39 * @var array<string, string>|null
40 */
41 protected $_actions; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
42
43 /**
44 * Initialize the List Table.
45 *
46 * @since 1.0.0
47 */
48 public function __construct() {
49 $screen = get_current_screen();
50
51 // Hide "Last Modified By" column by default.
52 if ( false === get_user_option( "manage{$screen->id}columnshidden" ) ) {
53 update_user_option( get_current_user_id(), "manage{$screen->id}columnshidden", array( 'table_last_modified_by' ), true );
54 }
55
56 // @phpstan-ignore-next-line (WordPress Core's docblocks state wrong argument types in some places.)
57 parent::__construct( array(
58 'singular' => 'tablepress-table', // Singular name of the listed records.
59 'plural' => 'tablepress-all-tables', // Plural name of the listed records.
60 'ajax' => false, // Does this list table support AJAX?
61 'screen' => $screen, // WP_Screen object.
62 ) );
63 }
64
65 /**
66 * Set the data items (here: tables) that are to be displayed by the List Tables, and their original count.
67 *
68 * @since 1.0.0
69 *
70 * @param string[] $items Tables to be displayed in the List Table.
71 */
72 public function set_items( array $items ): void {
73 $this->items = $items;
74 $this->items_count = count( $items );
75 }
76
77 /**
78 * Check whether the user has permissions for certain AJAX actions.
79 * (not used, but must be implemented in this child class)
80 *
81 * @since 1.0.0
82 *
83 * @return bool true (Default value).
84 */
85 #[\Override]
86 public function ajax_user_can(): bool {
87 return true;
88 }
89
90 /**
91 * Get a list of columns in this List Table.
92 *
93 * Format: 'internal-name' => 'Column Title'.
94 *
95 * @since 1.0.0
96 *
97 * @return array<string, string> List of columns in this List Table.
98 */
99 #[\Override]
100 public function get_columns(): array {
101 $columns = array(
102 'cb' => $this->has_items() ? '<input type="checkbox" />' : '', // Checkbox for "Select all", but only if there are items in the table.
103 // "name" is special in WP, which is why we prefix every entry here, to be safe!
104 'table_id' => __( 'ID', 'tablepress' ),
105 'table_name' => __( 'Table Name', 'tablepress' ),
106 'table_description' => __( 'Description', 'tablepress' ),
107 'table_author' => __( 'Author', 'tablepress' ),
108 'table_last_modified_by' => __( 'Last Modified By', 'tablepress' ),
109 'table_last_modified' => __( 'Last Modified', 'tablepress' ),
110 );
111 return $columns;
112 }
113
114 /**
115 * Get a list of columns that are sortable.
116 *
117 * Format: 'internal-name' => array( $field for $item[ $field ], true for already sorted ).
118 *
119 * @since 1.0.0
120 *
121 * @return array<string, array{string, bool}> List of sortable columns in this List Table.
122 */
123 #[\Override]
124 protected function get_sortable_columns(): array {
125 // No sorting on the Empty List placeholder.
126 if ( ! $this->has_items() ) {
127 return array();
128 }
129
130 $sortable_columns = array(
131 'table_id' => array( 'id', true ), // true means its already sorted.
132 'table_name' => array( 'name', false ),
133 'table_description' => array( 'description', false ),
134 'table_author' => array( 'author', false ),
135 'table_last_modified_by' => array( 'last_modified_by', false ),
136 'table_last_modified' => array( 'last_modified', false ),
137 );
138 return $sortable_columns;
139 }
140
141 /**
142 * Gets the name of the default primary column.
143 *
144 * @since 1.7.0
145 *
146 * @return string Name of the default primary column, in this case, the table name.
147 */
148 #[\Override]
149 protected function get_default_primary_column_name(): string {
150 return 'table_name';
151 }
152
153 /**
154 * Render a cell in the "cb" column.
155 *
156 * @since 1.0.0
157 *
158 * @param array<string, mixed> $item Data item for the current row.
159 * @return string HTML content of the cell.
160 */
161 #[\Override]
162 protected function column_cb( /* array */ $item ): string {
163 // Don't use type hints in the method declaration to prevent PHP errors, as the method is inherited.
164
165 $user_can_copy_table = current_user_can( 'tablepress_copy_table', $item['id'] );
166 $user_can_delete_table = current_user_can( 'tablepress_delete_table', $item['id'] );
167 $user_can_export_table = current_user_can( 'tablepress_export_table', $item['id'] );
168
169 if ( ! ( $user_can_copy_table || $user_can_delete_table || $user_can_export_table ) ) {
170 return '';
171 }
172
173 if ( '' === trim( $item['name'] ) ) {
174 $item['name'] = __( '(no name)', 'tablepress' );
175 }
176
177 return sprintf(
178 // The `label-covers-full-cell` class on the <label> is kept for (some) backwards compatibility with WordPress 6.3, and can be removed once TablePress requires WordPress 6.4.
179 '<input type="checkbox" id="cb-select-%1$s" name="table[]" value="%1$s" /><label class="label-covers-full-cell" for="cb-select-%1$s"><span class="screen-reader-text">%2$s</span></label>',
180 esc_attr( $item['id'] ),
181 esc_html( sprintf( __( 'Select table “%s”', 'tablepress' ), $item['name'] ) )
182 );
183 }
184
185 /**
186 * Render a cell in the "table_id" column.
187 *
188 * @since 1.0.0
189 *
190 * @param array<string, mixed> $item Data item for the current row.
191 * @return string HTML content of the cell.
192 */
193 protected function column_table_id( array $item ): string {
194 return esc_html( $item['id'] );
195 }
196
197 /**
198 * Render a cell in the "table_name" column.
199 *
200 * @since 1.0.0
201 *
202 * @param array<string, mixed> $item Data item for the current row.
203 * @return string HTML content of the cell.
204 */
205 protected function column_table_name( array $item ): string {
206 $user_can_edit_table = current_user_can( 'tablepress_edit_table', $item['id'] );
207 $user_can_copy_table = current_user_can( 'tablepress_copy_table', $item['id'] );
208 $user_can_export_table = current_user_can( 'tablepress_export_table', $item['id'] );
209 $user_can_delete_table = current_user_can( 'tablepress_delete_table', $item['id'] );
210 $user_can_preview_table = current_user_can( 'tablepress_preview_table', $item['id'] );
211
212 $edit_url = TablePress::url( array( 'action' => 'edit', 'table_id' => $item['id'] ) );
213 $copy_url = TablePress::url( array( 'action' => 'copy_table', 'item' => $item['id'], 'return' => 'list', 'return_item' => $item['id'] ), true, 'admin-post.php' );
214 $export_url = TablePress::url( array( 'action' => 'export', 'table_id' => $item['id'] ) );
215 $delete_url = TablePress::url( array( 'action' => 'delete_table', 'item' => $item['id'], 'return' => 'list', 'return_item' => $item['id'] ), true, 'admin-post.php' );
216 $preview_url = TablePress::url( array( 'action' => 'preview_table', 'item' => $item['id'], 'return' => 'list', 'return_item' => $item['id'] ), true, 'admin-post.php' );
217
218 if ( '' === trim( $item['name'] ) ) {
219 $item['name'] = __( '(no name)', 'tablepress' );
220 }
221
222 if ( $user_can_edit_table ) {
223 $row_text = '<strong><a title="' . esc_attr( sprintf( __( 'Edit &#8220;%s&#8221;', 'tablepress' ), esc_attr( $item['name'] ) ) ) . '" class="row-title" href="' . $edit_url . '">' . esc_html( $item['name'] ) . '</a></strong>';
224 } else {
225 $row_text = '<strong>' . esc_html( $item['name'] ) . '</strong>';
226 }
227
228 $row_actions = array();
229 if ( $user_can_edit_table ) {
230 $row_actions['edit'] = sprintf( '<a href="%1$s" title="%2$s">%3$s</a>', $edit_url, esc_attr( sprintf( __( 'Edit &#8220;%s&#8221;', 'tablepress' ), $item['name'] ) ), __( 'Edit', 'tablepress' ) );
231 }
232 $row_actions['shortcode hide-if-no-js'] = sprintf( '<a href="%1$s" title="%2$s">%3$s</a>', '#', esc_attr( '[' . TablePress::$shortcode . " id={$item['id']} /]" ), __( 'Show Shortcode', 'tablepress' ) );
233 if ( $user_can_copy_table ) {
234 $row_actions['copy'] = sprintf( '<a href="%1$s" title="%2$s">%3$s</a>', $copy_url, esc_attr( sprintf( __( 'Copy &#8220;%s&#8221;', 'tablepress' ), $item['name'] ) ), __( 'Copy', 'tablepress' ) );
235 }
236 if ( $user_can_export_table ) {
237 $row_actions['export'] = sprintf( '<a href="%1$s" title="%2$s">%3$s</a>', $export_url, esc_attr( sprintf( __( 'Export &#8220;%s&#8221;', 'tablepress' ), $item['name'] ) ), _x( 'Export', 'row action', 'tablepress' ) );
238 }
239 if ( $user_can_delete_table ) {
240 $row_actions['delete'] = sprintf( '<a href="%1$s" title="%2$s" class="delete-link">%3$s</a>', $delete_url, esc_attr( sprintf( __( 'Delete &#8220;%s&#8221;', 'tablepress' ), $item['name'] ) ), __( 'Delete', 'tablepress' ) );
241 }
242 if ( $user_can_preview_table ) {
243 $row_actions['table-preview'] = sprintf( '<a href="%1$s" title="%2$s">%3$s</a>', $preview_url, esc_attr( sprintf( __( 'Preview of table “%1$s” (ID %2$s)', 'tablepress' ), $item['name'], $item['id'] ) ), __( 'Preview', 'tablepress' ) );
244 }
245
246 return $row_text . $this->row_actions( $row_actions );
247 }
248
249 /**
250 * Render a cell in the "table_description" column.
251 *
252 * @since 1.0.0
253 *
254 * @param array<string, mixed> $item Data item for the current row.
255 * @return string HTML content of the cell.
256 */
257 protected function column_table_description( array $item ): string {
258 if ( '' === trim( $item['description'] ) ) {
259 $item['description'] = __( '(no description)', 'tablepress' );
260 }
261 return esc_html( $item['description'] );
262 }
263
264 /**
265 * Render a cell in the "table_author" column.
266 *
267 * @since 1.0.0
268 *
269 * @param array<string, mixed> $item Data item for the current row.
270 * @return string HTML content of the cell.
271 */
272 protected function column_table_author( array $item ): string {
273 return TablePress::get_user_display_name( $item['author'] );
274 }
275
276 /**
277 * Render a cell in the "last_modified_by" column.
278 *
279 * @since 1.0.0
280 *
281 * @param array<string, mixed> $item Data item for the current row.
282 * @return string HTML content of the cell.
283 */
284 protected function column_table_last_modified_by( array $item ): string {
285 return TablePress::get_user_display_name( $item['options']['last_editor'] );
286 }
287
288 /**
289 * Render a cell in the "table_last_modified" column.
290 *
291 * @since 1.0.0
292 *
293 * @param array<string, mixed> $item Data item for the current row.
294 * @return string HTML content of the cell.
295 */
296 protected function column_table_last_modified( array $item ): string {
297 $modified_timestamp = date_create( $item['last_modified'], wp_timezone() );
298 $modified_timestamp = $modified_timestamp->getTimestamp(); // @phpstan-ignore-line
299 $current_timestamp = time();
300 $time_diff = $current_timestamp - $modified_timestamp;
301 // Time difference is only shown up to one week.
302 if ( $time_diff >= 0 && $time_diff < WEEK_IN_SECONDS ) {
303 $time_diff = sprintf( __( '%s ago', 'default' ), human_time_diff( $modified_timestamp, $current_timestamp ) );
304 } else {
305 $time_diff = TablePress::format_datetime( $item['last_modified'], '<br />' );
306 }
307 $readable_time = TablePress::format_datetime( $item['last_modified'] );
308 return '<abbr title="' . esc_attr( $readable_time ) . '">' . $time_diff . '</abbr>';
309 }
310
311 /**
312 * Handles output for the default column.
313 *
314 * @since 1.8.0
315 *
316 * @param array<string, mixed> $item Data item for the current row.
317 * @param string $column_name Current column name.
318 */
319 #[\Override]
320 protected function column_default( /* array */ $item, /* string */ $column_name ): void {
321 // Don't use type hints in the method declaration to prevent PHP errors, as the method is inherited.
322
323 /**
324 * Fires inside each custom column of the TablePress list table.
325 *
326 * @since 1.8.0
327 *
328 * @param string $column_name Current column name.
329 * @param array<string, mixed> $item Data item for the current row.
330 */
331 do_action( 'manage_tablepress_list_custom_column', $column_name, $item );
332 }
333
334 /**
335 * Generates and display row actions links for the list table.
336 *
337 * The "Table Name" column already gets these, so return an empty string here to prevent them from being duplicated.
338 *
339 * @since 2.0.0
340 *
341 * @param object|array<string, mixed> $item The item being acted upon.
342 * @param string $column_name Current column name.
343 * @param string $primary Primary column name.
344 * @return string The row actions HTML, or an empty string if the current column is not the primary column.
345 */
346 #[\Override]
347 protected function handle_row_actions( /* object|array */ $item, /* string */ $column_name, /* string */ $primary ): string {
348 // Don't use type hints in the method declaration to prevent PHP errors, as the method is inherited.
349
350 return '';
351 }
352
353 /**
354 * Get a list (name => title) bulk actions that are available.
355 *
356 * @since 1.0.0
357 *
358 * @return array<string, string> Bulk actions for this table.
359 */
360 #[\Override]
361 protected function get_bulk_actions(): array {
362 $bulk_actions = array();
363
364 if ( current_user_can( 'tablepress_copy_tables' ) ) {
365 $bulk_actions['copy'] = _x( 'Copy', 'bulk action', 'tablepress' );
366 }
367 if ( current_user_can( 'tablepress_export_tables' ) ) {
368 $bulk_actions['export'] = _x( 'Export', 'bulk action', 'tablepress' );
369 }
370 if ( current_user_can( 'tablepress_delete_tables' ) ) {
371 $bulk_actions['delete'] = _x( 'Delete', 'bulk action', 'tablepress' );
372 }
373
374 return $bulk_actions;
375 }
376
377 /**
378 * Render the bulk actions dropdown.
379 *
380 * In comparison with parent class, this has modified HTML (especially no field named "action" as that's being used already)!
381 *
382 * @since 1.0.0
383 *
384 * @param 'top'|'bottom' $which The location of the bulk actions: 'top' or 'bottom'.
385 * This is designated as optional for backwards-compatibility.
386 */
387 #[\Override]
388 protected function bulk_actions( /* string */ $which = 'top' ): void {
389 // Don't use type hints in the method declaration to prevent PHP errors, as the method is inherited.
390
391 if ( is_null( $this->_actions ) ) {
392 $this->_actions = $this->get_bulk_actions();
393 $no_new_actions = $this->_actions;
394 /** This filter is documented in the WordPress function WP_List_Table::bulk_actions() in wp-admin/includes/class-wp-list-table.php */
395 $this->_actions = apply_filters( 'bulk_actions-' . $this->screen->id, $this->_actions ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
396 $this->_actions = array_intersect_assoc( $this->_actions, $no_new_actions );
397 $two = '';
398 } else {
399 $two = '2';
400 }
401
402 if ( empty( $this->_actions ) ) {
403 return;
404 }
405
406 $name_id = "bulk-action-selector-{$which}";
407 echo "<label for='{$name_id}' class='screen-reader-text'>" . __( 'Select Bulk Action', 'tablepress' ) . "</label>\n";
408 echo "<select name='{$name_id}' id='{$name_id}'>\n";
409 echo "<option value='-1' selected='selected'>" . __( 'Bulk Actions', 'tablepress' ) . "</option>\n";
410 foreach ( $this->_actions as $name => $title ) {
411 echo "\t<option value='{$name}'>{$title}</option>\n";
412 }
413 echo "</select>\n";
414 submit_button( __( 'Apply', 'tablepress' ), 'action', '', false, array( 'id' => "doaction{$two}" ) );
415 echo "\n";
416 }
417
418 /**
419 * Holds the message to be displayed when there are no items in the table.
420 *
421 * @since 1.0.0
422 */
423 #[\Override]
424 public function no_items(): void {
425 _e( 'No tables found.', 'tablepress' );
426 if ( 0 === $this->items_count ) {
427 $user_can_add_tables = current_user_can( 'tablepress_add_tables' );
428 $user_can_import_tables = current_user_can( 'tablepress_import_tables' );
429
430 $add_url = TablePress::url( array( 'action' => 'add' ) );
431 $import_url = TablePress::url( array( 'action' => 'import' ) );
432
433 if ( $user_can_add_tables && $user_can_import_tables ) {
434 echo ' ' . sprintf( __( 'You should <a href="%1$s">add</a> or <a href="%2$s">import</a> a table to get started!', 'tablepress' ), $add_url, $import_url );
435 } elseif ( $user_can_add_tables ) {
436 echo ' ' . sprintf( __( 'You should <a href="%s">add</a> a table to get started!', 'tablepress' ), $add_url );
437 } elseif ( $user_can_import_tables ) {
438 echo ' ' . sprintf( __( 'You should <a href="%s">import</a> a table to get started!', 'tablepress' ), $import_url );
439 }
440 }
441 }
442
443 /**
444 * Generate the elements above or below the table (like bulk actions and pagination).
445 *
446 * In comparison with parent class, this has no nonce field in its HTML code and a one-time filter around the pagination call, to change a string.
447 *
448 * @since 1.0.0
449 *
450 * @param 'top'|'bottom' $which Location ("top" or "bottom").
451 */
452 #[\Override]
453 protected function display_tablenav( /* string */ $which ): void {
454 // Don't use type hints in the method declaration to prevent PHP errors, as the method is inherited.
455
456 ?>
457 <div class="tablenav <?php echo esc_attr( $which ); ?>">
458
459 <?php if ( $this->has_items() ) : ?>
460 <div class="alignleft actions bulkactions">
461 <?php $this->bulk_actions( $which ); ?>
462 </div>
463 <?php
464 endif;
465 $this->extra_tablenav( $which );
466
467 add_filter( 'ngettext_default', array( $this, 'change_pagination_items_string' ), 10, 5 );
468 $this->pagination( $which );
469 remove_filter( 'ngettext_default', array( $this, 'change_pagination_items_string' ), 10 );
470 ?>
471
472 <br class="clear" />
473 </div>
474 <?php
475 }
476
477 /**
478 * Replaces the "%s item/%s items" string in the pagination with "%s table/%s tables".
479 *
480 * @since 2.0.0
481 *
482 * @param string $translation The current translation of a singular or plural form.
483 * @param string $single The text to be used if the number is singular.
484 * @param string $plural The text to be used if the number is plural.
485 * @param int $number The number to compare against to use either the singular or plural form.
486 * @param string $domain Text domain. Defaults to 'default'.
487 * @return string The changed translation.
488 */
489 public function change_pagination_items_string( string $translation, string $single, string $plural, int $number, string $domain ): string {
490 if ( '%s item' === $single && '%s items' === $plural ) {
491 $translation = _n( '%s table', '%s tables', $number, 'tablepress' );
492 }
493 return $translation;
494 }
495
496 /**
497 * Callback to determine whether the given $item contains the search term.
498 *
499 * @since 1.0.0
500 *
501 * @param string $item Table ID that shall be searched.
502 * @return bool Whether the search term was found or not.
503 */
504 protected function _search_callback( string $item ): bool {
505 static $term;
506 static $json_encoded_term;
507 if ( is_null( $term ) || is_null( $json_encoded_term ) ) {
508 $term = wp_unslash( $_GET['s'] );
509 $json_encoded_term = substr( wp_json_encode( $term, TABLEPRESS_JSON_OPTIONS ), 1, -1 ); // @phpstan-ignore-line
510 }
511
512 static $debug;
513 if ( is_null( $debug ) ) {
514 // Set debug variable to allow searching in corrupted tables.
515 $debug = isset( $_GET['debug'] ) ? ( 'true' === $_GET['debug'] ) : WP_DEBUG;
516 }
517
518 // Load table again, with data and options (for last_editor).
519 $item = TablePress::$model_table->load( $item, true, true );
520
521 if ( is_wp_error( $item ) ) {
522 return false;
523 }
524
525 // Don't search corrupted tables, except when debug mode is enabled via $_GET parameter or WP_DEBUG constant.
526 if ( ! $debug && isset( $item['is_corrupted'] ) && $item['is_corrupted'] ) {
527 return false;
528 }
529
530 // Search from easy to hard, so that "expensive" code maybe doesn't have to run.
531 if ( false !== stripos( $item['id'], $term )
532 || false !== stripos( $item['name'], $term )
533 || false !== stripos( $item['description'], $term )
534 || false !== stripos( TablePress::get_user_display_name( $item['author'] ), $term )
535 || false !== stripos( TablePress::get_user_display_name( $item['options']['last_editor'] ), $term )
536 || false !== stripos( TablePress::format_datetime( $item['last_modified'] ), $term )
537 || false !== stripos( wp_json_encode( $item['data'], TABLEPRESS_JSON_OPTIONS ), $json_encoded_term ) ) { // @phpstan-ignore-line
538 return true;
539 }
540
541 return false;
542 }
543
544 /**
545 * Callback to for the array sort function.
546 *
547 * @since 1.0.0
548 *
549 * @param array<string, mixed> $item_a First item that shall be compared to.
550 * @param array<string, mixed> $item_b The second item for the comparison.
551 * @return int (-1, 0, 1) depending on which item sorts "higher".
552 */
553 protected function _order_callback( array $item_a, array $item_b ): int {
554 global $orderby, $order;
555
556 if ( 'last_modified_by' !== $orderby ) {
557 if ( $item_a[ $orderby ] === $item_b[ $orderby ] ) {
558 return 0;
559 }
560 } else { // phpcs:ignore Universal.ControlStructures.DisallowLonelyIf.Found
561 if ( $item_a['options']['last_editor'] === $item_b['options']['last_editor'] ) {
562 return 0;
563 }
564 }
565
566 // Certain fields require some extra work before being sortable.
567 switch ( $orderby ) {
568 case 'last_modified':
569 // Compare UNIX timestamps for "last modified", which actually is a mySQL datetime string.
570 $result = ( strtotime( $item_a['last_modified'] ) > strtotime( $item_b['last_modified'] ) ) ? 1 : -1;
571 break;
572 case 'author':
573 // Get the actual author name, plain value is just the user ID.
574 $result = strnatcasecmp( TablePress::get_user_display_name( $item_a['author'] ), TablePress::get_user_display_name( $item_b['author'] ) );
575 break;
576 case 'last_modified_by':
577 // Get the actual last editor name, plain value is just the user ID.
578 $result = strnatcasecmp( TablePress::get_user_display_name( $item_a['options']['last_editor'] ), TablePress::get_user_display_name( $item_b['options']['last_editor'] ) );
579 break;
580 default:
581 // Other fields (ID, name, description) are sorted as strings.
582 $result = strnatcasecmp( $item_a[ $orderby ], $item_b[ $orderby ] );
583 }
584
585 return ( 'asc' === $order ) ? $result : - $result;
586 }
587
588 /**
589 * Prepares the list of items for displaying, by maybe searching and sorting, and by doing pagination.
590 *
591 * @since 1.0.0
592 */
593 #[\Override]
594 public function prepare_items(): void {
595 global $orderby, $order, $s;
596 wp_reset_vars( array( 'orderby', 'order', 's' ) );
597
598 // Maybe search in the items.
599 if ( $s ) {
600 $this->items = array_filter( $this->items, array( $this, '_search_callback' ) );
601 }
602
603 // Load actual tables after search for less memory consumption.
604 foreach ( $this->items as &$item ) {
605 // Don't load data, but load table options for access to last_editor.
606 $item = TablePress::$model_table->load( $item, false, true );
607 }
608 // Break reference in foreach iterator.
609 unset( $item );
610
611 // Maybe sort the items.
612 $_sortable_columns = $this->get_sortable_columns();
613 if ( $orderby && ! empty( $this->items ) && isset( $_sortable_columns[ "table_{$orderby}" ] ) ) {
614 usort( $this->items, array( $this, '_order_callback' ) );
615 }
616
617 // Number of records to show per page.
618 $per_page = $this->get_items_per_page( 'tablepress_list_per_page', 20 ); // Hard-coded, as in filter in Admin_Controller.
619 // Page number the user is currently viewing.
620 $current_page = $this->get_pagenum();
621 // Number of records in the array.
622 $total_items = count( $this->items );
623
624 // Slice items array to hold only items for the current page.
625 $this->items = array_slice( $this->items, ( ( $current_page - 1 ) * $per_page ), $per_page );
626
627 // Register pagination options and calculation results.
628 $this->set_pagination_args( array(
629 'total_items' => $total_items, // Total number of records/items.
630 'per_page' => $per_page, // Number of items per page.
631 'total_pages' => (int) ceil( $total_items / $per_page ), // Total number of pages.
632 ) );
633 }
634
635 } // class TablePress_All_Tables_List_Table
636