PluginProbe
AutomatorWP – No-Code Workflow Automation, Integration & Webhooks Plugin, now with AI / 6.0.3
AutomatorWP – No-Code Workflow Automation, Integration & Webhooks Plugin, now with AI v6.0.3
6.0.3 6.0.2 6.0.1 6.0.0 5.8.6 5.8.5 5.8.4 5.8.3 5.8.2 5.8.1 5.8.0 5.7.9.2 5.7.9.1 5.7.8 5.7.9 5.7.6 5.7.7 5.7.5 5.7.4 5.7.3 5.7.2 5.7.1 trunk 5.6.0 5.6.1 All 34 releases
← All changes | libraries/ct/includes/class-ct-list-table.php +468 -0 5.7.3 → 6.0.3 View file →
@@ -1,0 +1,468 @@
1 +<?php
2 +/**
3 + * List Table class
4 + *
5 + * Based on WP_Posts_List_Table class
6 + *
7 + * @author GamiPress <[email protected]>, Ruben Garcia <[email protected]>
8 + *
9 + * @since 1.0.0
10 + */
11 +// Exit if accessed directly
12 +defined( 'ABSPATH' ) || exit;
13 +
14 +if ( ! class_exists( 'CT_List_Table' ) ) :
15 +
16 + class CT_List_Table extends WP_List_Table {
17 +
18 + /**
19 + * Get things started
20 + *
21 + * @access public
22 + * @since 1.0.0
23 + *
24 + * @param array $args Optional. Arbitrary display and query arguments to pass through
25 + * the list table. Default empty array.
26 + */
27 + public function __construct( $args = array() ) {
28 + global $ct_table;
29 +
30 + parent::__construct( array(
31 + 'singular' => $ct_table->labels->singular_name,
32 + 'plural' => $ct_table->labels->plural_name,
33 + 'screen' => convert_to_screen( $ct_table->labels->plural_name )
34 + ) );
35 + }
36 +
37 + /**
38 + * Show the search field
39 + *
40 + * @since 1.0.0
41 + *
42 + * @param string $text Label for the search box
43 + * @param string $input_id ID of the search box
44 + *
45 + * @return void
46 + */
47 + public function search_box( $text, $input_id ) {
48 + if ( empty( $_REQUEST['s'] ) && !$this->has_items() )
49 + return;
50 +
51 + $input_id = $input_id . '-search-input';
52 +
53 + if ( ! empty( $_REQUEST['orderby'] ) ) {
54 + if ( is_array( $_REQUEST['orderby'] ) ) {
55 + foreach ( $_REQUEST['orderby'] as $key => $value ) {
56 + echo '<input type="hidden" name="orderby[' . esc_attr( sanitize_text_field( wp_unslash( $key ) ) ) . ']" value="' . esc_attr( sanitize_text_field( wp_unslash( $value ) ) ) . '" />';
57 + }
58 + } else {
59 + echo '<input type="hidden" name="orderby" value="' . esc_attr( sanitize_text_field( wp_unslash( $_REQUEST['orderby'] ) ) ) . '" />';
60 + }
61 + }
62 +
63 + if ( ! empty( $_REQUEST['order'] ) ) {
64 + echo '<input type="hidden" name="order" value="' . esc_attr( sanitize_text_field( wp_unslash( $_REQUEST['order'] ) ) ) . '" />';
65 + }
66 + ?>
67 + <p class="search-box">
68 + <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>"><?php echo $text; ?>:</label>
69 + <input type="search" id="<?php echo esc_attr( $input_id ); ?>" name="s" value="<?php _admin_search_query(); ?>" />
70 + <?php submit_button( $text, 'button', false, false, array( 'id' => 'search-submit' ) ); ?>
71 + </p>
72 + <?php
73 + }
74 +
75 + /**
76 + * Retrieve the view types
77 + *
78 + * @access public
79 + * @since 1.0.0
80 + *
81 + * @return array $views All the views available
82 + */
83 + public function get_views() {
84 +
85 + global $wpdb, $ct_table;
86 +
87 + /**
88 + * Utility filter to generate views based on a given field
89 + *
90 + * @since 1.0.0
91 + *
92 + * @param string $field_id The field id to generate the views
93 + *
94 + * @return string
95 + */
96 + $field_id = apply_filters( "ct_list_{$ct_table->name}_views_field", '' );
97 +
98 + /**
99 + * Labels for the filed id
100 + *
101 + * @since 1.0.0
102 + *
103 + * @param array $field_labels Field labels in format array( 'field_value' => 'Field Label' )
104 + * Field values that are not listed here won't get displayed
105 + *
106 + * @return array
107 + */
108 + $field_labels = apply_filters( "ct_list_{$ct_table->name}_views_field_labels", array() );
109 +
110 + $views = array();
111 +
112 + // Check if field ID and labels has been passed and also is field is registered on the table (not as meta)
113 + if( ! empty( $field_id ) && ! empty( $field_labels ) && isset( $ct_table->db->schema->fields[$field_id] ) ) {
114 +
115 + // Get the number of entries per each different field value
116 + $results = $wpdb->get_results( "SELECT {$field_id}, COUNT( * ) AS num_entries FROM {$ct_table->db->table_name} GROUP BY {$field_id}", ARRAY_A );
117 + $counts = array();
118 +
119 + // Loop them to build the counts array
120 + foreach( $results as $result ) {
121 + $counts[$result[$field_id]] = absint( $result['num_entries'] );
122 + }
123 +
124 + $list_link = ct_get_list_link( $ct_table->name );
125 + $list_link = add_query_arg( '_ctviewnonce', wp_create_nonce( 'ct_views_filter' ), $list_link );
126 + $current = '';
127 +
128 + if( isset( $_GET['_ctviewnonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash ( $_GET['_ctviewnonce'] ) ), 'ct_views_filter' ) ) {
129 + $current = isset( $_GET[$field_id] ) ? sanitize_text_field( wp_unslash( $_GET[$field_id] ) ) : '';
130 + }
131 +
132 + // Setup the 'All' view
133 + $all_count = absint( $wpdb->get_var( "SELECT COUNT( * ) FROM {$ct_table->db->table_name}" ) );
134 + $views['all'] = '<a href="' . esc_attr( $list_link ) . '" class="' . ( empty( $current ) ? 'current' : '' ) . '">' . esc_html__( 'All', 'ct' ) . ' <span class="count">(' . $all_count . ')</span></a>';
135 +
136 + foreach( $counts as $value => $count ) {
137 +
138 + // Skip fields that are not intended to being displayed
139 + if( ! isset( $field_labels[$value] ) ) {
140 + continue;
141 + }
142 +
143 + $label = $field_labels[$value];
144 + $url = $list_link . '&' . $field_id . '=' . $value;
145 +
146 + $views[$value] = '<a href="' . esc_attr( $url ) . '" class="' . ( $current === $value ? 'current' : '' ) . '">' . $label . ' <span class="count">(' . $count . ')</span>' . '</a>';
147 + }
148 +
149 + }
150 +
151 + /**
152 + * Available filter to past custom views
153 + *
154 + * @since 1.0.0
155 + *
156 + * @param array $views An array of views links.
157 + * Array format: array( 'link_id' => 'link' )
158 + * Link format: '<a href="#">{label} <span class="count">({count})</span></a>'
159 + */
160 + $views = apply_filters( "{$ct_table->name}_get_views", $views );
161 +
162 + return $views;
163 + }
164 +
165 + /**
166 + *
167 + * @return array
168 + */
169 + protected function get_bulk_actions() {
170 +
171 + global $ct_table;
172 +
173 + $actions = array();
174 +
175 + if ( current_user_can( $ct_table->cap->delete_items ) ) {
176 + $actions['delete'] = __( 'Delete Permanently' );
177 + }
178 +
179 + $actions = apply_filters( "{$ct_table->name}_bulk_actions", $actions );
180 +
181 + return $actions;
182 + }
183 +
184 + /**
185 + * Displays extra controls between bulk actions and pagination.
186 + *
187 + * @since 1.0.0
188 + *
189 + * @param string $which
190 + */
191 + protected function extra_tablenav( $which ) {
192 +
193 + global $ct_table;
194 +
195 + /**
196 + * Extra table nav
197 + *
198 + * @since 1.0.0
199 + *
200 + * @param string $which The location of the extra table nav markup: 'top' or 'bottom'.
201 + */
202 + do_action( "ct_manage_{$ct_table->name}_extra_tablenav", $which );
203 + // Backward compatibility
204 + do_action( "manage_{$ct_table->name}_extra_tablenav", $which );
205 +
206 + }
207 +
208 + /**
209 + *
210 + * @return array
211 + */
212 + protected function get_table_classes() {
213 + global $ct_table;
214 +
215 + return array( 'widefat', 'fixed', 'striped', $ct_table->name );
216 + }
217 +
218 + /**
219 + * Retrieve the table columns
220 + *
221 + * @access public
222 + * @since 1.0.0
223 + * @return array $columns Array of all the list table columns
224 + */
225 + public function get_columns() {
226 + global $ct_table;
227 +
228 + $columns = array();
229 + $bulk_actions = $this->get_bulk_actions();
230 +
231 + if( ! empty( $bulk_actions ) ) {
232 + $columns['cb'] = '<input type="checkbox" />';
233 + }
234 +
235 + /**
236 + * Filters the columns displayed in the list table of a specific CT table.
237 + *
238 + * @since 1.0.0
239 + *
240 + * @param array $posts_columns An array of column names.
241 + * @param CT_Table $ct_table The table object.
242 + */
243 + // Backward Compatibility
244 + $columns = apply_filters( "manage_{$ct_table->name}_columns", $columns, $ct_table );
245 + return apply_filters( "ct_manage_{$ct_table->name}_columns", $columns, $ct_table );
246 + }
247 +
248 + /**
249 + * Retrieve the table's sortable columns
250 + *
251 + * @access public
252 + * @since 1.0.0
253 + * @return array Array of all the sortable columns
254 + */
255 + public function get_sortable_columns() {
256 + global $ct_table;
257 +
258 + $sortable_columns = array();
259 +
260 + /**
261 + * Filters the sortable columns in the list table of a specific CT table.
262 + *
263 + * Format:
264 + * 'internal-name' => 'orderby'
265 + * or
266 + * 'internal-name' => array( 'orderby', true )
267 + * The second format will make the initial sorting order be descending
268 + *
269 + * @since 1.0.0
270 + *
271 + * @param array $sortable_columns An array of column names.
272 + * @param CT_Table $ct_table The table object.
273 + */
274 + // Backward Compatibility
275 + $sortable_columns = apply_filters( "manage_{$ct_table->name}_sortable_columns", $sortable_columns, $ct_table );
276 + return apply_filters( "ct_manage_{$ct_table->name}_sortable_columns", $sortable_columns, $ct_table );
277 + }
278 +
279 + /**
280 + * This function renders most of the columns in the list table.
281 + *
282 + * @access public
283 + * @since 1.0.0
284 + *
285 + * @param stdClass $item The current object.
286 + * @param string $column_name The name of the column
287 + * @return string The column value.
288 + */
289 + public function column_default( $item, $column_name ) {
290 + global $ct_table;
291 +
292 + $value = isset( $item->$column_name ) ? $item->$column_name : '';
293 +
294 + $primary_key = $ct_table->db->primary_key;
295 +
296 + ob_start();
297 + /**
298 + * Fires for each custom column of a specific CT table in the list table.
299 + *
300 + * The dynamic portion of the hook name, `$ct_table->name`, refers to the CT table name.
301 + *
302 + * @since 1.0.0
303 + *
304 + * @param string $column_name The name of the column to display.
305 + * @param int $object_id The current object ID.
306 + * @param stdClass $object The current object.
307 + * @param CT_Table $ct_table The CT table object.
308 + */
309 + do_action( "ct_manage_{$ct_table->name}_custom_column", $column_name, $item->$primary_key, $item, $ct_table );
310 + // Backward Compatibility
311 + do_action( "manage_{$ct_table->name}_custom_column", $column_name, $item->$primary_key, $item, $ct_table );
312 + $custom_output = ob_get_clean();
313 +
314 + if( ! empty( $custom_output ) ) {
315 + return $custom_output;
316 + }
317 +
318 + $bulk_actions = $this->get_bulk_actions();
319 +
320 + $first_column_index = ( ! empty( $bulk_actions ) ) ? 1 : 0;
321 +
322 + $can_edit_item = current_user_can( $ct_table->cap->edit_item, $item->$primary_key );
323 + $columns = $this->get_columns();
324 + $columns_keys = array_keys( $columns );
325 +
326 + if( $column_name === $columns_keys[$first_column_index] && $can_edit_item ) {
327 +
328 + // Turns first column into a text link with url to edit the item
329 + $value = sprintf( '<strong><a href="%s" aria-label="%s">%s</a></strong>',
330 + esc_attr( ct_get_edit_link( $ct_table->name, $item->$primary_key ) ),
331 + // translators: %s: value
332 + esc_attr( sprintf( __( 'Edit &#8220;%s&#8221;' ), $value ) ),
333 + $value
334 + );
335 +
336 + // Small screens toggle
337 + $value .= '<button type="button" class="toggle-row"><span class="screen-reader-text">' . esc_html__( 'Show more details' ) . '</span></button>';
338 +
339 + }
340 +
341 + return $value;
342 + }
343 +
344 + /**
345 + * Generates and displays row action links.
346 + *
347 + * @since 4.3.0
348 + * @access protected
349 + *
350 + * @param object $item The item being acted upon.
351 + * @param string $column_name Current column name.
352 + * @param string $primary Primary column name.
353 + *
354 + * @return string Row actions output for posts.
355 + */
356 + protected function handle_row_actions( $item, $column_name, $primary ) {
357 + if ( $primary !== $column_name ) {
358 + return '';
359 + }
360 +
361 + global $ct_table;
362 +
363 + $primary_key = $ct_table->db->primary_key;
364 + $actions = array();
365 +
366 + if ( $ct_table->views->edit && current_user_can( $ct_table->cap->edit_item, $item->$primary_key ) ) {
367 + $actions['edit'] = sprintf(
368 + '<a href="%s" aria-label="%s">%s</a>',
369 + esc_attr( ct_get_edit_link( $ct_table->name, $item->$primary_key ) ),
370 + esc_attr( __( 'Edit' ) ),
371 + esc_html__( 'Edit' )
372 + );
373 + }
374 +
375 + if ( current_user_can( $ct_table->cap->delete_item, $item->$primary_key ) ) {
376 + $actions['delete'] = sprintf(
377 + '<a href="%s" class="submitdelete" onclick="%s" aria-label="%s">%s</a>',
378 + ct_get_delete_link( $ct_table->name, $item->$primary_key ),
379 + "return confirm('" .
380 + esc_attr( ct_get_table_label( $ct_table->name, 'delete_item_confirm' ) ) .
381 + "');",
382 + esc_attr( __( 'Delete permanently' ) ),
383 + esc_html__( 'Delete Permanently' )
384 + );
385 + }
386 +
387 + /**
388 + * Filters the array of row action links on the Posts list table.
389 + *
390 + * The filter is evaluated only for non-hierarchical post types.
391 + *
392 + * @since 2.8.0
393 + *
394 + * @param array $actions An array of row action links. Defaults are
395 + * 'Edit', 'Quick Edit', 'Restore, 'Trash',
396 + * 'Delete Permanently', 'Preview', and 'View'.
397 + * @param WP_Post $post The post object.
398 + */
399 + $actions = apply_filters( "{$ct_table->name}_row_actions", $actions, $item );
400 +
401 + return $this->row_actions( $actions );
402 + }
403 +
404 + /**
405 + * Handles the checkbox column output.
406 + *
407 + * @since 1.0.0
408 + *
409 + * @param WP_Post $item The current WP_Post object.
410 + */
411 + public function column_cb( $item ) {
412 + global $ct_table;
413 +
414 + $primary_key = $ct_table->db->primary_key;
415 +
416 + if ( current_user_can( $ct_table->cap->edit_items ) ): ?>
417 + <label class="screen-reader-text" for="cb-select-<?php echo esc_attr( $item->$primary_key ); ?>"><?php
418 + // translators: %d: item ID
419 + echo esc_html( sprintf( ct_get_table_label( $ct_table->name, 'select_item' ), $item->$primary_key ) );
420 + ?></label>
421 + <input id="cb-select-<?php echo esc_attr( $item->$primary_key ); ?>" type="checkbox" name="item[]" value="<?php echo esc_attr( $item->$primary_key ); ?>" />
422 + <div class="locked-indicator">
423 + <span class="locked-indicator-icon" aria-hidden="true"></span>
424 + <span class="screen-reader-text"><?php
425 + /* translators: %d: item ID */
426 + echo esc_html( sprintf( ct_get_table_label( $ct_table->name, 'item_locked' ), $item->$primary_key ) );
427 + ?></span>
428 + </div>
429 + <?php endif;
430 + }
431 +
432 + /**
433 + * Renders the message to be displayed when there are no results.
434 + *
435 + * @since 1.0.0
436 + */
437 + function no_items() {
438 + global $ct_table;
439 +
440 + echo $ct_table->labels->not_found;
441 + }
442 +
443 + public function prepare_items() {
444 +
445 + global $ct_table, $ct_query;
446 +
447 + // Get per page setting
448 + $per_page = $this->get_items_per_page( 'edit_' . $ct_table->name . '_per_page' );
449 +
450 + // Update query vars based on settings
451 + $ct_query->query_vars['items_per_page'] = $per_page;
452 +
453 + // Get query results
454 + $this->items = $ct_query->get_results();
455 +
456 + $total_items = $ct_query->found_results;
457 +
458 + // Setup pagination args based on items found and per page settings
459 + $this->set_pagination_args( array(
460 + 'total_items' => $total_items,
461 + 'per_page' => $per_page,
462 + 'total_pages' => ceil( $total_items / $per_page )
463 + ) );
464 + }
465 +
466 + }
467 +
468 +endif;