PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 1.9.7
Tutor LMS – eLearning and online course solution v1.9.7
3.9.15 3.9.14 3.9.13 3.9.12 3.9.11 trunk 1.0.0 1.0.0-alpha 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.2.0 1.2.1 1.2.11 1.2.12 1.2.13 1.2.20 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9 1.8.0 1.8.1 1.8.10 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9.0 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.14 1.9.15 1.9.16 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1 2.0.10 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1.0 2.1.1 2.1.10 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.3.0 2.4.0 2.5.0 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 3.0.0 3.0.1 3.0.2 3.1.0 3.2.0 3.2.1 3.2.2 3.2.3 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.7.0 3.7.1 3.7.2 3.7.3 3.7.4 3.8.0 3.8.1 3.8.2 3.8.3 3.9.0 3.9.1 3.9.10 3.9.2 3.9.3 3.9.4 3.9.5 3.9.6 3.9.7 3.9.8 3.9.9
tutor / classes / Tutor_List_Table.php
tutor / classes Last commit date
Addons.php 4 years ago Admin.php 4 years ago Ajax.php 4 years ago Assets.php 4 years ago Course.php 4 years ago Course_Filter.php 4 years ago Course_Settings_Tabs.php 5 years ago Course_Widget.php 5 years ago Custom_Validation.php 5 years ago Dashboard.php 5 years ago Email.php 5 years ago FormHandler.php 5 years ago Frontend.php 5 years ago Gutenberg.php 4 years ago Instructor.php 4 years ago Instructors_List.php 4 years ago Lesson.php 4 years ago Options.php 4 years ago Post_types.php 4 years ago Private_Course_Access.php 5 years ago Q_and_A.php 5 years ago Question_Answers_List.php 4 years ago Quiz.php 4 years ago Quiz_Attempts_List.php 4 years ago RestAPI.php 5 years ago Rewrite_Rules.php 5 years ago Shortcode.php 4 years ago Student.php 5 years ago Students_List.php 4 years ago Taxonomies.php 5 years ago Template.php 4 years ago Theme_Compatibility.php 5 years ago Tools.php 5 years ago Tutor.php 4 years ago TutorEDD.php 5 years ago Tutor_Base.php 5 years ago Tutor_List_Table.php 4 years ago Tutor_Setup.php 4 years ago Upgrader.php 5 years ago User.php 4 years ago Utils.php 4 years ago Video_Stream.php 5 years ago Withdraw.php 5 years ago Withdraw_Requests_List.php 4 years ago WooCommerce.php 4 years ago
Tutor_List_Table.php
1480 lines
1 <?php
2 /**
3 * Created by PhpStorm.
4 * User: themeum
5 * Date: 24/9/18
6 * Time: 12:03 PM
7 */
8
9
10 if ( ! defined( 'ABSPATH' ) )
11 exit;
12
13 /**
14 * Base class for displaying a list of items in an ajaxified HTML table.
15 *
16 * @since 3.1.0
17 * @access private
18 */
19 class Tutor_List_Table {
20
21 /**
22 * The current list of items.
23 *
24 * @since 3.1.0
25 * @var array
26 */
27 public $items;
28
29 /**
30 * Various information about the current table.
31 *
32 * @since 3.1.0
33 * @var array
34 */
35 protected $_args;
36
37 /**
38 * Various information needed for displaying the pagination.
39 *
40 * @since 3.1.0
41 * @var array
42 */
43 protected $_pagination_args = array();
44
45 /**
46 * The current screen.
47 *
48 * @since 3.1.0
49 * @var object
50 */
51 protected $screen;
52
53 /**
54 * Cached bulk actions.
55 *
56 * @since 3.1.0
57 * @var array
58 */
59 private $_actions;
60
61 /**
62 * Cached pagination output.
63 *
64 * @since 3.1.0
65 * @var string
66 */
67 private $_pagination;
68
69 /**
70 * The view switcher modes.
71 *
72 * @since 4.1.0
73 * @var array
74 */
75 protected $modes = array();
76
77 /**
78 * Stores the value returned by ->get_column_info().
79 *
80 * @since 4.1.0
81 * @var array
82 */
83 protected $_column_headers;
84
85 /**
86 * {@internal Missing Summary}
87 *
88 * @var array
89 */
90 protected $compat_fields = array( '_args', '_pagination_args', 'screen', '_actions', '_pagination' );
91
92 /**
93 * {@internal Missing Summary}
94 *
95 * @var array
96 */
97 protected $compat_methods = array( 'set_pagination_args', 'get_views', 'get_bulk_actions', 'bulk_actions',
98 'row_actions', 'months_dropdown', 'view_switcher', 'comments_bubble', 'get_items_per_page', 'pagination',
99 'get_sortable_columns', 'get_column_info', 'get_table_classes', 'display_tablenav', 'extra_tablenav',
100 'single_row_columns' );
101
102 /**
103 * Constructor.
104 *
105 * The child class should call this constructor from its own constructor to override
106 * the default $args.
107 *
108 * @since 3.1.0
109 *
110 * @param array|string $args {
111 * Array or string of arguments.
112 *
113 * @type string $plural Plural value used for labels and the objects being listed.
114 * This affects things such as CSS class-names and nonces used
115 * in the list table, e.g. 'posts'. Default empty.
116 * @type string $singular Singular label for an object being listed, e.g. 'post'.
117 * Default empty
118 * @type bool $ajax Whether the list table supports Ajax. This includes loading
119 * and sorting data, for example. If true, the class will call
120 * the _js_vars() method in the footer to provide variables
121 * to any scripts handling Ajax events. Default false.
122 * @type string $screen String containing the hook name used to determine the current
123 * screen. If left null, the current screen will be automatically set.
124 * Default null.
125 * }
126 */
127 public function __construct( $args = array() ) {
128 $args = wp_parse_args( $args, array(
129 'plural' => '',
130 'singular' => '',
131 'ajax' => false,
132 'screen' => null,
133 ) );
134
135 $this->screen = convert_to_screen( $args['screen'] );
136
137 add_filter( "manage_{$this->screen->id}_columns", array( $this, 'get_columns' ), 0 );
138
139 if ( !$args['plural'] )
140 $args['plural'] = $this->screen->base;
141
142 $args['plural'] = sanitize_key( $args['plural'] );
143 $args['singular'] = sanitize_key( $args['singular'] );
144
145 $this->_args = $args;
146
147 if ( $args['ajax'] ) {
148 // wp_enqueue_script( 'list-table' );
149 add_action( 'admin_footer', array( $this, '_js_vars' ) );
150 }
151
152 if ( empty( $this->modes ) ) {
153 $this->modes = array(
154 'list' => __( 'List View' ),
155 'excerpt' => __( 'Excerpt View' )
156 );
157 }
158 }
159
160 /**
161 * Make private properties readable for backward compatibility.
162 *
163 * @since 4.0.0
164 *
165 * @param string $name Property to get.
166 * @return mixed Property.
167 */
168 public function __get( $name ) {
169 if ( in_array( $name, $this->compat_fields ) ) {
170 return $this->$name;
171 }
172 }
173
174 /**
175 * Make private properties settable for backward compatibility.
176 *
177 * @since 4.0.0
178 *
179 * @param string $name Property to check if set.
180 * @param mixed $value Property value.
181 * @return mixed Newly-set property.
182 */
183 public function __set( $name, $value ) {
184 if ( in_array( $name, $this->compat_fields ) ) {
185 return $this->$name = $value;
186 }
187 }
188
189 /**
190 * Make private properties checkable for backward compatibility.
191 *
192 * @since 4.0.0
193 *
194 * @param string $name Property to check if set.
195 * @return bool Whether the property is set.
196 */
197 public function __isset( $name ) {
198 if ( in_array( $name, $this->compat_fields ) ) {
199 return isset( $this->$name );
200 }
201 }
202
203 /**
204 * Make private properties un-settable for backward compatibility.
205 *
206 * @since 4.0.0
207 *
208 * @param string $name Property to unset.
209 */
210 public function __unset( $name ) {
211 if ( in_array( $name, $this->compat_fields ) ) {
212 unset( $this->$name );
213 }
214 }
215
216 /**
217 * Make private/protected methods readable for backward compatibility.
218 *
219 * @since 4.0.0
220 *
221 * @param callable $name Method to call.
222 * @param array $arguments Arguments to pass when calling.
223 * @return mixed|bool Return value of the callback, false otherwise.
224 */
225 public function __call( $name, $arguments ) {
226 if ( in_array( $name, $this->compat_methods ) ) {
227 return call_user_func_array( array( $this, $name ), $arguments );
228 }
229 return false;
230 }
231
232 /**
233 * Checks the current user's permissions
234 *
235 * @since 3.1.0
236 * @abstract
237 */
238 public function ajax_user_can() {
239 die( 'function Tutor_List_Table::ajax_user_can() must be over-ridden in a sub-class.' );
240 }
241
242 /**
243 * Prepares the list of items for displaying.
244 * @uses Tutor_List_Table::set_pagination_args()
245 *
246 * @since 3.1.0
247 * @abstract
248 */
249 public function prepare_items() {
250 die( 'function Tutor_List_Table::prepare_items() must be over-ridden in a sub-class.' );
251 }
252
253 /**
254 * An internal method that sets all the necessary pagination arguments
255 *
256 * @since 3.1.0
257 *
258 * @param array|string $args Array or string of arguments with information about the pagination.
259 */
260 protected function set_pagination_args( $args ) {
261 $args = wp_parse_args( $args, array(
262 'total_items' => 0,
263 'total_pages' => 0,
264 'per_page' => 0,
265 ) );
266
267 if ( !$args['total_pages'] && $args['per_page'] > 0 )
268 $args['total_pages'] = ceil( $args['total_items'] / $args['per_page'] );
269
270 // Redirect if page number is invalid and headers are not already sent.
271 if ( ! headers_sent() && ! wp_doing_ajax() && $args['total_pages'] > 0 && $this->get_pagenum() > $args['total_pages'] ) {
272 wp_redirect( add_query_arg( 'paged', $args['total_pages'] ) );
273 exit;
274 }
275
276 $this->_pagination_args = $args;
277 }
278
279 /**
280 * Access the pagination args.
281 *
282 * @since 3.1.0
283 *
284 * @param string $key Pagination argument to retrieve. Common values include 'total_items',
285 * 'total_pages', 'per_page', or 'infinite_scroll'.
286 * @return int Number of items that correspond to the given pagination argument.
287 */
288 public function get_pagination_arg( $key ) {
289 if ( 'page' === $key ) {
290 return $this->get_pagenum();
291 }
292
293 if ( isset( $this->_pagination_args[$key] ) ) {
294 return $this->_pagination_args[$key];
295 }
296 }
297
298 /**
299 * Whether the table has items to display or not
300 *
301 * @since 3.1.0
302 *
303 * @return bool
304 */
305 public function has_items() {
306 return !empty( $this->items );
307 }
308
309 /**
310 * Message to be displayed when there are no items
311 *
312 * @since 3.1.0
313 */
314 public function no_items() {
315 _e( 'No items found.' );
316 }
317
318 /**
319 * Displays the search box.
320 *
321 * @since 3.1.0
322 *
323 * @param string $text The 'submit' button label.
324 * @param string $input_id ID attribute value for the search input field.
325 */
326 public function search_box( $text, $input_id ) {
327 if ( empty( $_REQUEST['s'] ) && !$this->has_items() )
328 return;
329
330 $input_id = $input_id . '-search-input';
331
332 if ( ! empty( $_REQUEST['orderby'] ) )
333 echo '<input type="hidden" name="orderby" value="' . esc_attr( $_REQUEST['orderby'] ) . '" />';
334 if ( ! empty( $_REQUEST['order'] ) )
335 echo '<input type="hidden" name="order" value="' . esc_attr( $_REQUEST['order'] ) . '" />';
336 if ( ! empty( $_REQUEST['post_mime_type'] ) )
337 echo '<input type="hidden" name="post_mime_type" value="' . esc_attr( $_REQUEST['post_mime_type'] ) . '" />';
338 if ( ! empty( $_REQUEST['detached'] ) )
339 echo '<input type="hidden" name="detached" value="' . esc_attr( $_REQUEST['detached'] ) . '" />';
340 ?>
341 <p class="search-box">
342 <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>"><?php echo $text; ?>:</label>
343 <input type="search" id="<?php echo esc_attr( $input_id ); ?>" name="s" value="<?php _admin_search_query(); ?>" />
344 <?php submit_button( $text, '', '', false, array( 'id' => 'search-submit' ) ); ?>
345 </p>
346 <?php
347 }
348
349 /**
350 * @since 1.8.0
351 * get course list
352 * @param $selected | optional
353 */
354 public function course_dropdown($selected = ''){
355 $courses = (current_user_can('administrator')) ? tutils()->get_courses() : tutils()->get_courses_by_instructor();
356 $markup = '
357 <div class="alignright">
358 <label>'.__('Course', 'tutor-pro').'</label>
359 <select class="tutor-assignment-course-sorting">
360 <option value="0">'.__('All','tutor').'</option>
361 OPTIONS_PLACEHOLDER
362 </select>
363 </div>
364 ';
365 $options = '';
366 foreach($courses as $course){
367 $options .= '<option value="'.$course->ID.'" '.selected($selected,$course->ID,false).'> '.$course->post_title.' </option>';
368 }
369
370 $content = str_replace('OPTIONS_PLACEHOLDER', $options, $markup);
371 echo $content;
372 }
373
374 /**
375 * @since 1.8.0
376 * get sort by param
377 * @param $selected | optional
378 */
379
380 public function sorting_order($selected='DESC'){
381 $orders = ['DESC','ASC'];
382 $markup = '
383 <div class="alignright">
384 <label>'.__('Sort By', 'tutor').'</label>
385 <select class="tutor-assignment-order-sorting">
386 OPTION_PLACEHOLDER
387 </select>
388 </div>
389 ';
390 $options = '';
391 foreach($orders as $order){
392 $options .= '<option value="'.$order.'" '.selected($selected,$order,false).'> '.__( $order, 'tutor' ).' </option>';
393 }
394 $content = str_replace('OPTION_PLACEHOLDER', $options, $markup);
395 echo $content;
396 }
397 /**
398 * @since 1.8.0
399 * get sort by param
400 * @param $selected | optional
401 */
402
403 public function sorting_date($selected = ''){
404 $placeholder = __( get_option( 'date_format' ), 'tutor' );
405 $markup = '
406 <div class="alignright assignment-date-box">
407 <label>'.__('Date', 'tutor').'</label>
408 <input type="" class="tutor_date_picker tutor-assignment-date-sorting" placeholder="'.$placeholder.'" value="'.$selected.'">
409 <i class="tutor-icon-calendar"></i>
410 </div>
411 ';
412 echo $markup;
413 }
414
415 /**
416 * Get an associative array ( id => link ) with the list
417 * of views available on this table.
418 *
419 * @since 3.1.0
420 *
421 * @return array
422 */
423 protected function get_views() {
424 return array();
425 }
426
427 /**
428 * Display the list of views available on this table.
429 *
430 * @since 3.1.0
431 */
432 public function views() {
433 $views = $this->get_views();
434 /**
435 * Filters the list of available list table views.
436 *
437 * The dynamic portion of the hook name, `$this->screen->id`, refers
438 * to the ID of the current screen, usually a string.
439 *
440 * @since 3.5.0
441 *
442 * @param array $views An array of available list table views.
443 */
444 $views = apply_filters( "views_{$this->screen->id}", $views );
445
446 if ( empty( $views ) )
447 return;
448
449 $this->screen->render_screen_reader_content( 'heading_views' );
450
451 echo "<ul class='subsubsub'>\n";
452 foreach ( $views as $class => $view ) {
453 $views[ $class ] = "\t<li class='$class'>$view";
454 }
455 echo implode( " |</li>\n", $views ) . "</li>\n";
456 echo "</ul>";
457 }
458
459 /**
460 * Get an associative array ( option_name => option_title ) with the list
461 * of bulk actions available on this table.
462 *
463 * @since 3.1.0
464 *
465 * @return array
466 */
467 protected function get_bulk_actions() {
468 return array();
469 }
470
471 /**
472 * Display the bulk actions dropdown.
473 *
474 * @since 3.1.0
475 *
476 * @param string $which The location of the bulk actions: 'top' or 'bottom'.
477 * This is designated as optional for backward compatibility.
478 */
479 protected function bulk_actions( $which = '' ) {
480 if ( is_null( $this->_actions ) ) {
481 $this->_actions = $this->get_bulk_actions();
482 /**
483 * Filters the list table Bulk Actions drop-down.
484 *
485 * The dynamic portion of the hook name, `$this->screen->id`, refers
486 * to the ID of the current screen, usually a string.
487 *
488 * This filter can currently only be used to remove bulk actions.
489 *
490 * @since 3.5.0
491 *
492 * @param array $actions An array of the available bulk actions.
493 */
494 $this->_actions = apply_filters( "bulk_actions-{$this->screen->id}", $this->_actions );
495 $two = '';
496 } else {
497 $two = '2';
498 }
499
500 if ( empty( $this->_actions ) )
501 return;
502
503 echo '<label for="bulk-action-selector-' . esc_attr( $which ) . '" class="screen-reader-text">' . __( 'Select bulk action' ) . '</label>';
504 echo '<select name="action' . $two . '" id="bulk-action-selector-' . esc_attr( $which ) . "\">\n";
505 echo '<option value="-1">' . __( 'Bulk Actions', 'tutor' ) . "</option>\n";
506
507 foreach ( $this->_actions as $name => $title ) {
508 $class = 'edit' === $name ? ' class="hide-if-no-js"' : '';
509
510 echo "\t" . '<option value="' . $name . '"' . $class . '>' . $title . "</option>\n";
511 }
512
513 echo "</select>\n";
514
515 submit_button( __( 'Apply' ), 'action', '', false, array( 'id' => "doaction$two" ) );
516 echo "\n";
517 }
518
519 /**
520 * Get the current action selected from the bulk actions dropdown.
521 *
522 * @since 3.1.0
523 *
524 * @return string|false The action name or False if no action was selected
525 */
526 public function current_action() {
527 if ( isset( $_REQUEST['filter_action'] ) && ! empty( $_REQUEST['filter_action'] ) )
528 return false;
529
530 if ( isset( $_REQUEST['action'] ) && -1 != $_REQUEST['action'] )
531 return $_REQUEST['action'];
532
533 if ( isset( $_REQUEST['action2'] ) && -1 != $_REQUEST['action2'] )
534 return $_REQUEST['action2'];
535
536 return false;
537 }
538
539 /**
540 * Generate row actions div
541 *
542 * @since 3.1.0
543 *
544 * @param array $actions The list of actions
545 * @param bool $always_visible Whether the actions should be always visible
546 * @return string
547 */
548 protected function row_actions( $actions, $always_visible = false ) {
549 $action_count = count( $actions );
550 $i = 0;
551
552 if ( !$action_count )
553 return '';
554
555 $out = '<div class="' . ( $always_visible ? 'row-actions visible' : 'row-actions' ) . '">';
556 foreach ( $actions as $action => $link ) {
557 ++$i;
558 ( $i == $action_count ) ? $sep = '' : $sep = ' | ';
559 $out .= "<span class='$action'>$link$sep</span>";
560 }
561 $out .= '</div>';
562
563 $out .= '<button type="button" class="toggle-row"><span class="screen-reader-text">' . __( 'Show more details' ) . '</span></button>';
564
565 return $out;
566 }
567
568 /**
569 * Display a monthly dropdown for filtering items
570 *
571 * @since 3.1.0
572 *
573 * @global wpdb $wpdb
574 * @global WP_Locale $wp_locale
575 *
576 * @param string $post_type
577 */
578 protected function months_dropdown( $post_type ) {
579 global $wpdb, $wp_locale;
580
581 /**
582 * Filters whether to remove the 'Months' drop-down from the post list table.
583 *
584 * @since 4.2.0
585 *
586 * @param bool $disable Whether to disable the drop-down. Default false.
587 * @param string $post_type The post type.
588 */
589 if ( apply_filters( 'disable_months_dropdown', false, $post_type ) ) {
590 return;
591 }
592
593 $extra_checks = "AND post_status != 'auto-draft'";
594 if ( ! isset( $_GET['post_status'] ) || 'trash' !== $_GET['post_status'] ) {
595 $extra_checks .= " AND post_status != 'trash'";
596 } elseif ( isset( $_GET['post_status'] ) ) {
597 $extra_checks = $wpdb->prepare( ' AND post_status = %s', $_GET['post_status'] );
598 }
599
600 $months = $wpdb->get_results( $wpdb->prepare( "
601 SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
602 FROM $wpdb->posts
603 WHERE post_type = %s
604 $extra_checks
605 ORDER BY post_date DESC
606 ", $post_type ) );
607
608 /**
609 * Filters the 'Months' drop-down results.
610 *
611 * @since 3.7.0
612 *
613 * @param object $months The months drop-down query results.
614 * @param string $post_type The post type.
615 */
616 $months = apply_filters( 'months_dropdown_results', $months, $post_type );
617
618 $month_count = count( $months );
619
620 if ( !$month_count || ( 1 == $month_count && 0 == $months[0]->month ) )
621 return;
622
623 $m = isset( $_GET['m'] ) ? (int) $_GET['m'] : 0;
624 ?>
625 <label for="filter-by-date" class="screen-reader-text"><?php _e( 'Filter by date' ); ?></label>
626 <select name="m" id="filter-by-date">
627 <option<?php selected( $m, 0 ); ?> value="0"><?php _e( 'All dates' ); ?></option>
628 <?php
629 foreach ( $months as $arc_row ) {
630 if ( 0 == $arc_row->year )
631 continue;
632
633 $month = zeroise( $arc_row->month, 2 );
634 $year = $arc_row->year;
635
636 printf( "<option %s value='%s'>%s</option>\n",
637 selected( $m, $year . $month, false ),
638 esc_attr( $arc_row->year . $month ),
639 /* translators: 1: month name, 2: 4-digit year */
640 sprintf( __( '%1$s %2$d' ), $wp_locale->get_month( $month ), $year )
641 );
642 }
643 ?>
644 </select>
645 <?php
646 }
647
648 /**
649 * Display a view switcher
650 *
651 * @since 3.1.0
652 *
653 * @param string $current_mode
654 */
655 protected function view_switcher( $current_mode ) {
656 ?>
657 <input type="hidden" name="mode" value="<?php echo esc_attr( $current_mode ); ?>" />
658 <div class="view-switch">
659 <?php
660 foreach ( $this->modes as $mode => $title ) {
661 $classes = array( 'view-' . $mode );
662 if ( $current_mode === $mode )
663 $classes[] = 'current';
664 printf(
665 "<a href='%s' class='%s' id='view-switch-$mode'><span class='screen-reader-text'>%s</span></a>\n",
666 esc_url( add_query_arg( 'mode', $mode ) ),
667 implode( ' ', $classes ),
668 $title
669 );
670 }
671 ?>
672 </div>
673 <?php
674 }
675
676 /**
677 * Display a comment count bubble
678 *
679 * @since 3.1.0
680 *
681 * @param int $post_id The post ID.
682 * @param int $pending_comments Number of pending comments.
683 */
684 protected function comments_bubble( $post_id, $pending_comments ) {
685 $approved_comments = get_comments_number();
686
687 $approved_comments_number = number_format_i18n( $approved_comments );
688 $pending_comments_number = number_format_i18n( $pending_comments );
689
690 $approved_only_phrase = sprintf( _n( '%s comment', '%s comments', $approved_comments ), $approved_comments_number );
691 $approved_phrase = sprintf( _n( '%s approved comment', '%s approved comments', $approved_comments ), $approved_comments_number );
692 $pending_phrase = sprintf( _n( '%s pending comment', '%s pending comments', $pending_comments ), $pending_comments_number );
693
694 // No comments at all.
695 if ( ! $approved_comments && ! $pending_comments ) {
696 printf( '<span aria-hidden="true">&#8212;</span><span class="screen-reader-text">%s</span>',
697 __( 'No comments' )
698 );
699 // Approved comments have different display depending on some conditions.
700 } elseif ( $approved_comments ) {
701 printf( '<a href="%s" class="post-com-count post-com-count-approved"><span class="comment-count-approved" aria-hidden="true">%s</span><span class="screen-reader-text">%s</span></a>',
702 esc_url( add_query_arg( array( 'p' => $post_id, 'comment_status' => 'approved' ), admin_url( 'edit-comments.php' ) ) ),
703 $approved_comments_number,
704 $pending_comments ? $approved_phrase : $approved_only_phrase
705 );
706 } else {
707 printf( '<span class="post-com-count post-com-count-no-comments"><span class="comment-count comment-count-no-comments" aria-hidden="true">%s</span><span class="screen-reader-text">%s</span></span>',
708 $approved_comments_number,
709 $pending_comments ? __( 'No approved comments' ) : __( 'No comments' )
710 );
711 }
712
713 if ( $pending_comments ) {
714 printf( '<a href="%s" class="post-com-count post-com-count-pending"><span class="comment-count-pending" aria-hidden="true">%s</span><span class="screen-reader-text">%s</span></a>',
715 esc_url( add_query_arg( array( 'p' => $post_id, 'comment_status' => 'moderated' ), admin_url( 'edit-comments.php' ) ) ),
716 $pending_comments_number,
717 $pending_phrase
718 );
719 } else {
720 printf( '<span class="post-com-count post-com-count-pending post-com-count-no-pending"><span class="comment-count comment-count-no-pending" aria-hidden="true">%s</span><span class="screen-reader-text">%s</span></span>',
721 $pending_comments_number,
722 $approved_comments ? __( 'No pending comments' ) : __( 'No comments' )
723 );
724 }
725 }
726
727 /**
728 * Get the current page number
729 *
730 * @since 3.1.0
731 *
732 * @return int
733 */
734 public function get_pagenum() {
735 $pagenum = isset( $_REQUEST['paged'] ) ? absint( $_REQUEST['paged'] ) : 0;
736
737 if ( isset( $this->_pagination_args['total_pages'] ) && $pagenum > $this->_pagination_args['total_pages'] )
738 $pagenum = $this->_pagination_args['total_pages'];
739
740 return max( 1, $pagenum );
741 }
742
743 /**
744 * Get number of items to display on a single page
745 *
746 * @since 3.1.0
747 *
748 * @param string $option
749 * @param int $default
750 * @return int
751 */
752 protected function get_items_per_page( $option, $default = 20 ) {
753 $per_page = (int) get_user_option( $option );
754 if ( empty( $per_page ) || $per_page < 1 )
755 $per_page = $default;
756
757 /**
758 * Filters the number of items to be displayed on each page of the list table.
759 *
760 * The dynamic hook name, $option, refers to the `per_page` option depending
761 * on the type of list table in use. Possible values include: 'edit_comments_per_page',
762 * 'sites_network_per_page', 'site_themes_network_per_page', 'themes_network_per_page',
763 * 'users_network_per_page', 'edit_post_per_page', 'edit_page_per_page',
764 * 'edit_{$post_type}_per_page', etc.
765 *
766 * @since 2.9.0
767 *
768 * @param int $per_page Number of items to be displayed. Default 20.
769 */
770 return (int) apply_filters( "{$option}", $per_page );
771 }
772
773 /**
774 * Display the pagination.
775 *
776 * @since 3.1.0
777 *
778 * @param string $which
779 */
780 protected function pagination( $which ) {
781 if ( empty( $this->_pagination_args ) ) {
782 return;
783 }
784
785 $total_items = $this->_pagination_args['total_items'];
786 $total_pages = $this->_pagination_args['total_pages'];
787 $infinite_scroll = false;
788 if ( isset( $this->_pagination_args['infinite_scroll'] ) ) {
789 $infinite_scroll = $this->_pagination_args['infinite_scroll'];
790 }
791
792 if ( 'top' === $which && $total_pages > 1 ) {
793 $this->screen->render_screen_reader_content( 'heading_pagination' );
794 }
795
796 $output = '<span class="displaying-num">' . sprintf( _n( '%s item', '%s items', $total_items ), number_format_i18n( $total_items ) ) . '</span>';
797
798 $current = $this->get_pagenum();
799 $removable_query_args = wp_removable_query_args();
800
801 $current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
802
803 $current_url = remove_query_arg( $removable_query_args, $current_url );
804
805 $page_links = array();
806
807 $total_pages_before = '<span class="paging-input">';
808 $total_pages_after = '</span></span>';
809
810 $disable_first = $disable_last = $disable_prev = $disable_next = false;
811
812 if ( $current == 1 ) {
813 $disable_first = true;
814 $disable_prev = true;
815 }
816 if ( $current == 2 ) {
817 $disable_first = true;
818 }
819 if ( $current == $total_pages ) {
820 $disable_last = true;
821 $disable_next = true;
822 }
823 if ( $current == $total_pages - 1 ) {
824 $disable_last = true;
825 }
826
827 if ( $disable_first ) {
828 $page_links[] = '<span class="tablenav-pages-navspan" aria-hidden="true">&laquo;</span>';
829 } else {
830 $page_links[] = sprintf( "<a class='first-page' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
831 esc_url( remove_query_arg( 'paged', $current_url ) ),
832 __( 'First page' ),
833 '&laquo;'
834 );
835 }
836
837 if ( $disable_prev ) {
838 $page_links[] = '<span class="tablenav-pages-navspan" aria-hidden="true">&lsaquo;</span>';
839 } else {
840 $page_links[] = sprintf( "<a class='prev-page' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
841 esc_url( add_query_arg( 'paged', max( 1, $current-1 ), $current_url ) ),
842 __( 'Previous page' ),
843 '&lsaquo;'
844 );
845 }
846
847 if ( 'bottom' === $which ) {
848 $html_current_page = $current;
849 $total_pages_before = '<span class="screen-reader-text">' . __( 'Current Page' ) . '</span><span id="table-paging" class="paging-input"><span class="tablenav-paging-text">';
850 } else {
851 $html_current_page = sprintf( "%s<input class='current-page' id='current-page-selector' type='text' name='paged' value='%s' size='%d' aria-describedby='table-paging' /><span class='tablenav-paging-text'>",
852 '<label for="current-page-selector" class="screen-reader-text">' . __( 'Current Page' ) . '</label>',
853 $current,
854 strlen( $total_pages )
855 );
856 }
857 $html_total_pages = sprintf( "<span class='total-pages'>%s</span>", number_format_i18n( $total_pages ) );
858 $page_links[] = $total_pages_before . sprintf( _x( '%1$s of %2$s', 'paging' ), $html_current_page, $html_total_pages ) . $total_pages_after;
859
860 if ( $disable_next ) {
861 $page_links[] = '<span class="tablenav-pages-navspan" aria-hidden="true">&rsaquo;</span>';
862 } else {
863 $page_links[] = sprintf( "<a class='next-page' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
864 esc_url( add_query_arg( 'paged', min( $total_pages, $current+1 ), $current_url ) ),
865 __( 'Next page' ),
866 '&rsaquo;'
867 );
868 }
869
870 if ( $disable_last ) {
871 $page_links[] = '<span class="tablenav-pages-navspan" aria-hidden="true">&raquo;</span>';
872 } else {
873 $page_links[] = sprintf( "<a class='last-page' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
874 esc_url( add_query_arg( 'paged', $total_pages, $current_url ) ),
875 __( 'Last page' ),
876 '&raquo;'
877 );
878 }
879
880 $pagination_links_class = 'pagination-links';
881 if ( ! empty( $infinite_scroll ) ) {
882 $pagination_links_class .= ' hide-if-js';
883 }
884 $output .= "\n<span class='$pagination_links_class'>" . join( "\n", $page_links ) . '</span>';
885
886 if ( $total_pages ) {
887 $page_class = $total_pages < 2 ? ' one-page' : '';
888 } else {
889 $page_class = ' no-pages';
890 }
891 $this->_pagination = "<div class='tablenav-pages{$page_class}'>$output</div>";
892
893 echo $this->_pagination;
894 }
895
896 /**
897 * Get a list of columns. The format is:
898 * 'internal-name' => 'Title'
899 *
900 * @since 3.1.0
901 * @abstract
902 *
903 * @return array
904 */
905 public function get_columns() {
906 die( 'function Tutor_List_Table::get_columns() must be over-ridden in a sub-class.' );
907 }
908
909 /**
910 * Get a list of sortable columns. The format is:
911 * 'internal-name' => 'orderby'
912 * or
913 * 'internal-name' => array( 'orderby', true )
914 *
915 * The second format will make the initial sorting order be descending
916 *
917 * @since 3.1.0
918 *
919 * @return array
920 */
921 protected function get_sortable_columns() {
922 return array();
923 }
924
925 /**
926 * Gets the name of the default primary column.
927 *
928 * @since 4.3.0
929 *
930 * @return string Name of the default primary column, in this case, an empty string.
931 */
932 protected function get_default_primary_column_name() {
933 $columns = $this->get_columns();
934 $column = '';
935
936 if ( empty( $columns ) ) {
937 return $column;
938 }
939
940 // We need a primary defined so responsive views show something,
941 // so let's fall back to the first non-checkbox column.
942 foreach ( $columns as $col => $column_name ) {
943 if ( 'cb' === $col ) {
944 continue;
945 }
946
947 $column = $col;
948 break;
949 }
950
951 return $column;
952 }
953
954 /**
955 * Public wrapper for Tutor_List_Table::get_default_primary_column_name().
956 *
957 * @since 4.4.0
958 *
959 * @return string Name of the default primary column.
960 */
961 public function get_primary_column() {
962 return $this->get_primary_column_name();
963 }
964
965 /**
966 * Gets the name of the primary column.
967 *
968 * @since 4.3.0
969 *
970 * @return string The name of the primary column.
971 */
972 protected function get_primary_column_name() {
973 $columns = get_column_headers( $this->screen );
974 $default = $this->get_default_primary_column_name();
975
976 // If the primary column doesn't exist fall back to the
977 // first non-checkbox column.
978 if ( ! isset( $columns[ $default ] ) ) {
979 $default = Tutor_List_Table::get_default_primary_column_name();
980 }
981
982 /**
983 * Filters the name of the primary column for the current list table.
984 *
985 * @since 4.3.0
986 *
987 * @param string $default Column name default for the specific list table, e.g. 'name'.
988 * @param string $context Screen ID for specific list table, e.g. 'plugins'.
989 */
990 $column = apply_filters( 'list_table_primary_column', $default, $this->screen->id );
991
992 if ( empty( $column ) || ! isset( $columns[ $column ] ) ) {
993 $column = $default;
994 }
995
996 return $column;
997 }
998
999 /**
1000 * Get a list of all, hidden and sortable columns, with filter applied
1001 *
1002 * @since 3.1.0
1003 *
1004 * @return array
1005 */
1006 protected function get_column_info() {
1007 // $_column_headers is already set / cached
1008 if ( isset( $this->_column_headers ) && is_array( $this->_column_headers ) ) {
1009 // Back-compat for list tables that have been manually setting $_column_headers for horse reasons.
1010 // In 4.3, we added a fourth argument for primary column.
1011 $column_headers = array( array(), array(), array(), $this->get_primary_column_name() );
1012 foreach ( $this->_column_headers as $key => $value ) {
1013 $column_headers[ $key ] = $value;
1014 }
1015
1016 return $column_headers;
1017 }
1018
1019 $columns = get_column_headers( $this->screen );
1020 $hidden = get_hidden_columns( $this->screen );
1021
1022 $sortable_columns = $this->get_sortable_columns();
1023 /**
1024 * Filters the list table sortable columns for a specific screen.
1025 *
1026 * The dynamic portion of the hook name, `$this->screen->id`, refers
1027 * to the ID of the current screen, usually a string.
1028 *
1029 * @since 3.5.0
1030 *
1031 * @param array $sortable_columns An array of sortable columns.
1032 */
1033 $_sortable = apply_filters( "manage_{$this->screen->id}_sortable_columns", $sortable_columns );
1034
1035 $sortable = array();
1036 foreach ( $_sortable as $id => $data ) {
1037 if ( empty( $data ) )
1038 continue;
1039
1040 $data = (array) $data;
1041 if ( !isset( $data[1] ) )
1042 $data[1] = false;
1043
1044 $sortable[$id] = $data;
1045 }
1046
1047 $primary = $this->get_primary_column_name();
1048 $this->_column_headers = array( $columns, $hidden, $sortable, $primary );
1049
1050 return $this->_column_headers;
1051 }
1052
1053 /**
1054 * Return number of visible columns
1055 *
1056 * @since 3.1.0
1057 *
1058 * @return int
1059 */
1060 public function get_column_count() {
1061 list ( $columns, $hidden ) = $this->get_column_info();
1062 $hidden = array_intersect( array_keys( $columns ), array_filter( $hidden ) );
1063 return count( $columns ) - count( $hidden );
1064 }
1065
1066 /**
1067 * Print column headers, accounting for hidden and sortable columns.
1068 *
1069 * @since 3.1.0
1070 *
1071 * @staticvar int $cb_counter
1072 *
1073 * @param bool $with_id Whether to set the id attribute or not
1074 */
1075 public function print_column_headers( $with_id = true ) {
1076 list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
1077
1078 $current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
1079 $current_url = remove_query_arg( 'paged', $current_url );
1080
1081 if ( isset( $_GET['orderby'] ) ) {
1082 $current_orderby = $_GET['orderby'];
1083 } else {
1084 $current_orderby = '';
1085 }
1086
1087 if ( isset( $_GET['order'] ) && 'desc' === $_GET['order'] ) {
1088 $current_order = 'desc';
1089 } else {
1090 $current_order = 'asc';
1091 }
1092
1093 if ( ! empty( $columns['cb'] ) ) {
1094 static $cb_counter = 1;
1095 $columns['cb'] = '<label class="screen-reader-text" for="cb-select-all-' . $cb_counter . '">' . __( 'Select All' ) . '</label>'
1096 . '<input id="cb-select-all-' . $cb_counter . '" type="checkbox" />';
1097 $cb_counter++;
1098 }
1099
1100 foreach ( $columns as $column_key => $column_display_name ) {
1101 $class = array( 'manage-column', "column-$column_key" );
1102
1103 if ( in_array( $column_key, $hidden ) ) {
1104 $class[] = 'hidden';
1105 }
1106
1107 if ( 'cb' === $column_key )
1108 $class[] = 'check-column';
1109 elseif ( in_array( $column_key, array( 'posts', 'comments', 'links' ) ) )
1110 $class[] = 'num';
1111
1112 if ( $column_key === $primary ) {
1113 $class[] = 'column-primary';
1114 }
1115
1116 if ( isset( $sortable[$column_key] ) ) {
1117 list( $orderby, $desc_first ) = $sortable[$column_key];
1118
1119 if ( $current_orderby === $orderby ) {
1120 $order = 'asc' === $current_order ? 'desc' : 'asc';
1121 $class[] = 'sorted';
1122 $class[] = $current_order;
1123 } else {
1124 $order = $desc_first ? 'desc' : 'asc';
1125 $class[] = 'sortable';
1126 $class[] = $desc_first ? 'asc' : 'desc';
1127 }
1128
1129 $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>';
1130 }
1131
1132 $tag = ( 'cb' === $column_key ) ? 'td' : 'th';
1133 $scope = ( 'th' === $tag ) ? 'scope="col"' : '';
1134 $id = $with_id ? "id='$column_key'" : '';
1135
1136 if ( !empty( $class ) )
1137 $class = "class='" . join( ' ', $class ) . "'";
1138
1139 echo "<$tag $scope $id $class>$column_display_name</$tag>";
1140 }
1141 }
1142
1143 /**
1144 * Display the table
1145 *
1146 * @since 3.1.0
1147 */
1148 public function display($enable_sorting_field_with_bulk_action = false) {
1149 $singular = $this->_args['singular'];
1150 if ( $enable_sorting_field_with_bulk_action ) {
1151 $this->display_sorting_fields( );
1152 } else {
1153 $this->display_tablenav('top');
1154 }
1155
1156 $this->screen->render_screen_reader_content( 'heading_list' );
1157 ?>
1158 <table class="wp-list-table <?php echo implode( ' ', $this->get_table_classes() ); ?>">
1159 <thead>
1160 <tr>
1161 <?php $this->print_column_headers(); ?>
1162 </tr>
1163 </thead>
1164
1165 <tbody id="the-list"<?php
1166 if ( $singular ) {
1167 echo " data-wp-lists='list:$singular'";
1168 } ?>>
1169 <?php $this->display_rows_or_placeholder(); ?>
1170 </tbody>
1171
1172 <tfoot>
1173 <tr>
1174 <?php $this->print_column_headers( false ); ?>
1175 </tr>
1176 </tfoot>
1177
1178 </table>
1179 <?php
1180 $this->display_tablenav( 'bottom' );
1181 }
1182
1183 /**
1184 * Get a list of CSS classes for the Tutor_List_Table table tag.
1185 *
1186 * @since 3.1.0
1187 *
1188 * @return array List of CSS classes for the table tag.
1189 */
1190 protected function get_table_classes() {
1191 return array( 'widefat', 'fixed', 'striped', $this->_args['plural'] );
1192 }
1193
1194 /**
1195 * Generate the table navigation above or below the table
1196 *
1197 * @since 3.1.0
1198 * @param string $which
1199 */
1200 protected function display_tablenav( $which ) {
1201 if ( 'top' === $which ) {
1202 wp_nonce_field( 'bulk-' . $this->_args['plural'] );
1203 }
1204 ?>
1205 <div class="tablenav <?php echo esc_attr( $which ); ?>">
1206
1207 <?php if ( $this->has_items() ): ?>
1208 <div class="alignleft actions bulkactions">
1209 <?php $this->bulk_actions( $which ); ?>
1210 </div>
1211 <?php endif;
1212 $this->extra_tablenav( $which );
1213 $this->pagination( $which );
1214 ?>
1215
1216 <br class="clear" />
1217 </div>
1218 <?php
1219 }
1220
1221 /**
1222 * Sorting fields added on tutor table
1223 *
1224 * Course id | Search | Date | Order
1225 *
1226 * @since 1.9.5
1227 */
1228 protected function display_sorting_fields() {
1229 $search_filter = isset( $_GET['search'] ) ? sanitize_text_field( $_GET['search'] ) : '';
1230 $course_id = isset( $_GET['course-id'] ) ? sanitize_text_field( $_GET['course-id'] ) : '';
1231 $date_filter = isset( $_GET['date'] ) ? sanitize_text_field( $_GET['date'] ) : '';
1232 $order_filter = isset( $_GET['order'] ) ? sanitize_text_field( $_GET['order'] ) : '';
1233 $which = 'top';
1234 ?>
1235 <div class="tutor-sorting-bulk-action-wrapper">
1236 <div class="tablenav <?php echo esc_attr( $which ); ?>">
1237 <?php if ( $this->has_items() ): ?>
1238 <div class="alignleft actions bulkactions">
1239 <?php $this->bulk_actions( $which ); ?>
1240 </div>
1241 <?php endif;
1242 $this->extra_tablenav( $which );
1243
1244 ?>
1245 </div>
1246
1247 <div class="tutor-admin-search-box-container" style="margin:0px;">
1248
1249 <div>
1250 <div class="menu-label"><?php _e('Courses', 'tutor'); ?></div>
1251 <div>
1252 <?php
1253 //get courses
1254 $courses = (current_user_can('administrator')) ? tutils()->get_courses() : tutils()->get_courses_by_instructor();
1255 ?>
1256
1257 <select class="tutor-report-category tutor-announcement-course-sorting">
1258
1259 <option value=""><?php _e('All', 'tutor'); ?></option>
1260
1261 <?php if ($courses) : ?>
1262 <?php foreach ($courses as $course) : ?>
1263 <option value="<?php echo esc_attr($course->ID) ?>" <?php selected($course_id, $course->ID, 'selected') ?>>
1264 <?php echo $course->post_title; ?>
1265 </option>
1266 <?php endforeach; ?>
1267 <?php else : ?>
1268 <option value=""><?php _e('No course found', 'tutor'); ?></option>
1269 <?php endif; ?>
1270 </select>
1271 </div>
1272 </div>
1273
1274 <div>
1275 <div class="menu-label"><?php _e('Sort By', 'tutor'); ?></div>
1276 <div>
1277 <select class="tutor-report-sort tutor-announcement-order-sorting">
1278 <option <?php selected($order_filter, 'ASC'); ?>>ASC</option>
1279 <option <?php selected($order_filter, 'DESC'); ?>>DESC</option>
1280 </select>
1281 </div>
1282 </div>
1283
1284 <div>
1285 <div class="menu-label"><?php _e('Date', 'tutor'); ?></div>
1286 <div class="date-range-input">
1287 <input type="text" class="tutor_date_picker tutor-announcement-date-sorting" id="tutor-announcement-datepicker" placeholder="<?php _e( get_option( 'date_format' ) , 'tutor' );?>" value="<?php echo $date_filter; ?>" autocomplete="off" />
1288 <i class="tutor-icon-calendar"></i>
1289 </div>
1290 </div>
1291
1292 <div class="tutor-search-form-group">
1293 <div class="menu-label"><?php _e('Search', 'tutor'); ?></div>
1294 <div style="position:relative;">
1295 <input type="text" name="search" class="tutor-report-search tutor-announcement-search-field" value="<?php echo $search_filter; ?>" autocomplete="off" placeholder="<?php _e('Search', 'tutor'); ?>" />
1296 <button class="tutor-report-search-btn tutor-announcement-search-sorting"><i class="tutor-icon-magnifying-glass-1"></i></button>
1297 </div>
1298 </div>
1299
1300 </div>
1301 </div>
1302 <?php
1303 }
1304
1305 /**
1306 * Extra controls to be displayed between bulk actions and pagination
1307 *
1308 * @since 3.1.0
1309 *
1310 * @param string $which
1311 */
1312 protected function extra_tablenav( $which ) {}
1313
1314 /**
1315 * Generate the tbody element for the list table.
1316 *
1317 * @since 3.1.0
1318 */
1319 public function display_rows_or_placeholder() {
1320 if ( $this->has_items() ) {
1321 $this->display_rows();
1322 } else {
1323 echo '<tr class="no-items"><td class="colspanchange" colspan="' . $this->get_column_count() . '">';
1324 $this->no_items();
1325 echo '</td></tr>';
1326 }
1327 }
1328
1329 /**
1330 * Generate the table rows
1331 *
1332 * @since 3.1.0
1333 */
1334 public function display_rows() {
1335 foreach ( $this->items as $item )
1336 $this->single_row( $item );
1337 }
1338
1339 /**
1340 * Generates content for a single row of the table
1341 *
1342 * @since 3.1.0
1343 *
1344 * @param object $item The current item
1345 */
1346 public function single_row( $item ) {
1347 echo '<tr>';
1348 $this->single_row_columns( $item );
1349 echo '</tr>';
1350 }
1351
1352 /**
1353 *
1354 * @param object $item
1355 * @param string $column_name
1356 */
1357 protected function column_default( $item, $column_name ) {}
1358
1359 /**
1360 *
1361 * @param object $item
1362 */
1363 protected function column_cb( $item ) {}
1364
1365 /**
1366 * Generates the columns for a single row of the table
1367 *
1368 * @since 3.1.0
1369 *
1370 * @param object $item The current item
1371 */
1372 protected function single_row_columns( $item ) {
1373 list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
1374
1375 foreach ( $columns as $column_name => $column_display_name ) {
1376 $classes = "$column_name column-$column_name";
1377 if ( $primary === $column_name ) {
1378 $classes .= ' has-row-actions column-primary';
1379 }
1380
1381 if ( in_array( $column_name, $hidden ) ) {
1382 $classes .= ' hidden';
1383 }
1384
1385 // Comments column uses HTML in the display name with screen reader text.
1386 // Instead of using esc_attr(), we strip tags to get closer to a user-friendly string.
1387 $data = 'data-colname="' . wp_strip_all_tags( $column_display_name ) . '"';
1388
1389 $attributes = "class='$classes' $data";
1390
1391 if ( 'cb' === $column_name ) {
1392 echo '<th scope="row" class="check-column">';
1393 echo $this->column_cb( $item );
1394 echo '</th>';
1395 } elseif ( method_exists( $this, '_column_' . $column_name ) ) {
1396 echo call_user_func(
1397 array( $this, '_column_' . $column_name ),
1398 $item,
1399 $classes,
1400 $data,
1401 $primary
1402 );
1403 } elseif ( method_exists( $this, 'column_' . $column_name ) ) {
1404 echo "<td $attributes>";
1405 echo call_user_func( array( $this, 'column_' . $column_name ), $item );
1406 echo $this->handle_row_actions( $item, $column_name, $primary );
1407 echo "</td>";
1408 } else {
1409 echo "<td $attributes>";
1410 echo $this->column_default( $item, $column_name );
1411 echo $this->handle_row_actions( $item, $column_name, $primary );
1412 echo "</td>";
1413 }
1414 }
1415 }
1416
1417 /**
1418 * Generates and display row actions links for the list table.
1419 *
1420 * @since 4.3.0
1421 *
1422 * @param object $item The item being acted upon.
1423 * @param string $column_name Current column name.
1424 * @param string $primary Primary column name.
1425 * @return string The row actions HTML, or an empty string if the current column is the primary column.
1426 */
1427 protected function handle_row_actions( $item, $column_name, $primary ) {
1428 return $column_name === $primary ? '<button type="button" class="toggle-row"><span class="screen-reader-text">' . __( 'Show more details' ) . '</span></button>' : '';
1429 }
1430
1431 /**
1432 * Handle an incoming ajax request (called from admin-ajax.php)
1433 *
1434 * @since 3.1.0
1435 */
1436 public function ajax_response() {
1437 $this->prepare_items();
1438
1439 ob_start();
1440 if ( ! empty( $_REQUEST['no_placeholder'] ) ) {
1441 $this->display_rows();
1442 } else {
1443 $this->display_rows_or_placeholder();
1444 }
1445
1446 $rows = ob_get_clean();
1447
1448 $response = array( 'rows' => $rows );
1449
1450 if ( isset( $this->_pagination_args['total_items'] ) ) {
1451 $response['total_items_i18n'] = sprintf(
1452 _n( '%s item', '%s items', $this->_pagination_args['total_items'] ),
1453 number_format_i18n( $this->_pagination_args['total_items'] )
1454 );
1455 }
1456 if ( isset( $this->_pagination_args['total_pages'] ) ) {
1457 $response['total_pages'] = $this->_pagination_args['total_pages'];
1458 $response['total_pages_i18n'] = number_format_i18n( $this->_pagination_args['total_pages'] );
1459 }
1460
1461 die( wp_json_encode( $response ) );
1462 }
1463
1464 /**
1465 * Send required variables to JavaScript land
1466 *
1467 */
1468 public function _js_vars() {
1469 $args = array(
1470 'class' => get_class( $this ),
1471 'screen' => array(
1472 'id' => $this->screen->id,
1473 'base' => $this->screen->base,
1474 )
1475 );
1476
1477 printf( "<script type='text/javascript'>list_args = %s;</script>\n", wp_json_encode( $args ) );
1478 }
1479 }
1480