PluginProbe
User Profile Builder – Beautiful User Registration Forms, User Profiles & User Role Editor / 4.0.3
User Profile Builder – Beautiful User Registration Forms, User Profiles & User Role Editor v4.0.3
4.0.3 4.0.2 4.0.1 4.0.0 3.16.6 3.16.5 3.16.4 3.16.3 3.16.2 3.16.1 3.16.0 3.15.9 3.9.9 3.9.5 3.9.6 3.9.7 3.9.8 1.1.7 1.1.8 1.1.9 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 All 341 releases
profile-builder / assets / lib / class-list-table.php

class-list-table.php in User Profile Builder – Beautiful User Registration Forms, User Profiles & User Role Editor 4.0.3, at assets/lib/class-list-table.php

976 lines 24.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Base class for displaying a list of items in an ajaxified HTML table.
5 *
6 * @package WordPress
7 * @subpackage List_Table
8 * @since 3.1.0
9 * @access private
10 */
11 class PB_WP_List_Table {
12
13 /**
14 * The current list of items
15 *
16 * @since 3.1.0
17 * @var array
18 * @access protected
19 */
20 var $items;
21
22 /**
23 * Various information about the current table
24 *
25 * @since 3.1.0
26 * @var array
27 * @access private
28 */
29 var $_args;
30
31 /**
32 * Various information needed for displaying the pagination
33 *
34 * @since 3.1.0
35 * @var array
36 * @access private
37 */
38 var $_pagination_args = array();
39
40 /**
41 * The current screen
42 *
43 * @since 3.1.0
44 * @var object
45 * @access protected
46 */
47 var $screen;
48
49 /**
50 * Cached bulk actions
51 *
52 * @since 3.1.0
53 * @var array
54 * @access private
55 */
56 var $_actions;
57
58 /**
59 * Cached pagination output
60 *
61 * @since 3.1.0
62 * @var string
63 * @access private
64 */
65 var $_pagination;
66
67 var $_column_headers;
68
69 var $dataArray;
70
71 /**
72 * Constructor. The child class should call this constructor from its own constructor
73 *
74 * @param array $args An associative array with information about the current table
75 * @access protected
76 */
77 function __construct( $args = array() ) {
78 $args = wp_parse_args( $args, array(
79 'plural' => '',
80 'singular' => '',
81 'ajax' => false,
82 'screen' => null,
83 ) );
84
85 $this->screen = convert_to_screen( $args['screen'] );
86
87 add_filter( "manage_{$this->screen->id}_columns", array( $this, 'get_columns' ), 0 );
88
89 if ( !$args['plural'] )
90 $args['plural'] = $this->screen->base;
91
92 $args['plural'] = sanitize_key( $args['plural'] );
93 $args['singular'] = sanitize_key( $args['singular'] );
94
95 $this->_args = $args;
96
97 if ( $args['ajax'] ) {
98 // wp_enqueue_script( 'list-table' );
99 add_action( 'admin_footer', array( $this, '_js_vars' ) );
100 }
101 }
102
103 /**
104 * Checks the current user's permissions
105 * @uses wp_die()
106 *
107 * @since 3.1.0
108 * @access public
109 * @abstract
110 */
111 function ajax_user_can() {
112 die( 'function WP_List_Table::ajax_user_can() must be over-ridden in a sub-class.' );
113 }
114
115 /**
116 * Prepares the list of items for displaying.
117 * @uses WP_List_Table::set_pagination_args()
118 *
119 * @since 3.1.0
120 * @access public
121 * @abstract
122 */
123 function prepare_items() {
124 die( 'function WP_List_Table::prepare_items() must be over-ridden in a sub-class.' );
125 }
126
127 /**
128 * An internal method that sets all the necessary pagination arguments
129 *
130 * @param array $args An associative array with information about the pagination
131 * @access protected
132 */
133 function set_pagination_args( $args ) {
134 $args = wp_parse_args( $args, array(
135 'total_items' => 0,
136 'total_pages' => 0,
137 'per_page' => 0,
138 ) );
139
140 if ( !$args['total_pages'] && $args['per_page'] > 0 )
141 $args['total_pages'] = ceil( $args['total_items'] / $args['per_page'] );
142
143 // redirect if page number is invalid and headers are not already sent
144 if ( ! headers_sent() && ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) && $args['total_pages'] > 0 && $this->get_pagenum() > $args['total_pages'] ) {
145 wp_safe_redirect( add_query_arg( 'paged', $args['total_pages'] ) );
146 exit;
147 }
148
149 $this->_pagination_args = $args;
150 }
151
152 /**
153 * Access the pagination args
154 *
155 * @since 3.1.0
156 * @access public
157 *
158 * @param string $key
159 * @return array
160 */
161 function get_pagination_arg( $key ) {
162 if ( 'page' == $key )
163 return $this->get_pagenum();
164
165 if ( isset( $this->_pagination_args[$key] ) )
166 return $this->_pagination_args[$key];
167 }
168
169 /**
170 * Whether the table has items to display or not
171 *
172 * @since 3.1.0
173 * @access public
174 *
175 * @return bool
176 */
177 function has_items() {
178 return !empty( $this->items );
179 }
180
181 /**
182 * Message to be displayed when there are no items
183 *
184 * @since 3.1.0
185 * @access public
186 */
187 function no_items() {
188 esc_html_e( 'No items found.' );//phpcs:ignore WordPress.WP.I18n.MissingArgDomain
189 }
190
191 /**
192 * Display the search box.
193 *
194 * @since 3.1.0
195 * @access public
196 *
197 * @param string $text The search button text
198 * @param string $input_id The search input id
199 */
200 function search_box( $text, $input_id ) {
201 if ( empty( $_REQUEST['s'] ) && !$this->has_items() )
202 return;
203
204 $input_id = $input_id . '-search-input';
205
206 if ( ! empty( $_REQUEST['orderby'] ) )
207 echo '<input type="hidden" name="orderby" value="' . esc_attr( $_REQUEST['orderby'] ) . '" />';//phpcs:ignore
208 if ( ! empty( $_REQUEST['order'] ) )
209 echo '<input type="hidden" name="order" value="' . esc_attr( $_REQUEST['order'] ) . '" />';//phpcs:ignore
210 if ( ! empty( $_REQUEST['post_mime_type'] ) )
211 echo '<input type="hidden" name="post_mime_type" value="' . esc_attr( $_REQUEST['post_mime_type'] ) . '" />';//phpcs:ignore
212 if ( ! empty( $_REQUEST['detached'] ) )
213 echo '<input type="hidden" name="detached" value="' . esc_attr( $_REQUEST['detached'] ) . '" />';//phpcs:ignore
214 ?>
215 <p class="search-box">
216 <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ) ?>"><?php echo esc_html( $text ); ?>:</label>
217 <input type="search" id="<?php echo esc_attr( $input_id ) ?>" name="s" value="<?php _admin_search_query(); ?>" />
218 <?php submit_button( $text, 'button', false, false, array('id' => 'search-submit') ); ?>
219 </p>
220 <?php
221 }
222
223 /**
224 * Get an associative array ( id => link ) with the list
225 * of views available on this table.
226 *
227 * @since 3.1.0
228 * @access protected
229 *
230 * @return array
231 */
232 function get_views() {
233 return array();
234 }
235
236 /**
237 * Display the list of views available on this table.
238 *
239 * @since 3.1.0
240 * @access public
241 */
242 function views() {
243 $views = $this->get_views();
244 /**
245 * Filter the list of available list table views.
246 *
247 * The dynamic portion of the hook name, $this->screen->id, refers
248 * to the ID of the current screen, usually a string.
249 *
250 * @since 3.5.0
251 *
252 * @param array $views An array of available list table views.
253 */
254 $views = apply_filters( "views_{$this->screen->id}", $views );
255
256 if ( empty( $views ) )
257 return;
258
259 echo "<ul class='subsubsub'>\n";
260 foreach ( $views as $class => $view ) {
261 $views[ $class ] = "\t<li class='$class'>$view";
262 }
263 echo wp_kses_post( implode( " |</li>\n", $views ) . "</li>\n" );
264 echo "</ul>";
265 }
266
267 /**
268 * Get an associative array ( option_name => option_title ) with the list
269 * of bulk actions available on this table.
270 *
271 * @since 3.1.0
272 * @access protected
273 *
274 * @return array
275 */
276 function get_bulk_actions() {
277 return array();
278 }
279
280 /**
281 * Display the bulk actions dropdown.
282 *
283 * @since 3.1.0
284 * @access public
285 */
286 function bulk_actions() {
287 if ( is_null( $this->_actions ) ) {
288 $no_new_actions = $this->_actions = $this->get_bulk_actions();
289 /**
290 * Filter the list table Bulk Actions drop-down.
291 *
292 * The dynamic portion of the hook name, $this->screen->id, refers
293 * to the ID of the current screen, usually a string.
294 *
295 * This filter can currently only be used to remove bulk actions.
296 *
297 * @since 3.5.0
298 *
299 * @param array $actions An array of the available bulk actions.
300 */
301 $this->_actions = apply_filters( "bulk_actions-{$this->screen->id}", $this->_actions );
302 $this->_actions = array_intersect_assoc( $this->_actions, $no_new_actions );
303 $two = '';
304 } else {
305 $two = '2';
306 }
307
308 if ( empty( $this->_actions ) )
309 return;
310
311 echo "<select name='action". esc_attr( $two ) ."'>\n";
312 echo "<option value='-1' selected='selected'>" . __( 'Bulk Actions' ) . "</option>\n";//phpcs:ignore
313
314 foreach ( $this->_actions as $name => $title ) {
315 $class = 'edit' == $name ? ' class="hide-if-no-js"' : '';
316
317 echo "\t<option value='".esc_attr($name)."'$class>". esc_html( $title )."</option>\n";//phpcs:ignore
318 }
319
320 echo "</select>\n";
321
322 submit_button( __( 'Apply' ), 'action', false, false, array( 'id' => "doaction$two" ) );//phpcs:ignore
323 echo "\n";
324 }
325
326 /**
327 * Get the current action selected from the bulk actions dropdown.
328 *
329 * @since 3.1.0
330 * @access public
331 *
332 * @return string|bool The action name or False if no action was selected
333 */
334 function current_action() {
335 if ( isset( $_REQUEST['action'] ) && -1 != $_REQUEST['action'] )
336 return sanitize_text_field( $_REQUEST['action'] );
337
338 if ( isset( $_REQUEST['action2'] ) && -1 != $_REQUEST['action2'] )
339 return sanitize_text_field( $_REQUEST['action2'] );
340
341 return false;
342 }
343
344 /**
345 * Generate row actions div
346 *
347 * @since 3.1.0
348 * @access protected
349 *
350 * @param array $actions The list of actions
351 * @param bool $always_visible Whether the actions should be always visible
352 * @return string
353 */
354 function row_actions( $actions, $always_visible = false ) {
355 $action_count = count( $actions );
356 $i = 0;
357
358 if ( !$action_count )
359 return '';
360
361 $out = '<div class="' . ( $always_visible ? 'row-actions visible' : 'row-actions' ) . '">';
362 foreach ( $actions as $action => $link ) {
363 ++$i;
364 ( $i == $action_count ) ? $sep = '' : $sep = ' | ';
365 $out .= "<span class='$action'>$link$sep</span>";
366 }
367 $out .= '</div>';
368
369 return $out;
370 }
371
372 /**
373 * Display a monthly dropdown for filtering items
374 *
375 * @since 3.1.0
376 * @access protected
377 */
378 function months_dropdown( $post_type ) {
379 global $wpdb, $wp_locale;
380
381 $months = $wpdb->get_results( $wpdb->prepare( "
382 SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
383 FROM $wpdb->posts
384 WHERE post_type = %s
385 ORDER BY post_date DESC
386 ", $post_type ) );
387
388 /**
389 * Filter the 'Months' drop-down results.
390 *
391 * @since 3.7.0
392 *
393 * @param object $months The months drop-down query results.
394 * @param string $post_type The post type.
395 */
396 $months = apply_filters( 'months_dropdown_results', $months, $post_type );
397
398 $month_count = count( $months );
399
400 if ( !$month_count || ( 1 == $month_count && 0 == $months[0]->month ) )
401 return;
402
403 $m = isset( $_GET['m'] ) ? (int) sanitize_text_field( $_GET['m'] ) : 0;
404 ?>
405 <select name='m'>
406 <option<?php selected( $m, 0 ); ?> value='0'><?php esc_html_e( 'Show all dates' ); //phpcs:ignore ?></option>
407 <?php
408 foreach ( $months as $arc_row ) {
409 if ( 0 == $arc_row->year )
410 continue;
411
412 $month = zeroise( $arc_row->month, 2 );
413 $year = $arc_row->year;
414
415 printf( "<option %s value='%s'>%s</option>\n",
416 selected( $m, $year . $month, false ),
417 esc_attr( $arc_row->year . $month ),
418 /* translators: 1: month name, 2: 4-digit year */
419 sprintf( __( '%1$s %2$d' ), esc_attr( $wp_locale->get_month( $month ) ), esc_attr( $year ) )//phpcs:ignore
420 );
421 }
422 ?>
423 </select>
424 <?php
425 }
426
427 /**
428 * Display a view switcher
429 *
430 * @since 3.1.0
431 * @access protected
432 */
433 function view_switcher( $current_mode ) {
434 $modes = array(
435 'list' => __( 'List View' ),//phpcs:ignore
436 'excerpt' => __( 'Excerpt View' )//phpcs:ignore
437 );
438
439 ?>
440 <input type="hidden" name="mode" value="<?php echo esc_attr( $current_mode ); ?>" />
441 <div class="view-switch">
442 <?php
443 foreach ( $modes as $mode => $title ) {
444 $class = ( $current_mode == $mode ) ? 'class="current"' : '';
445 echo "<a href='" . esc_url( add_query_arg( 'mode', $mode, $_SERVER['REQUEST_URI'] ) ) . "' $class><img id='view-switch-$mode' src='" . esc_url( includes_url( 'images/blank.gif' ) ) . "' width='20' height='20' title='$title' alt='$title' /></a>\n";//phpcs:ignore
446 }
447 ?>
448 </div>
449 <?php
450 }
451
452 /**
453 * Display a comment count bubble
454 *
455 * @since 3.1.0
456 * @access protected
457 *
458 * @param int $post_id
459 * @param int $pending_comments
460 */
461 function comments_bubble( $post_id, $pending_comments ) {
462
463 if( !empty( $pending_comments ) )
464 $pending_phrase = sprintf( __( '%s pending' ), number_format( $pending_comments ) );//phpcs:ignore
465 else
466 $pending_phrase = __( '0 pending' );//phpcs:ignore
467
468 if ( $pending_comments )
469 echo '<strong>';
470
471 echo "<a href='" . esc_url( add_query_arg( 'p', $post_id, admin_url( 'edit-comments.php' ) ) ) . "' title='" . esc_attr( $pending_phrase ) . "' class='post-com-count'><span class='comment-count'>" . number_format_i18n( get_comments_number() ) . "</span></a>";//phpcs:ignore
472
473 if ( $pending_comments )
474 echo '</strong>';
475 }
476
477 /**
478 * Get the current page number
479 *
480 * @since 3.1.0
481 * @access protected
482 *
483 * @return int
484 */
485 function get_pagenum() {
486 $pagenum = isset( $_REQUEST['paged'] ) ? absint( $_REQUEST['paged'] ) : 0;
487
488 if( isset( $this->_pagination_args['total_pages'] ) && $pagenum > $this->_pagination_args['total_pages'] )
489 $pagenum = $this->_pagination_args['total_pages'];
490
491 return max( 1, $pagenum );
492 }
493
494 /**
495 * Get number of items to display on a single page
496 *
497 * @since 3.1.0
498 * @access protected
499 *
500 * @return int
501 */
502 function get_items_per_page( $option, $default = 20 ) {
503 $per_page = (int) get_user_option( $option );
504 if ( empty( $per_page ) || $per_page < 1 )
505 $per_page = $default;
506
507 /**
508 * Filter the number of items to be displayed on each page of the list table.
509 *
510 * The dynamic hook name, $option, refers to the per page option depending
511 * on the type of list table in use. Possible values may include:
512 * 'edit_comments_per_page', 'sites_network_per_page', 'site_themes_network_per_page',
513 * 'themes_netework_per_page', 'users_network_per_page', 'edit_{$post_type}', etc.
514 *
515 * @since 2.9.0
516 *
517 * @param int $per_page Number of items to be displayed. Default 20.
518 */
519 return (int) apply_filters( $option, $per_page );
520 }
521
522 /**
523 * Display the pagination.
524 *
525 * @since 3.1.0
526 * @access protected
527 */
528 function pagination( $which ) {
529 if ( empty( $this->_pagination_args ) )
530 return;
531
532 extract( $this->_pagination_args, EXTR_SKIP );
533
534 $output = '<span class="displaying-num">' . sprintf( _n( '1 item', '%s items', $total_items ), number_format_i18n( $total_items ) ) . '</span>';//phpcs:ignore
535
536 $current = $this->get_pagenum();
537
538 $current_url = set_url_scheme( 'http://' . sanitize_text_field( $_SERVER['HTTP_HOST'] ) . esc_url_raw( $_SERVER['REQUEST_URI'] ) );//phpcs:ignore
539
540 $current_url = remove_query_arg( array( 'hotkeys_highlight_last', 'hotkeys_highlight_first' ), $current_url );
541
542 $page_links = array();
543
544 $disable_first = $disable_last = '';
545 if ( $current == 1 )
546 $disable_first = ' disabled';
547 if ( $current == $total_pages )
548 $disable_last = ' disabled';
549
550 $page_links[] = sprintf( "<a class='%s' title='%s' href='%s'>%s</a>",
551 'first-page button' . $disable_first,
552 esc_attr__( 'Go to the first page' ),//phpcs:ignore
553 esc_url( remove_query_arg( 'paged', $current_url ) ),
554 '&laquo;'
555 );
556
557 $page_links[] = sprintf( "<a class='%s' title='%s' href='%s'>%s</a>",
558 'prev-page button' . $disable_first,
559 esc_attr__( 'Go to the previous page' ),//phpcs:ignore
560 esc_url( add_query_arg( 'paged', max( 1, $current-1 ), $current_url ) ),
561 '&lsaquo;'
562 );
563
564 if ( 'bottom' == $which )
565 $html_current_page = $current;
566 else
567 $html_current_page = sprintf( "<input class='current-page' title='%s' type='text' name='paged' value='%s' size='%d' />",
568 esc_attr__( 'Current page' ),//phpcs:ignore
569 $current,
570 strlen( $total_pages )
571 );
572
573 $html_total_pages = sprintf( "<span class='total-pages'>%s</span>", number_format_i18n( $total_pages ) );
574 $page_links[] = '<span class="paging-input">' . sprintf( _x( '%1$s of %2$s', 'paging' ), $html_current_page, $html_total_pages ) . '</span>'; //phpcs:ignore
575
576 $page_links[] = sprintf( "<a class='%s' title='%s' href='%s'>%s</a>",
577 'next-page button' . $disable_last,
578 esc_attr__( 'Go to the next page' ),//phpcs:ignore
579 esc_url( add_query_arg( 'paged', min( $total_pages, $current+1 ), $current_url ) ),
580 '&rsaquo;'
581 );
582
583 $page_links[] = sprintf( "<a class='%s' title='%s' href='%s'>%s</a>",
584 'last-page button' . $disable_last,
585 esc_attr__( 'Go to the last page' ),//phpcs:ignore
586 esc_url( add_query_arg( 'paged', $total_pages, $current_url ) ),
587 '&raquo;'
588 );
589
590 $pagination_links_class = 'pagination-links';
591 if ( ! empty( $infinite_scroll ) )
592 $pagination_links_class = ' hide-if-js';
593 $output .= "\n<span class='$pagination_links_class'>" . join( "\n", $page_links ) . '</span>';
594
595 if ( $total_pages )
596 $page_class = $total_pages < 2 ? ' one-page' : '';
597 else
598 $page_class = ' no-pages';
599
600 $this->_pagination = "<div class='tablenav-pages{$page_class}'>$output</div>";
601
602 echo $this->_pagination;//phpcs:ignore
603 }
604
605 /**
606 * Get a list of columns. The format is:
607 * 'internal-name' => 'Title'
608 *
609 * @since 3.1.0
610 * @access protected
611 * @abstract
612 *
613 * @return array
614 */
615 function get_columns() {
616 die( 'function WP_List_Table::get_columns() must be over-ridden in a sub-class.' );
617 }
618
619 /**
620 * Get a list of sortable columns. The format is:
621 * 'internal-name' => 'orderby'
622 * or
623 * 'internal-name' => array( 'orderby', true )
624 *
625 * The second format will make the initial sorting order be descending
626 *
627 * @since 3.1.0
628 * @access protected
629 *
630 * @return array
631 */
632 function get_sortable_columns() {
633 return array();
634 }
635
636 /**
637 * Get a list of all, hidden and sortable columns, with filter applied
638 *
639 * @since 3.1.0
640 * @access protected
641 *
642 * @return array
643 */
644 function get_column_info() {
645 if ( isset( $this->_column_headers ) )
646 return $this->_column_headers;
647
648 $columns = get_column_headers( $this->screen );
649 $hidden = get_hidden_columns( $this->screen );
650
651 $sortable_columns = $this->get_sortable_columns();
652 /**
653 * Filter the list table sortable columns for a specific screen.
654 *
655 * The dynamic portion of the hook name, $this->screen->id, refers
656 * to the ID of the current screen, usually a string.
657 *
658 * @since 3.5.0
659 *
660 * @param array $sortable_columns An array of sortable columns.
661 */
662 $_sortable = apply_filters( "manage_{$this->screen->id}_sortable_columns", $sortable_columns );
663
664 $sortable = array();
665 foreach ( $_sortable as $id => $data ) {
666 if ( empty( $data ) )
667 continue;
668
669 $data = (array) $data;
670 if ( !isset( $data[1] ) )
671 $data[1] = false;
672
673 $sortable[$id] = $data;
674 }
675
676 $this->_column_headers = array( $columns, $hidden, $sortable );
677
678 return $this->_column_headers;
679 }
680
681 /**
682 * Return number of visible columns
683 *
684 * @since 3.1.0
685 * @access public
686 *
687 * @return int
688 */
689 function get_column_count() {
690 list ( $columns, $hidden ) = $this->get_column_info();
691 $hidden = array_intersect( array_keys( $columns ), array_filter( $hidden ) );
692 return count( $columns ) - count( $hidden );
693 }
694
695 /**
696 * Print column headers, accounting for hidden and sortable columns.
697 *
698 * @since 3.1.0
699 * @access protected
700 *
701 * @param bool $with_id Whether to set the id attribute or not
702 */
703 function print_column_headers( $with_id = true ) {
704 list( $columns, $hidden, $sortable ) = $this->get_column_info();
705
706 $current_url = set_url_scheme( 'http://' . sanitize_text_field( $_SERVER['HTTP_HOST'] ) . esc_url_raw( $_SERVER['REQUEST_URI'] ) );//phpcs:ignore
707 $current_url = remove_query_arg( 'paged', $current_url );
708
709 if ( isset( $_GET['orderby'] ) )
710 $current_orderby = sanitize_sql_orderby( $_GET['orderby'] );
711 else
712 $current_orderby = '';
713
714 if ( isset( $_GET['order'] ) && 'desc' == sanitize_text_field( $_GET['order'] ) )
715 $current_order = 'desc';
716 else
717 $current_order = 'asc';
718
719 if ( ! empty( $columns['cb'] ) ) {
720 static $cb_counter = 1;
721 $columns['cb'] = '<label class="screen-reader-text" for="cb-select-all-' . esc_attr( $cb_counter ) . '">' . __( 'Select All' ) . '</label>'//phpcs:ignore
722 . '<input id="cb-select-all-' . $cb_counter . '" type="checkbox" />';
723 $cb_counter++;
724 }
725
726 foreach ( $columns as $column_key => $column_display_name ) {
727 $class = array( 'manage-column', "column-$column_key" );
728
729 $style = '';
730 if ( in_array( $column_key, $hidden ) )
731 $style = 'display:none;';
732
733 if ( 'cb' == $column_key ) {
734 $class[] = 'check-column';
735 $style .= ' padding: 10px 0 10px 3px;';
736 } elseif ( in_array( $column_key, array( 'posts', 'comments', 'links' ) ) )
737 $class[] = 'num';
738
739 $style = ' style="' . $style . '"';
740
741 if ( isset( $sortable[$column_key] ) ) {
742 list( $orderby, $desc_first ) = $sortable[$column_key];
743
744 if ( $current_orderby == $orderby ) {
745 $order = 'asc' == $current_order ? 'desc' : 'asc';
746 $class[] = 'sorted';
747 $class[] = $current_order;
748 } else {
749 $order = $desc_first ? 'desc' : 'asc';
750 $class[] = 'sortable';
751 $class[] = $desc_first ? 'asc' : 'desc';
752 }
753
754 $column_display_name = '<a href="' . esc_url( add_query_arg( compact( 'orderby', 'order' ), $current_url ) ) . '"><span>' . $column_display_name . '</span><span class="sorting-indicator"></span></a>';
755 }
756
757 $id = $with_id ? "id='$column_key'" : '';
758
759 if ( !empty( $class ) )
760 $class = "class='" . join( ' ', $class ) . "'";
761
762 echo "<th scope='col' $id $class $style>$column_display_name</th>";//phpcs:ignore
763 }
764 }
765
766 /**
767 * Display the table
768 *
769 * @since 3.1.0
770 * @access public
771 */
772 function display() {
773 extract( $this->_args );
774
775 $this->display_tablenav( 'top' );
776
777 ?>
778 <table class="wp-list-table <?php echo esc_attr( implode( ' ', $this->get_table_classes() ) ); ?>" cellspacing="0">
779 <thead>
780 <tr>
781 <?php $this->print_column_headers(); ?>
782 </tr>
783 </thead>
784
785 <tfoot>
786 <tr>
787 <?php $this->print_column_headers( false ); ?>
788 </tr>
789 </tfoot>
790
791 <tbody id="the-list"<?php if ( $singular ) echo " data-wp-lists='list:$singular'";//phpcs:ignore ?>>
792 <?php $this->display_rows_or_placeholder(); ?>
793 </tbody>
794 </table>
795 <?php
796 $this->display_tablenav( 'bottom' );
797 }
798
799 /**
800 * Get a list of CSS classes for the <table> tag
801 *
802 * @since 3.1.0
803 * @access protected
804 *
805 * @return array
806 */
807 function get_table_classes() {
808 return array( 'widefat', 'fixed', $this->_args['plural'] );
809 }
810
811 /**
812 * Generate the table navigation above or below the table
813 *
814 * @since 3.1.0
815 * @access protected
816 */
817 function display_tablenav( $which ) {
818 if ( 'top' == $which )
819 wp_nonce_field( 'bulk-' . $this->_args['plural'] );
820 ?>
821 <div class="tablenav <?php echo esc_attr( $which ); ?>">
822
823 <div class="alignleft actions bulkactions">
824 <?php $this->bulk_actions(); ?>
825 </div>
826 <?php
827 $this->extra_tablenav( $which );
828 $this->pagination( $which );
829 ?>
830
831 <br class="clear" />
832 </div>
833 <?php
834 }
835
836 /**
837 * Extra controls to be displayed between bulk actions and pagination
838 *
839 * @since 3.1.0
840 * @access protected
841 */
842 function extra_tablenav( $which ) {}
843
844 /**
845 * Generate the <tbody> part of the table
846 *
847 * @since 3.1.0
848 * @access protected
849 */
850 function display_rows_or_placeholder() {
851 if ( $this->has_items() ) {
852 $this->display_rows();
853 } else {
854 list( $columns, $hidden ) = $this->get_column_info();
855 echo '<tr class="no-items"><td class="colspanchange" colspan="' . esc_attr( $this->get_column_count() ) . '">';
856 $this->no_items();
857 echo '</td></tr>';
858 }
859 }
860
861 /**
862 * Generate the table rows
863 *
864 * @since 3.1.0
865 * @access protected
866 */
867 function display_rows() {
868 foreach ( $this->items as $item )
869 $this->single_row( $item );
870 }
871
872 /**
873 * Generates content for a single row of the table
874 *
875 * @since 3.1.0
876 * @access protected
877 *
878 * @param object $item The current item
879 */
880 function single_row( $item ) {
881 static $row_class = '';
882 $row_class = ( $row_class == '' ? ' class="alternate"' : '' );
883
884 echo '<tr id="user-'. esc_attr( $item['ID'] ) .'" ' . $row_class . '>';//phpcs:ignore
885 $this->single_row_columns( $item );
886 echo '</tr>';
887 }
888
889 /**
890 * Generates the columns for a single row of the table
891 *
892 * @since 3.1.0
893 * @access protected
894 *
895 * @param object $item The current item
896 */
897 function single_row_columns( $item ) {
898 list( $columns, $hidden ) = $this->get_column_info();
899
900 foreach ( $columns as $column_name => $column_display_name ) {
901 $class = "class='$column_name column-$column_name'";
902
903 $style = '';
904 if ( in_array( $column_name, $hidden ) )
905 $style = ' style="display:none;"';
906
907 $attributes = "$class$style";
908
909 if ( 'cb' == $column_name ) {
910 echo '<th scope="row" class="check-column">';
911 echo $this->column_cb( $item );//phpcs:ignore
912 echo '</th>';
913 }
914 elseif ( method_exists( $this, 'column_' . $column_name ) ) {
915 echo "<td $attributes>";//phpcs:ignore
916 echo call_user_func( array( $this, 'column_' . $column_name ), $item );//phpcs:ignore
917 echo "</td>";
918 }
919 else {
920 echo "<td $attributes>";//phpcs:ignore
921 echo $this->column_default( $item, $column_name );//phpcs:ignore
922 echo "</td>";
923 }
924 }
925 }
926
927 /**
928 * Handle an incoming ajax request (called from admin-ajax.php)
929 *
930 * @since 3.1.0
931 * @access public
932 */
933 function ajax_response() {
934 $this->prepare_items();
935
936 extract( $this->_args );
937 extract( $this->_pagination_args, EXTR_SKIP );
938
939 ob_start();
940 if ( ! empty( $_REQUEST['no_placeholder'] ) )
941 $this->display_rows();
942 else
943 $this->display_rows_or_placeholder();
944
945 $rows = ob_get_clean();
946
947 $response = array( 'rows' => $rows );
948
949 if ( isset( $total_items ) )
950 $response['total_items_i18n'] = sprintf( _n( '1 item', '%s items', $total_items ), number_format_i18n( $total_items ) );//phpcs:ignore
951
952 if ( isset( $total_pages ) ) {
953 $response['total_pages'] = $total_pages;
954 $response['total_pages_i18n'] = number_format_i18n( $total_pages );
955 }
956
957 die( json_encode( $response ) );
958 }
959
960 /**
961 * Send required variables to JavaScript land
962 *
963 * @access private
964 */
965 function _js_vars() {
966 $args = array(
967 'class' => get_class( $this ),
968 'screen' => array(
969 'id' => $this->screen->id,
970 'base' => $this->screen->base,
971 )
972 );
973
974 printf( "<script type='text/javascript'>list_args = %s;</script>\n", json_encode( $args ) );
975 }
976 }