PluginProbe
TablePress – Tables in WordPress made easy / 2.2.1
TablePress – Tables in WordPress made easy v2.2.1
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.1, at views/class-all-tables-list-table.php

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