PluginProbe
User Profile Builder – Beautiful User Registration Forms, User Profiles & User Role Editor / 3.6.2
User Profile Builder – Beautiful User Registration Forms, User Profiles & User Role Editor v3.6.2
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 2.0.7 All 340 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 3.6.2, at assets/lib/class-list-table.php

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