PluginProbe
TablePress – Tables in WordPress made easy / 1.14
TablePress – Tables in WordPress made easy v1.14
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 2.4.4 All 44 releases
tablepress / views / view-list.php

view-list.php in TablePress – Tables in WordPress made easy 1.14, at views/view-list.php

789 lines 33.0 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
4 *
5 * @package TablePress
6 * @subpackage Views
7 * @author Tobias Bäthge
8 * @since 1.0.0
9 */
10
11 // Prohibit direct script loading.
12 defined( 'ABSPATH' ) || die( 'No direct script access allowed!' );
13
14 /**
15 * List Tables View class
16 * @package TablePress
17 * @subpackage Views
18 * @author Tobias Bäthge
19 * @since 1.0.0
20 */
21 class TablePress_List_View extends TablePress_View {
22
23 /**
24 * Object for the All Tables List Table.
25 *
26 * @since 1.0.0
27 * @var TablePress_All_Tables_List_Table
28 */
29 protected $wp_list_table;
30
31 /**
32 * Set up the view with data and do things that are specific for this view.
33 *
34 * @since 1.0.0
35 *
36 * @param string $action Action for this view.
37 * @param array $data Data for this view.
38 */
39 public function setup( $action, array $data ) {
40 parent::setup( $action, $data );
41
42 add_thickbox();
43 $this->admin_page->enqueue_script( 'list', array( 'jquery' ), array( // phpcs:ignore PEAR.Functions.FunctionCallSignature.MultipleArguments
44 'list' => array(
45 'shortcode_popup' => __( 'To embed this table into a post or page, use this Shortcode:', 'tablepress' ),
46 'donation-message-already-donated' => __( 'Thank you very much! Your donation is highly appreciated. You just contributed to the further development of TablePress!', 'tablepress' ),
47 'donation-message-maybe-later' => sprintf( __( 'No problem! I still hope you enjoy the benefits that TablePress adds to your site. If you should change your mind, you&#8217;ll always find the &#8220;Donate&#8221; button on the <a href="%s">TablePress website</a>.', 'tablepress' ), 'https://tablepress.org/' ),
48 ),
49 ) );
50
51 if ( $data['messages']['first_visit'] ) {
52 $this->add_header_message(
53 __( 'Thank you for using TablePress for the first time!', 'tablepress' ) . ' '
54 . sprintf( __( 'If you encounter any questions or problems, please visit the <a href="%1$s">FAQ</a>, the <a href="%2$s">Documentation</a>, and the <a href="%3$s">Support</a> section on the <a href="%4$s">plugin website</a>.', 'tablepress' ), 'https://tablepress.org/faq/', 'https://tablepress.org/documentation/', 'https://tablepress.org/support/', 'https://tablepress.org/' ) . '</p><p>'
55 . $this->ajax_link( array( 'action' => 'hide_message', 'item' => 'first_visit', 'return' => 'list' ), __( 'Hide this message', 'tablepress' ) ),
56 'notice-info not-dismissible',
57 '<em>' . __( 'Welcome!', 'tablepress' ) . '</em>'
58 );
59 }
60
61 if ( $data['messages']['wp_table_reloaded_warning'] ) {
62 $this->add_header_message(
63 '<strong>' . __( 'You have activated the plugin WP-Table Reloaded, which can not be used together with TablePress.', 'tablepress' ) . '</strong><br />'
64 . __( 'It is strongly recommended that you switch from WP-Table Reloaded to TablePress, which not only fixes many problems, but also has more and better features than WP-Table Reloaded.', 'tablepress' ) . '<br />'
65 . sprintf( __( 'Please follow the <a href="%s">migration guide</a> to move your tables and then deactivate WP-Table Reloaded!', 'tablepress' ), 'https://tablepress.org/migration-from-wp-table-reloaded/' ),
66 'notice-error not-dismissible',
67 '<em>' . __( 'Attention!', 'tablepress' ) . '</em>'
68 );
69 }
70
71 if ( $data['messages']['donation_message'] ) {
72 $this->add_header_message(
73 '<img alt="' . esc_attr__( 'Tobias Bäthge, developer of TablePress', 'tablepress' ) . '" src="https://secure.gravatar.com/avatar/50f1cff2e27a1f522b18ce229c057bc5?s=110" height="110" width="110" style="float:left;margin:2px 10px 30px 0;" />'
74 . __( 'Hi, my name is Tobias, I&#8217;m the developer of the TablePress plugin.', 'tablepress' ) . '</p><p>'
75 . __( 'Thanks for using it! You&#8217;ve installed TablePress over a month ago.', 'tablepress' ) . ' '
76 . sprintf( _n( 'If everything works and you are satisfied with the results of managing your %s table, isn&#8217;t that worth a coffee or two?', 'If everything works and you are satisfied with the results of managing your %s tables, isn&#8217;t that worth a coffee or two?', $data['table_count'], 'tablepress' ), esc_html( $data['table_count'] ) ) . '<br />'
77 . sprintf( __( '<a href="%s">Donations</a> help me to continue user support and development of this <em>free</em> software &mdash; things for which I spend countless hours of my free time! Thank you very much!', 'tablepress' ), 'https://tablepress.org/donate/' ) . '</p><p>'
78 . __( 'Sincerely, Tobias', 'tablepress' ) . '</p><p style="font-size:14px">'
79 . sprintf( '<a href="%s" class="button" target="_blank" rel="noopener"><strong>%s</strong></a>', 'https://tablepress.org/donate/', __( 'Sure, I&#8217;ll buy you a coffee and support TablePress!', 'tablepress' ) ) . '&nbsp;&nbsp;&nbsp;'
80 . $this->ajax_link( array( 'action' => 'hide_message', 'item' => 'donation_nag', 'return' => 'list', 'target' => 'already-donated', 'class' => 'button' ), __( 'I already donated.', 'tablepress' ) ) . '&nbsp;&nbsp;&nbsp;'
81 . $this->ajax_link( array( 'action' => 'hide_message', 'item' => 'donation_nag', 'return' => 'list', 'target' => 'maybe-later', 'class' => 'button' ), __( 'No, thanks. Don&#8217;t ask again.', 'tablepress' ) ),
82 'notice-success not-dismissible',
83 '<em>' . __( 'TablePress needs you!', 'tablepress' ) . '</em>'
84 );
85 }
86
87 if ( $data['messages']['plugin_update_message'] ) {
88 $this->add_header_message(
89 sprintf( __( 'Please read the <a href="%s">release announcement</a> for more information.', 'tablepress' ), 'https://tablepress.org/news/' ) . ' '
90 . sprintf( __( 'If you like the new features and enhancements, <a href="%s">giving a donation</a> towards the further support and development of TablePress is recommended. Thank you!', 'tablepress' ), 'https://tablepress.org/donate/' )
91 . '</p>'
92 . '<div style="margin:20px 0;height:45px"><a href="https://wpactivitylog.com/?utm_source=tablepress&utm_medium=referral&utm_campaign=WSAL" target="_blank" rel="noopener"><img src="' . plugins_url( 'admin/img/wsal-mark.png', TABLEPRESS__FILE__ ) . '" alt="' . sprintf( esc_attr_x( 'This release of TablePress is supported by %s, the most comprehensive WordPress activity logs plugin.', 'WP Activity Log', 'tablepress' ), 'WP Activity Log' ) . '" style="width:46px;height:45px;float:left;margin-right:10px" /></a>'
93 . '<div style="font-size:14px;font-weight:bold;max-width:530px;padding:5px 0;line-height:normal">' . sprintf( _x( 'This release of TablePress is supported by %s, the most comprehensive WordPress activity logs plugin.', 'WP Activity Log', 'tablepress' ), '<a href="https://wpactivitylog.com/?utm_source=tablepress&utm_medium=referral&utm_campaign=WSAL" target="_blank" rel="noopener">WP Activity Log</a>' ) . '</div></div>'
94 . '<p>'
95 . $this->ajax_link( array( 'action' => 'hide_message', 'item' => 'plugin_update', 'return' => 'list' ), __( 'Hide this message', 'tablepress' ) ),
96 'notice-info not-dismissible',
97 '<em>' . sprintf( __( 'Thank you for updating to TablePress %s!', 'tablepress' ), TablePress::version ) . '</em>'
98 );
99 }
100
101 $this->process_action_messages( array(
102 'success_delete' => _n( 'The table was deleted successfully.', 'The tables were deleted successfully.', 1, 'tablepress' ),
103 'success_delete_plural' => _n( 'The table was deleted successfully.', 'The tables were deleted successfully.', 2, 'tablepress' ),
104 'error_delete' => __( 'Error: The table could not be deleted.', 'tablepress' ),
105 'error_save' => __( 'Error: The table could not be saved.', 'tablepress' ),
106 'success_copy' => _n( 'The table was copied successfully.', 'The tables were copied successfully.', 1, 'tablepress' ) . ( ( false !== $data['table_id'] ) ? ' ' . sprintf( __( 'The copied table has the table ID &#8220;%s&#8221;.', 'tablepress' ), esc_html( $data['table_id'] ) ) : '' ),
107 'success_copy_plural' => _n( 'The table was copied successfully.', 'The tables were copied successfully.', 2, 'tablepress' ),
108 'error_copy' => __( 'Error: The table could not be copied.', 'tablepress' ),
109 'error_no_table' => __( 'Error: You did not specify a valid table ID.', 'tablepress' ),
110 'error_load_table' => __( 'Error: This table could not be loaded!', 'tablepress' ),
111 'error_bulk_action_invalid' => __( 'Error: This bulk action is invalid!', 'tablepress' ),
112 'error_no_selection' => __( 'Error: You did not select any tables!', 'tablepress' ),
113 'error_delete_not_all_tables' => __( 'Notice: Not all selected tables could be deleted!', 'tablepress' ),
114 'error_copy_not_all_tables' => __( 'Notice: Not all selected tables could be copied!', 'tablepress' ),
115 'success_import' => __( 'The tables were imported successfully.', 'tablepress' ),
116 ) );
117
118 $this->add_text_box( 'head', array( $this, 'textbox_head' ), 'normal' );
119 $this->add_text_box( 'tables-list', array( $this, 'textbox_tables_list' ), 'normal' );
120
121 add_screen_option( 'per_page', array( 'label' => __( 'Tables', 'tablepress' ), 'default' => 20 ) ); // Admin_Controller contains function to allow changes to this in the Screen Options to be saved
122 $this->wp_list_table = new TablePress_All_Tables_List_Table();
123 $this->wp_list_table->set_items( $this->data['table_ids'] );
124 $this->wp_list_table->prepare_items();
125
126 // Cleanup Request URI string, which WP_List_Table uses to generate the sort URLs.
127 $_SERVER['REQUEST_URI'] = remove_query_arg( array( 'message', 'table_id' ), $_SERVER['REQUEST_URI'] );
128 }
129
130 /**
131 * Render the current view (in this view: without form tag).
132 *
133 * @since 1.0.0
134 */
135 public function render() {
136 ?>
137 <div id="tablepress-page" class="wrap">
138 <?php
139 $this->print_nav_tab_menu();
140 // Print all header messages.
141 foreach ( $this->header_messages as $message ) {
142 echo $message;
143 }
144
145 // For this screen, this is done in textbox_tables_list(), to get the fields into the correct <form>:
146 // $this->do_text_boxes( 'header' );
147 ?>
148 <div id="poststuff">
149 <div id="post-body" class="metabox-holder columns-<?php echo ( isset( $GLOBALS['screen_layout_columns'] ) && ( 2 === $GLOBALS['screen_layout_columns'] ) ) ? '2' : '1'; ?>">
150 <div id="postbox-container-2" class="postbox-container">
151 <?php
152 $this->do_text_boxes( 'normal' );
153 $this->do_meta_boxes( 'normal' );
154
155 $this->do_text_boxes( 'additional' );
156 $this->do_meta_boxes( 'additional' );
157
158 // Print all submit buttons.
159 $this->do_text_boxes( 'submit' );
160 ?>
161 </div>
162 <div id="postbox-container-1" class="postbox-container">
163 <?php
164 // Print all boxes in the sidebar.
165 $this->do_text_boxes( 'side' );
166 $this->do_meta_boxes( 'side' );
167 ?>
168 </div>
169 </div>
170 <br class="clear" />
171 </div>
172 </div>
173 <?php
174 }
175
176 /**
177 * Print the screen head text.
178 *
179 * @since 1.0.0
180 *
181 * @param array $data Data for this screen.
182 * @param array $box Information about the text box.
183 */
184 public function textbox_head( array $data, array $box ) {
185 ?>
186 <p>
187 <?php _e( 'This is a list of your tables.', 'tablepress' ); ?>
188 <?php printf( __( 'To insert a table into a post or page, copy its Shortcode %s and paste it into a &#8220;Shortcode&#8221; block at the desired place in the block editor.', 'tablepress' ), '<label class="screen-reader-text" for="table-shortcode-inline">' . esc_html__( 'Shortcode text for editor', 'tablepress' ) . '</label>' . '<input type="text" class="table-shortcode table-shortcode-inline" id="table-shortcode-inline" value="' . esc_attr( '[' . TablePress::$shortcode . ' id=<ID> /]' ) . '" readonly="readonly" />' ); ?>
189 <?php _e( 'Each table has a unique ID that needs to be adjusted in that Shortcode.', 'tablepress' ); ?>
190 </p>
191 <?php
192 }
193
194 /**
195 * Print the content of the "All Tables" text box.
196 *
197 * @since 1.0.0
198 *
199 * @param array $data Data for this screen.
200 * @param array $box Information about the text box.
201 */
202 public function textbox_tables_list( array $data, array $box ) {
203 if ( ! empty( $_GET['s'] ) ) {
204 printf( '<span class="subtitle">' . __( 'Search results for &#8220;%s&#8221;', 'tablepress' ) . '</span>', esc_html( wp_unslash( $_GET['s'] ) ) );
205 }
206 ?>
207 <form method="get" action="">
208 <?php
209 if ( isset( $_GET['page'] ) ) {
210 echo '<input type="hidden" name="page" value="' . esc_attr( $_GET['page'] ) . '" />' . "\n";
211 }
212 $this->wp_list_table->search_box( __( 'Search Tables', 'tablepress' ), 'tables_search' );
213 ?>
214 </form>
215 <form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
216 <?php
217 // This prints the nonce and action fields for this screen (done here instead of render(), due to moved <form>).
218 $this->do_text_boxes( 'header' );
219 $this->wp_list_table->display();
220 ?>
221 </form>
222 <?php
223 }
224
225 /**
226 * Create HTML code for an AJAXified link.
227 *
228 * @since 1.0.0
229 *
230 * @param array $params Parameters for the URL.
231 * @param string $text Text for the link.
232 * @return string HTML code for the link.
233 */
234 protected function ajax_link( array $params, $text ) {
235 $class = 'ajax-link';
236 if ( ! empty( $params['class'] ) ) {
237 $class .= ' ' . esc_attr( $params['class'] );
238 }
239 $url = TablePress::url( $params, true, 'admin-post.php' );
240 $action = esc_attr( $params['action'] );
241 $item = esc_attr( $params['item'] );
242 $target = isset( $params['target'] ) ? esc_attr( $params['target'] ) : '';
243 return "<a class=\"{$class}\" href=\"{$url}\" data-action=\"{$action}\" data-item=\"{$item}\" data-target=\"{$target}\">{$text}</a>";
244 }
245
246 } // class TablePress_List_View
247
248 /**
249 * TablePress All Tables List Table Class
250 * @package TablePress
251 * @subpackage Views
252 * @author Tobias Bäthge
253 * @link https://codex.wordpress.org/Class_Reference/WP_List_Table
254 * @since 1.0.0
255 */
256 class TablePress_All_Tables_List_Table extends WP_List_Table {
257
258 /**
259 * Number of items of the initial data set (before sort, search, and pagination).
260 *
261 * @since 1.0.0
262 * @var int
263 */
264 protected $items_count = 0;
265
266 /**
267 * Initialize the List Table.
268 *
269 * @since 1.0.0
270 */
271 public function __construct() {
272 $screen = get_current_screen();
273
274 // Hide "Last Modified By" column by default.
275 if ( false === get_user_option( 'manage' . $screen->id . 'columnshidden' ) ) {
276 update_user_option( get_current_user_id(), 'manage' . $screen->id . 'columnshidden', array( 'table_last_modified_by' ), true );
277 }
278
279 parent::__construct( array(
280 'singular' => 'tablepress-table', // Singular name of the listed records.
281 'plural' => 'tablepress-all-tables', // Plural name of the listed records.
282 'ajax' => false, // Does this list table support AJAX?
283 'screen' => $screen, // WP_Screen object.
284 ) );
285 }
286
287 /**
288 * Set the data items (here: tables) that are to be displayed by the List Tables, and their original count.
289 *
290 * @since 1.0.0
291 *
292 * @param array $items Tables to be displayed in the List Table.
293 */
294 public function set_items( array $items ) {
295 $this->items = $items;
296 $this->items_count = count( $items );
297 }
298
299 /**
300 * Check whether the user has permissions for certain AJAX actions.
301 * (not used, but must be implemented in this child class)
302 *
303 * @since 1.0.0
304 *
305 * @return bool true (Default value).
306 */
307 public function ajax_user_can() {
308 return true;
309 }
310
311 /**
312 * Get a list of columns in this List Table.
313 *
314 * Format: 'internal-name' => 'Column Title'.
315 *
316 * @since 1.0.0
317 *
318 * @return array List of columns in this List Table.
319 */
320 public function get_columns() {
321 $columns = array(
322 'cb' => $this->has_items() ? '<input type="checkbox" />' : '', // Checkbox for "Select all", but only if there are items in the table.
323 // "name" is special in WP, which is why we prefix every entry here, to be safe!
324 'table_id' => __( 'ID', 'tablepress' ),
325 'table_name' => __( 'Table Name', 'tablepress' ),
326 'table_description' => __( 'Description', 'tablepress' ),
327 'table_author' => __( 'Author', 'tablepress' ),
328 'table_last_modified_by' => __( 'Last Modified By', 'tablepress' ),
329 'table_last_modified' => __( 'Last Modified', 'tablepress' ),
330 );
331 return $columns;
332 }
333
334 /**
335 * Get a list of columns that are sortable.
336 *
337 * Format: 'internal-name' => array( $field for $item[ $field ], true for already sorted ).
338 *
339 * @since 1.0.0
340 *
341 * @return array List of sortable columns in this List Table.
342 */
343 protected function get_sortable_columns() {
344 // No sorting on the Empty List placeholder.
345 if ( ! $this->has_items() ) {
346 return array();
347 }
348
349 $sortable_columns = array(
350 'table_id' => array( 'id', true ), // true means its already sorted
351 'table_name' => array( 'name', false ),
352 'table_description' => array( 'description', false ),
353 'table_author' => array( 'author', false ),
354 'table_last_modified_by' => array( 'last_modified_by', false ),
355 'table_last_modified' => array( 'last_modified', false ),
356 );
357 return $sortable_columns;
358 }
359
360 /**
361 * Gets the name of the default primary column.
362 *
363 * @since 1.7.0
364 *
365 * @return string Name of the default primary column, in this case, the table name.
366 */
367 protected function get_default_primary_column_name() {
368 return 'table_name';
369 }
370
371 /**
372 * Render a cell in the "cb" column.
373 *
374 * @since 1.0.0
375 *
376 * @param array $item Data item for the current row.
377 * @return string HTML content of the cell.
378 */
379 protected function column_cb( /* array */ $item ) {
380 // Don't use `array` type hint in method declaration to prevent a Strict Standards notice, as the method is inherited.
381 $user_can_copy_table = current_user_can( 'tablepress_copy_table', $item['id'] );
382 $user_can_delete_table = current_user_can( 'tablepress_delete_table', $item['id'] );
383 $user_can_export_table = current_user_can( 'tablepress_export_table', $item['id'] );
384
385 if ( $user_can_copy_table || $user_can_delete_table || $user_can_export_table ) {
386 return sprintf(
387 '<label><span class="screen-reader-text">%1$s</span><input type="checkbox" name="table[]" value="%2$s" /></label>',
388 esc_html__( 'Bulk action selector', 'tablepress' ),
389 esc_attr( $item['id'] )
390 );
391 } else {
392 return '';
393 }
394 }
395
396 /**
397 * Render a cell in the "table_id" column.
398 *
399 * @since 1.0.0
400 *
401 * @param array $item Data item for the current row.
402 * @return string HTML content of the cell.
403 */
404 protected function column_table_id( array $item ) {
405 return esc_html( $item['id'] );
406 }
407
408 /**
409 * Render a cell in the "table_name" column.
410 *
411 * @since 1.0.0
412 *
413 * @param array $item Data item for the current row.
414 * @return string HTML content of the cell.
415 */
416 protected function column_table_name( array $item ) {
417 $user_can_edit_table = current_user_can( 'tablepress_edit_table', $item['id'] );
418 $user_can_copy_table = current_user_can( 'tablepress_copy_table', $item['id'] );
419 $user_can_export_table = current_user_can( 'tablepress_export_table', $item['id'] );
420 $user_can_delete_table = current_user_can( 'tablepress_delete_table', $item['id'] );
421 $user_can_preview_table = current_user_can( 'tablepress_preview_table', $item['id'] );
422
423 $edit_url = TablePress::url( array( 'action' => 'edit', 'table_id' => $item['id'] ) );
424 $copy_url = TablePress::url( array( 'action' => 'copy_table', 'item' => $item['id'], 'return' => 'list', 'return_item' => $item['id'] ), true, 'admin-post.php' );
425 $export_url = TablePress::url( array( 'action' => 'export', 'table_id' => $item['id'] ) );
426 $delete_url = TablePress::url( array( 'action' => 'delete_table', 'item' => $item['id'], 'return' => 'list', 'return_item' => $item['id'] ), true, 'admin-post.php' );
427 $preview_url = TablePress::url( array( 'action' => 'preview_table', 'item' => $item['id'], 'return' => 'list', 'return_item' => $item['id'] ), true, 'admin-post.php' );
428
429 if ( '' === trim( $item['name'] ) ) {
430 $item['name'] = __( '(no name)', 'tablepress' );
431 }
432
433 if ( $user_can_edit_table ) {
434 $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>';
435 } else {
436 $row_text = '<strong>' . esc_html( $item['name'] ) . '</strong>';
437 }
438
439 $row_actions = array();
440 if ( $user_can_edit_table ) {
441 $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' ) );
442 }
443 $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' ) );
444 if ( $user_can_copy_table ) {
445 $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' ) );
446 }
447 if ( $user_can_export_table ) {
448 $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' ) );
449 }
450 if ( $user_can_delete_table ) {
451 $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' ) );
452 }
453 if ( $user_can_preview_table ) {
454 $row_actions['table-preview'] = sprintf( '<a href="%1$s" title="%2$s">%3$s</a>', $preview_url, esc_attr( sprintf( __( 'Show a preview of &#8220;%s&#8221;', 'tablepress' ), $item['name'] ) ), __( 'Preview', 'tablepress' ) );
455 }
456
457 return $row_text . $this->row_actions( $row_actions );
458 }
459
460 /**
461 * Render a cell in the "table_description" column.
462 *
463 * @since 1.0.0
464 *
465 * @param array $item Data item for the current row.
466 * @return string HTML content of the cell.
467 */
468 protected function column_table_description( array $item ) {
469 if ( '' === trim( $item['description'] ) ) {
470 $item['description'] = __( '(no description)', 'tablepress' );
471 }
472 return esc_html( $item['description'] );
473 }
474
475 /**
476 * Render a cell in the "table_author" column.
477 *
478 * @since 1.0.0
479 *
480 * @param array $item Data item for the current row.
481 * @return string HTML content of the cell.
482 */
483 protected function column_table_author( array $item ) {
484 return TablePress::get_user_display_name( $item['author'] );
485 }
486
487 /**
488 * Render a cell in the "last_modified_by" column.
489 *
490 * @since 1.0.0
491 *
492 * @param array $item Data item for the current row.
493 * @return string HTML content of the cell.
494 */
495 protected function column_table_last_modified_by( array $item ) {
496 return TablePress::get_user_display_name( $item['options']['last_editor'] );
497 }
498
499 /**
500 * Render a cell in the "table_last_modified" column.
501 *
502 * @since 1.0.0
503 *
504 * @param array $item Data item for the current row.
505 * @return string HTML content of the cell.
506 */
507 protected function column_table_last_modified( array $item ) {
508 $modified_timestamp = date_create( $item['last_modified'], wp_timezone() );
509 $modified_timestamp = $modified_timestamp->getTimestamp();
510 $current_timestamp = time();
511 $time_diff = $current_timestamp - $modified_timestamp;
512 // Time difference is only shown up to one week.
513 if ( $time_diff >= 0 && $time_diff < WEEK_IN_SECONDS ) {
514 $time_diff = sprintf( __( '%s ago', 'default' ), human_time_diff( $modified_timestamp, $current_timestamp ) );
515 } else {
516 $time_diff = TablePress::format_datetime( $item['last_modified'], '<br />' );
517 }
518 $readable_time = TablePress::format_datetime( $item['last_modified'] );
519 return '<abbr title="' . esc_attr( $readable_time ) . '">' . $time_diff . '</abbr>';
520 }
521
522 /**
523 * Handles output for the default column.
524 *
525 * @since 1.8.0
526 *
527 * @param array $item Data item for the current row.
528 * @param string $column_name Current column name.
529 */
530 protected function column_default( /* array */ $item, $column_name ) {
531 // Don't use `array` type hint in method declaration to prevent a Strict Standards notice, as the method is inherited.
532 /**
533 * Fires inside each custom column of the TablePress list table.
534 *
535 * @since 1.8.0
536 *
537 * @param array $column_name Current column name.
538 * @param string $item Data item for the current row.
539 */
540 do_action( 'manage_tablepress_list_custom_column', $column_name, $item );
541 }
542
543 /**
544 * Get a list (name => title) bulk actions that are available.
545 *
546 * @since 1.0.0
547 *
548 * @return array Bulk actions for this table.
549 */
550 protected function get_bulk_actions() {
551 $bulk_actions = array();
552
553 if ( current_user_can( 'tablepress_copy_tables' ) ) {
554 $bulk_actions['copy'] = _x( 'Copy', 'bulk action', 'tablepress' );
555 }
556 if ( current_user_can( 'tablepress_export_tables' ) ) {
557 $bulk_actions['export'] = _x( 'Export', 'bulk action', 'tablepress' );
558 }
559 if ( current_user_can( 'tablepress_delete_tables' ) ) {
560 $bulk_actions['delete'] = _x( 'Delete', 'bulk action', 'tablepress' );
561 }
562
563 return $bulk_actions;
564 }
565
566 /**
567 * Render the bulk actions dropdown.
568 *
569 * In comparison with parent class, this has modified HTML (especially no field named "action" as that's being used already)!
570 *
571 * @since 1.0.0
572 *
573 * @param string $which The location of the bulk actions: 'top' or 'bottom'.
574 * This is designated as optional for backwards-compatibility.
575 */
576 protected function bulk_actions( $which = '' ) {
577 if ( is_null( $this->_actions ) ) {
578 $this->_actions = $this->get_bulk_actions();
579 $no_new_actions = $this->_actions;
580 /** This filter is documented in the WordPress function WP_List_Table::bulk_actions() in wp-admin/includes/class-wp-list-table.php */
581 $this->_actions = apply_filters( 'bulk_actions-' . $this->screen->id, $this->_actions ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
582 $this->_actions = array_intersect_assoc( $this->_actions, $no_new_actions );
583 $two = '';
584 } else {
585 $two = '2';
586 }
587
588 if ( empty( $this->_actions ) ) {
589 return;
590 }
591
592 $name_id = "bulk-action-selector-{$which}";
593 echo "<label for='{$name_id}' class='screen-reader-text'>" . __( 'Select Bulk Action', 'tablepress' ) . "</label>\n";
594 echo "<select name='{$name_id}' id='{$name_id}'>\n";
595 echo "<option value='-1' selected='selected'>" . __( 'Bulk Actions', 'tablepress' ) . "</option>\n";
596 foreach ( $this->_actions as $name => $title ) {
597 echo "\t<option value='{$name}'>{$title}</option>\n";
598 }
599 echo "</select>\n";
600 submit_button( __( 'Apply', 'tablepress' ), 'action', '', false, array( 'id' => "doaction{$two}" ) );
601 echo "\n";
602 }
603
604 /**
605 * Holds the message to be displayed when there are no items in the table.
606 *
607 * @since 1.0.0
608 */
609 public function no_items() {
610 _e( 'No tables found.', 'tablepress' );
611 if ( 0 === $this->items_count ) {
612 $user_can_add_tables = current_user_can( 'tablepress_add_tables' );
613 $user_can_import_tables = current_user_can( 'tablepress_import_tables' );
614
615 $add_url = TablePress::url( array( 'action' => 'add' ) );
616 $import_url = TablePress::url( array( 'action' => 'import' ) );
617
618 if ( $user_can_add_tables && $user_can_import_tables ) {
619 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 );
620 } elseif ( $user_can_add_tables ) {
621 echo ' ' . sprintf( __( 'You should <a href="%s">add</a> a table to get started!', 'tablepress' ), $add_url );
622 } elseif ( $user_can_import_tables ) {
623 echo ' ' . sprintf( __( 'You should <a href="%s">import</a> a table to get started!', 'tablepress' ), $import_url );
624 }
625 }
626 }
627
628 /**
629 * Generate the elements above or below the table (like bulk actions and pagination).
630 *
631 * In comparison with parent class, this has modified HTML (no nonce field), and a check whether there are items.
632 *
633 * @since 1.0.0
634 *
635 * @param string $which Location ("top" or "bottom").
636 */
637 protected function display_tablenav( $which ) {
638 if ( ! $this->has_items() ) {
639 return;
640 }
641 ?>
642 <div class="tablenav <?php echo esc_attr( $which ); ?>">
643 <div class="alignleft actions">
644 <?php $this->bulk_actions( $which ); ?>
645 </div>
646 <?php
647 $this->extra_tablenav( $which );
648 $this->pagination( $which );
649 ?>
650 <br class="clear" />
651 </div>
652 <?php
653 }
654
655 /**
656 * Callback to determine whether the given $item contains the search term.
657 *
658 * @since 1.0.0
659 *
660 * @param string $item Table ID that shall be searched.
661 * @return bool Whether the search term was found or not.
662 */
663 protected function _search_callback( $item ) {
664 static $term, $json_encoded_term;
665 if ( is_null( $term ) || is_null( $json_encoded_term ) ) {
666 $term = wp_unslash( $_GET['s'] );
667 $json_encoded_term = substr( wp_json_encode( $term, TABLEPRESS_JSON_OPTIONS ), 1, -1 );
668 }
669
670 static $debug;
671 if ( is_null( $debug ) ) {
672 // Set debug variable to allow searching in corrupted tables.
673 $debug = isset( $_GET['debug'] ) ? ( 'true' === $_GET['debug'] ) : WP_DEBUG;
674 }
675
676 // load table again, with data and options (for last_editor).
677 $item = TablePress::$model_table->load( $item, true, true );
678
679 // Don't search corrupted tables, except when debug mode is enabled via $_GET parameter or WP_DEBUG constant.
680 if ( ! $debug && isset( $item['is_corrupted'] ) && $item['is_corrupted'] ) {
681 return false;
682 }
683
684 // Search from easy to hard, so that "expensive" code maybe doesn't have to run.
685 if ( false !== stripos( $item['id'], $term )
686 || false !== stripos( $item['name'], $term )
687 || false !== stripos( $item['description'], $term )
688 || false !== stripos( TablePress::get_user_display_name( $item['author'] ), $term )
689 || false !== stripos( TablePress::get_user_display_name( $item['options']['last_editor'] ), $term )
690 || false !== stripos( TablePress::format_datetime( $item['last_modified'] ), $term )
691 || false !== stripos( wp_json_encode( $item['data'], TABLEPRESS_JSON_OPTIONS ), $json_encoded_term ) ) {
692 return true;
693 }
694
695 return false;
696 }
697
698 /**
699 * Callback to for the array sort function.
700 *
701 * @since 1.0.0
702 *
703 * @param array $item_a First item that shall be compared to.
704 * @param array $item_b The second item for the comparison.
705 * @return int (-1, 0, 1) depending on which item sorts "higher".
706 */
707 protected function _order_callback( array $item_a, array $item_b ) {
708 global $orderby, $order;
709
710 if ( 'last_modified_by' !== $orderby ) {
711 if ( $item_a[ $orderby ] === $item_b[ $orderby ] ) {
712 return 0;
713 }
714 } else {
715 if ( $item_a['options']['last_editor'] === $item_b['options']['last_editor'] ) {
716 return 0;
717 }
718 }
719
720 // Certain fields require some extra work before being sortable.
721 switch ( $orderby ) {
722 case 'last_modified':
723 // Compare UNIX timestamps for "last modified", which actually is a mySQL datetime string.
724 $result = ( strtotime( $item_a['last_modified'] ) > strtotime( $item_b['last_modified'] ) ) ? 1 : -1;
725 break;
726 case 'author':
727 // Get the actual author name, plain value is just the user ID.
728 $result = strnatcasecmp( TablePress::get_user_display_name( $item_a['author'] ), TablePress::get_user_display_name( $item_b['author'] ) );
729 break;
730 case 'last_modified_by':
731 // Get the actual last editor name, plain value is just the user ID.
732 $result = strnatcasecmp( TablePress::get_user_display_name( $item_a['options']['last_editor'] ), TablePress::get_user_display_name( $item_b['options']['last_editor'] ) );
733 break;
734 default:
735 // Other fields (ID, name, description) are sorted as strings.
736 $result = strnatcasecmp( $item_a[ $orderby ], $item_b[ $orderby ] );
737 }
738
739 return ( 'asc' === $order ) ? $result : - $result;
740 }
741
742 /**
743 * Prepares the list of items for displaying, by maybe searching and sorting, and by doing pagination.
744 *
745 * @since 1.0.0
746 */
747 public function prepare_items() {
748 global $orderby, $order, $s;
749 wp_reset_vars( array( 'orderby', 'order', 's' ) );
750
751 // Maybe search in the items.
752 if ( $s ) {
753 $this->items = array_filter( $this->items, array( $this, '_search_callback' ) );
754 }
755
756 // Load actual tables after search for less memory consumption.
757 foreach ( $this->items as &$item ) {
758 // Don't load data, but load table options for access to last_editor.
759 $item = TablePress::$model_table->load( $item, false, true );
760 }
761 // Break reference in foreach iterator.
762 unset( $item );
763
764 // Maybe sort the items.
765 $_sortable_columns = $this->get_sortable_columns();
766 if ( $orderby && ! empty( $this->items ) && isset( $_sortable_columns[ "table_{$orderby}" ] ) ) {
767 usort( $this->items, array( $this, '_order_callback' ) );
768 }
769
770 // Number of records to show per page.
771 $per_page = $this->get_items_per_page( 'tablepress_list_per_page', 20 ); // hard-coded, as in filter in Admin_Controller
772 // Page number the user is currently viewing.
773 $current_page = $this->get_pagenum();
774 // Number of records in the array.
775 $total_items = count( $this->items );
776
777 // Slice items array to hold only items for the current page.
778 $this->items = array_slice( $this->items, ( ( $current_page - 1 ) * $per_page ), $per_page );
779
780 // Register pagination options and calculation results.
781 $this->set_pagination_args( array(
782 'total_items' => $total_items, // Total number of records/items
783 'per_page' => $per_page, // Number of items per page
784 'total_pages' => ceil( $total_items / $per_page ), // Total number of pages
785 ) );
786 }
787
788 } // class TablePress_All_Tables_List_Table
789