PluginProbe
TablePress – Tables in WordPress made easy / 3.4
TablePress – Tables in WordPress made easy v3.4
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
← All changes | views/class-all-tables-list-table.php +67 -29 2.2.3 → 3.4 View file →
@@ -7,8 +7,10 @@
7 7 * @author Tobias Bäthge
8 8 * @since 2.0.0
9 9 */
10 10
11 +declare(strict_types=1);
12 +
11 13 // Prohibit direct script loading.
12 14 defined( 'ABSPATH' ) || die( 'No direct script access allowed!' );
13 15
14 16 /**
@@ -24,11 +26,10 @@
24 26 /**
25 27 * Number of items of the initial data set (before sort, search, and pagination).
26 28 *
27 29 * @since 1.0.0
28 - * @var int
29 30 */
30 - protected $items_count = 0;
31 + protected int $items_count = 0;
31 32
32 33 /**
33 34 * Cached bulk actions.
34 35 *
@@ -35,11 +36,11 @@
35 36 * This property has to be declared here, as it's `private` in the parent class
36 37 * and thus can't be inherited.
37 38 *
38 39 * @since 1.0.0
39 - * @var array<string, string>|null
40 + * @var array<string, string>
40 41 */
41 - protected $_actions; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
42 + protected array $_actions; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
42 43
43 44 /**
44 45 * Initialize the List Table.
45 46 *
@@ -48,13 +49,13 @@
48 49 public function __construct() {
49 50 $screen = get_current_screen();
50 51
51 52 // 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 );
53 + if ( false === get_user_option( "manage{$screen->id}columnshidden" ) ) { // @phpstan-ignore property.nonObject
54 + update_user_option( get_current_user_id(), "manage{$screen->id}columnshidden", array( 'table_last_modified_by' ), true ); // @phpstan-ignore property.nonObject
54 55 }
55 56
56 - // @phpstan-ignore-next-line (WordPress Core's docblocks state wrong argument types in some places.)
57 + // @phpstan-ignore argument.type (WordPress Core's docblocks state wrong argument types in some places.)
57 58 parent::__construct( array(
58 59 'singular' => 'tablepress-table', // Singular name of the listed records.
59 60 'plural' => 'tablepress-all-tables', // Plural name of the listed records.
60 61 'ajax' => false, // Does this list table support AJAX?
@@ -81,8 +82,9 @@
81 82 * @since 1.0.0
82 83 *
83 84 * @return bool true (Default value).
84 85 */
86 + #[\Override]
85 87 public function ajax_user_can(): bool {
86 88 return true;
87 89 }
88 90
@@ -94,11 +96,12 @@
94 96 * @since 1.0.0
95 97 *
96 98 * @return array<string, string> List of columns in this List Table.
97 99 */
100 + #[\Override]
98 101 public function get_columns(): array {
99 102 $columns = array(
100 - 'cb' => $this->has_items() ? '<input type="checkbox" />' : '', // Checkbox for "Select all", but only if there are items in the table.
103 + 'cb' => $this->has_items() ? '<input type="checkbox">' : '', // Checkbox for "Select all", but only if there are items in the table.
101 104 // "name" is special in WP, which is why we prefix every entry here, to be safe!
102 105 'table_id' => __( 'ID', 'tablepress' ),
103 106 'table_name' => __( 'Table Name', 'tablepress' ),
104 107 'table_description' => __( 'Description', 'tablepress' ),
@@ -117,8 +120,9 @@
117 120 * @since 1.0.0
118 121 *
119 122 * @return array<string, array{string, bool}> List of sortable columns in this List Table.
120 123 */
124 + #[\Override]
121 125 protected function get_sortable_columns(): array {
122 126 // No sorting on the Empty List placeholder.
123 127 if ( ! $this->has_items() ) {
124 128 return array();
@@ -141,8 +145,9 @@
141 145 * @since 1.7.0
142 146 *
143 147 * @return string Name of the default primary column, in this case, the table name.
144 148 */
149 + #[\Override]
145 150 protected function get_default_primary_column_name(): string {
146 151 return 'table_name';
147 152 }
148 153
@@ -153,8 +158,9 @@
153 158 *
154 159 * @param array<string, mixed> $item Data item for the current row.
155 160 * @return string HTML content of the cell.
156 161 */
162 + #[\Override]
157 163 protected function column_cb( /* array */ $item ): string {
158 164 // Don't use type hints in the method declaration to prevent PHP errors, as the method is inherited.
159 165
160 166 $user_can_copy_table = current_user_can( 'tablepress_copy_table', $item['id'] );
@@ -169,12 +175,11 @@
169 175 $item['name'] = __( '(no name)', 'tablepress' );
170 176 }
171 177
172 178 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>',
179 + '<input type="checkbox" id="cb-select-%1$s" name="table[]" value="%1$s"><label for="cb-select-%1$s"><span class="screen-reader-text">%2$s</span></label>',
175 180 esc_attr( $item['id'] ),
176 - esc_html( sprintf( __( 'Select table “%s”', 'tablepress' ), $item['name'] ) )
181 + esc_html( sprintf( __( 'Select table “%s”', 'tablepress' ), $item['name'] ) ),
177 182 );
178 183 }
179 184
180 185 /**
@@ -189,8 +194,25 @@
189 194 return esc_html( $item['id'] );
190 195 }
191 196
192 197 /**
198 + * Returns a clean label for the primary (Table Name) column's row header `aria-label`.
199 + *
200 + * Provides screen readers with just the table name as the row header name,
201 + * preventing them from computing the name from the full cell content.
202 + *
203 + * @since 3.3.4
204 + *
205 + * @param array<string, mixed> $item Data item for the current row.
206 + * @return string The table name.
207 + */
208 + protected function get_primary_column_aria_label( /* array */ $item ): string {
209 + // Don't use type hints in the method declaration to prevent PHP errors, as the method is inherited.
210 +
211 + return trim( $item['name'] );
212 + }
213 +
214 + /**
193 215 * Render a cell in the "table_name" column.
194 216 *
195 217 * @since 1.0.0
196 218 *
@@ -231,9 +253,9 @@
231 253 if ( $user_can_export_table ) {
232 254 $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 255 }
234 256 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' ) );
257 + $row_actions['delete'] = sprintf( '<a href="%1$s" title="%2$s">%3$s</a>', $delete_url, esc_attr( sprintf( __( 'Delete “%1$s” (ID %2$s)', 'tablepress' ), $item['name'], $item['id'] ) ), __( 'Delete', 'tablepress' ) );
236 258 }
237 259 if ( $user_can_preview_table ) {
238 260 $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 261 }
@@ -289,9 +311,13 @@
289 311 * @return string HTML content of the cell.
290 312 */
291 313 protected function column_table_last_modified( array $item ): string {
292 314 $modified_timestamp = date_create( $item['last_modified'], wp_timezone() );
293 - $modified_timestamp = $modified_timestamp->getTimestamp(); // @phpstan-ignore-line
315 + if ( false === $modified_timestamp ) {
316 + $modified_timestamp = $item['last_modified'];
317 + } else {
318 + $modified_timestamp = $modified_timestamp->getTimestamp();
319 + }
294 320 $current_timestamp = time();
295 321 $time_diff = $current_timestamp - $modified_timestamp;
296 322 // Time difference is only shown up to one week.
297 323 if ( $time_diff >= 0 && $time_diff < WEEK_IN_SECONDS ) {
@@ -296,9 +322,9 @@
296 322 // Time difference is only shown up to one week.
297 323 if ( $time_diff >= 0 && $time_diff < WEEK_IN_SECONDS ) {
298 324 $time_diff = sprintf( __( '%s ago', 'default' ), human_time_diff( $modified_timestamp, $current_timestamp ) );
299 325 } else {
300 - $time_diff = TablePress::format_datetime( $item['last_modified'], '<br />' );
326 + $time_diff = TablePress::format_datetime( $item['last_modified'], '<br>' );
301 327 }
302 328 $readable_time = TablePress::format_datetime( $item['last_modified'] );
303 329 return '<abbr title="' . esc_attr( $readable_time ) . '">' . $time_diff . '</abbr>';
304 330 }
@@ -310,8 +336,9 @@
310 336 *
311 337 * @param array<string, mixed> $item Data item for the current row.
312 338 * @param string $column_name Current column name.
313 339 */
340 + #[\Override]
314 341 protected function column_default( /* array */ $item, /* string */ $column_name ): void {
315 342 // Don't use type hints in the method declaration to prevent PHP errors, as the method is inherited.
316 343
317 344 /**
@@ -336,8 +363,9 @@
336 363 * @param string $column_name Current column name.
337 364 * @param string $primary Primary column name.
338 365 * @return string The row actions HTML, or an empty string if the current column is not the primary column.
339 366 */
367 + #[\Override]
340 368 protected function handle_row_actions( /* object|array */ $item, /* string */ $column_name, /* string */ $primary ): string {
341 369 // Don't use type hints in the method declaration to prevent PHP errors, as the method is inherited.
342 370
343 371 return '';
@@ -349,8 +377,9 @@
349 377 * @since 1.0.0
350 378 *
351 379 * @return array<string, string> Bulk actions for this table.
352 380 */
381 + #[\Override]
353 382 protected function get_bulk_actions(): array {
354 383 $bulk_actions = array();
355 384
356 385 if ( current_user_can( 'tablepress_copy_tables' ) ) {
@@ -375,12 +404,13 @@
375 404 *
376 405 * @param 'top'|'bottom' $which The location of the bulk actions: 'top' or 'bottom'.
377 406 * This is designated as optional for backwards-compatibility.
378 407 */
408 + #[\Override]
379 409 protected function bulk_actions( /* string */ $which = 'top' ): void {
380 410 // Don't use type hints in the method declaration to prevent PHP errors, as the method is inherited.
381 411
382 - if ( is_null( $this->_actions ) ) {
412 + if ( ! isset( $this->_actions ) ) {
383 413 $this->_actions = $this->get_bulk_actions();
384 414 $no_new_actions = $this->_actions;
385 415 /** This filter is documented in the WordPress function WP_List_Table::bulk_actions() in wp-admin/includes/class-wp-list-table.php */
386 416 $this->_actions = apply_filters( 'bulk_actions-' . $this->screen->id, $this->_actions ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
@@ -394,16 +424,19 @@
394 424 return;
395 425 }
396 426
397 427 $name_id = "bulk-action-selector-{$which}";
398 - echo "<label for='{$name_id}' class='screen-reader-text'>" . __( 'Select Bulk Action', 'tablepress' ) . "</label>\n";
428 + echo "<label for='{$name_id}' class='screen-reader-text'>" .
429 + /* translators: Hidden accessibility text. */
430 + __( 'Select bulk action', 'default' ) .
431 + '</label>';
399 432 echo "<select name='{$name_id}' id='{$name_id}'>\n";
400 - echo "<option value='-1' selected='selected'>" . __( 'Bulk Actions', 'tablepress' ) . "</option>\n";
433 + echo "<option value='-1' selected='selected'>" . __( 'Bulk actions', 'default' ) . "</option>\n";
401 434 foreach ( $this->_actions as $name => $title ) {
402 435 echo "\t<option value='{$name}'>{$title}</option>\n";
403 436 }
404 437 echo "</select>\n";
405 - submit_button( __( 'Apply', 'tablepress' ), 'action', '', false, array( 'id' => "doaction{$two}" ) );
438 + submit_button( __( 'Apply', 'default' ), 'action', 'bulk_action', false, array( 'id' => "doaction{$two}" ) );
406 439 echo "\n";
407 440 }
408 441
409 442 /**
@@ -410,8 +443,9 @@
410 443 * Holds the message to be displayed when there are no items in the table.
411 444 *
412 445 * @since 1.0.0
413 446 */
447 + #[\Override]
414 448 public function no_items(): void {
415 449 _e( 'No tables found.', 'tablepress' );
416 450 if ( 0 === $this->items_count ) {
417 451 $user_can_add_tables = current_user_can( 'tablepress_add_tables' );
@@ -438,8 +472,9 @@
438 472 * @since 1.0.0
439 473 *
440 474 * @param 'top'|'bottom' $which Location ("top" or "bottom").
441 475 */
476 + #[\Override]
442 477 protected function display_tablenav( /* string */ $which ): void {
443 478 // Don't use type hints in the method declaration to prevent PHP errors, as the method is inherited.
444 479
445 480 ?>
@@ -457,9 +492,9 @@
457 492 $this->pagination( $which );
458 493 remove_filter( 'ngettext_default', array( $this, 'change_pagination_items_string' ), 10 );
459 494 ?>
460 495
461 - <br class="clear" />
496 + <br class="clear">
462 497 </div>
463 498 <?php
464 499 }
465 500
@@ -476,8 +511,9 @@
476 511 * @return string The changed translation.
477 512 */
478 513 public function change_pagination_items_string( string $translation, string $single, string $plural, int $number, string $domain ): string {
479 514 if ( '%s item' === $single && '%s items' === $plural ) {
515 + /* translators: %s: Number of tables */
480 516 $translation = _n( '%s table', '%s tables', $number, 'tablepress' );
481 517 }
482 518 return $translation;
483 519 }
@@ -494,9 +530,9 @@
494 530 static $term;
495 531 static $json_encoded_term;
496 532 if ( is_null( $term ) || is_null( $json_encoded_term ) ) {
497 533 $term = wp_unslash( $_GET['s'] );
498 - $json_encoded_term = substr( wp_json_encode( $term, TABLEPRESS_JSON_OPTIONS ), 1, -1 ); // @phpstan-ignore-line
534 + $json_encoded_term = substr( wp_json_encode( $term, TABLEPRESS_JSON_OPTIONS ), 1, -1 ); // @phpstan-ignore argument.type
499 535 }
500 536
501 537 static $debug;
502 538 if ( is_null( $debug ) ) {
@@ -515,16 +551,18 @@
515 551 if ( ! $debug && isset( $item['is_corrupted'] ) && $item['is_corrupted'] ) {
516 552 return false;
517 553 }
518 554
555 + $fn_stripos = function_exists( 'mb_stripos' ) ? 'mb_stripos' : 'stripos';
556 +
519 557 // 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
558 + if ( false !== $fn_stripos( $item['id'], (string) $term )
559 + || false !== $fn_stripos( $item['name'], (string) $term )
560 + || false !== $fn_stripos( $item['description'], (string) $term )
561 + || false !== $fn_stripos( TablePress::get_user_display_name( $item['author'] ), (string) $term )
562 + || false !== $fn_stripos( TablePress::get_user_display_name( $item['options']['last_editor'] ), (string) $term )
563 + || false !== $fn_stripos( TablePress::format_datetime( $item['last_modified'] ), (string) $term )
564 + || false !== $fn_stripos( wp_json_encode( $item['data'], TABLEPRESS_JSON_OPTIONS ), (string) $json_encoded_term ) ) { // @phpstan-ignore argument.type
527 565 return true;
528 566 }
529 567
530 568 return false;
@@ -578,8 +616,9 @@
578 616 * Prepares the list of items for displaying, by maybe searching and sorting, and by doing pagination.
579 617 *
580 618 * @since 1.0.0
581 619 */
620 + #[\Override]
582 621 public function prepare_items(): void {
583 622 global $orderby, $order, $s;
584 623 wp_reset_vars( array( 'orderby', 'order', 's' ) );
585 624
@@ -592,10 +631,9 @@
592 631 foreach ( $this->items as &$item ) {
593 632 // Don't load data, but load table options for access to last_editor.
594 633 $item = TablePress::$model_table->load( $item, false, true );
595 634 }
596 - // Break reference in foreach iterator.
597 - unset( $item );
635 + unset( $item ); // Unset use-by-reference parameter of foreach loop.
598 636
599 637 // Maybe sort the items.
600 638 $_sortable_columns = $this->get_sortable_columns();
601 639 if ( $orderby && ! empty( $this->items ) && isset( $_sortable_columns[ "table_{$orderby}" ] ) ) {