PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 1.9.12
Tutor LMS – eLearning and online course solution v1.9.12
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 4 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 4 years ago Rewrite_Rules.php 4 years ago Shortcode.php 4 years ago Student.php 4 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 4 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
1482 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 $date_filter = sanitize_text_field( tutor_utils()->array_get( 'date', $_GET, '' ) );
406 $date_input = '' !== $date_filter ? tutor_get_formated_date( get_option( 'date_format' ), $date_filter ) : '';
407 $markup = '
408 <div class="alignright assignment-date-box">
409 <label>'.__('Date', 'tutor').'</label>
410 <input type="" class="tutor_date_picker tutor-assignment-date-sorting" placeholder="' . $placeholder . '" value="' . $date_input . '">
411 <i class="tutor-icon-calendar"></i>
412 </div>
413 ';
414 echo $markup;
415 }
416
417 /**
418 * Get an associative array ( id => link ) with the list
419 * of views available on this table.
420 *
421 * @since 3.1.0
422 *
423 * @return array
424 */
425 protected function get_views() {
426 return array();
427 }
428
429 /**
430 * Display the list of views available on this table.
431 *
432 * @since 3.1.0
433 */
434 public function views() {
435 $views = $this->get_views();
436 /**
437 * Filters the list of available list table views.
438 *
439 * The dynamic portion of the hook name, `$this->screen->id`, refers
440 * to the ID of the current screen, usually a string.
441 *
442 * @since 3.5.0
443 *
444 * @param array $views An array of available list table views.
445 */
446 $views = apply_filters( "views_{$this->screen->id}", $views );
447
448 if ( empty( $views ) )
449 return;
450
451 $this->screen->render_screen_reader_content( 'heading_views' );
452
453 echo "<ul class='subsubsub'>\n";
454 foreach ( $views as $class => $view ) {
455 $views[ $class ] = "\t<li class='$class'>$view";
456 }
457 echo implode( " |</li>\n", $views ) . "</li>\n";
458 echo "</ul>";
459 }
460
461 /**
462 * Get an associative array ( option_name => option_title ) with the list
463 * of bulk actions available on this table.
464 *
465 * @since 3.1.0
466 *
467 * @return array
468 */
469 protected function get_bulk_actions() {
470 return array();
471 }
472
473 /**
474 * Display the bulk actions dropdown.
475 *
476 * @since 3.1.0
477 *
478 * @param string $which The location of the bulk actions: 'top' or 'bottom'.
479 * This is designated as optional for backward compatibility.
480 */
481 protected function bulk_actions( $which = '' ) {
482 if ( is_null( $this->_actions ) ) {
483 $this->_actions = $this->get_bulk_actions();
484 /**
485 * Filters the list table Bulk Actions drop-down.
486 *
487 * The dynamic portion of the hook name, `$this->screen->id`, refers
488 * to the ID of the current screen, usually a string.
489 *
490 * This filter can currently only be used to remove bulk actions.
491 *
492 * @since 3.5.0
493 *
494 * @param array $actions An array of the available bulk actions.
495 */
496 $this->_actions = apply_filters( "bulk_actions-{$this->screen->id}", $this->_actions );
497 $two = '';
498 } else {
499 $two = '2';
500 }
501
502 if ( empty( $this->_actions ) )
503 return;
504
505 echo '<label for="bulk-action-selector-' . esc_attr( $which ) . '" class="screen-reader-text">' . __( 'Select bulk action' ) . '</label>';
506 echo '<select name="action' . $two . '" id="bulk-action-selector-' . esc_attr( $which ) . "\">\n";
507 echo '<option value="-1">' . __( 'Bulk Actions', 'tutor' ) . "</option>\n";
508
509 foreach ( $this->_actions as $name => $title ) {
510 $class = 'edit' === $name ? ' class="hide-if-no-js"' : '';
511
512 echo "\t" . '<option value="' . $name . '"' . $class . '>' . $title . "</option>\n";
513 }
514
515 echo "</select>\n";
516
517 submit_button( __( 'Apply' ), 'action', '', false, array( 'id' => "doaction$two" ) );
518 echo "\n";
519 }
520
521 /**
522 * Get the current action selected from the bulk actions dropdown.
523 *
524 * @since 3.1.0
525 *
526 * @return string|false The action name or False if no action was selected
527 */
528 public function current_action() {
529 if ( isset( $_REQUEST['filter_action'] ) && ! empty( $_REQUEST['filter_action'] ) )
530 return false;
531
532 if ( isset( $_REQUEST['action'] ) && -1 != $_REQUEST['action'] )
533 return $_REQUEST['action'];
534
535 if ( isset( $_REQUEST['action2'] ) && -1 != $_REQUEST['action2'] )
536 return $_REQUEST['action2'];
537
538 return false;
539 }
540
541 /**
542 * Generate row actions div
543 *
544 * @since 3.1.0
545 *
546 * @param array $actions The list of actions
547 * @param bool $always_visible Whether the actions should be always visible
548 * @return string
549 */
550 protected function row_actions( $actions, $always_visible = false ) {
551 $action_count = count( $actions );
552 $i = 0;
553
554 if ( !$action_count )
555 return '';
556
557 $out = '<div class="' . ( $always_visible ? 'row-actions visible' : 'row-actions' ) . '">';
558 foreach ( $actions as $action => $link ) {
559 ++$i;
560 ( $i == $action_count ) ? $sep = '' : $sep = ' | ';
561 $out .= "<span class='$action'>$link$sep</span>";
562 }
563 $out .= '</div>';
564
565 $out .= '<button type="button" class="toggle-row"><span class="screen-reader-text">' . __( 'Show more details' ) . '</span></button>';
566
567 return $out;
568 }
569
570 /**
571 * Display a monthly dropdown for filtering items
572 *
573 * @since 3.1.0
574 *
575 * @global wpdb $wpdb
576 * @global WP_Locale $wp_locale
577 *
578 * @param string $post_type
579 */
580 protected function months_dropdown( $post_type ) {
581 global $wpdb, $wp_locale;
582
583 /**
584 * Filters whether to remove the 'Months' drop-down from the post list table.
585 *
586 * @since 4.2.0
587 *
588 * @param bool $disable Whether to disable the drop-down. Default false.
589 * @param string $post_type The post type.
590 */
591 if ( apply_filters( 'disable_months_dropdown', false, $post_type ) ) {
592 return;
593 }
594
595 $extra_checks = "AND post_status != 'auto-draft'";
596 if ( ! isset( $_GET['post_status'] ) || 'trash' !== $_GET['post_status'] ) {
597 $extra_checks .= " AND post_status != 'trash'";
598 } elseif ( isset( $_GET['post_status'] ) ) {
599 $extra_checks = $wpdb->prepare( ' AND post_status = %s', $_GET['post_status'] );
600 }
601
602 $months = $wpdb->get_results( $wpdb->prepare( "
603 SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
604 FROM $wpdb->posts
605 WHERE post_type = %s
606 $extra_checks
607 ORDER BY post_date DESC
608 ", $post_type ) );
609
610 /**
611 * Filters the 'Months' drop-down results.
612 *
613 * @since 3.7.0
614 *
615 * @param object $months The months drop-down query results.
616 * @param string $post_type The post type.
617 */
618 $months = apply_filters( 'months_dropdown_results', $months, $post_type );
619
620 $month_count = count( $months );
621
622 if ( !$month_count || ( 1 == $month_count && 0 == $months[0]->month ) )
623 return;
624
625 $m = isset( $_GET['m'] ) ? (int) $_GET['m'] : 0;
626 ?>
627 <label for="filter-by-date" class="screen-reader-text"><?php _e( 'Filter by date' ); ?></label>
628 <select name="m" id="filter-by-date">
629 <option<?php selected( $m, 0 ); ?> value="0"><?php _e( 'All dates' ); ?></option>
630 <?php
631 foreach ( $months as $arc_row ) {
632 if ( 0 == $arc_row->year )
633 continue;
634
635 $month = zeroise( $arc_row->month, 2 );
636 $year = $arc_row->year;
637
638 printf( "<option %s value='%s'>%s</option>\n",
639 selected( $m, $year . $month, false ),
640 esc_attr( $arc_row->year . $month ),
641 /* translators: 1: month name, 2: 4-digit year */
642 sprintf( __( '%1$s %2$d' ), $wp_locale->get_month( $month ), $year )
643 );
644 }
645 ?>
646 </select>
647 <?php
648 }
649
650 /**
651 * Display a view switcher
652 *
653 * @since 3.1.0
654 *
655 * @param string $current_mode
656 */
657 protected function view_switcher( $current_mode ) {
658 ?>
659 <input type="hidden" name="mode" value="<?php echo esc_attr( $current_mode ); ?>" />
660 <div class="view-switch">
661 <?php
662 foreach ( $this->modes as $mode => $title ) {
663 $classes = array( 'view-' . $mode );
664 if ( $current_mode === $mode )
665 $classes[] = 'current';
666 printf(
667 "<a href='%s' class='%s' id='view-switch-$mode'><span class='screen-reader-text'>%s</span></a>\n",
668 esc_url( add_query_arg( 'mode', $mode ) ),
669 implode( ' ', $classes ),
670 $title
671 );
672 }
673 ?>
674 </div>
675 <?php
676 }
677
678 /**
679 * Display a comment count bubble
680 *
681 * @since 3.1.0
682 *
683 * @param int $post_id The post ID.
684 * @param int $pending_comments Number of pending comments.
685 */
686 protected function comments_bubble( $post_id, $pending_comments ) {
687 $approved_comments = get_comments_number();
688
689 $approved_comments_number = number_format_i18n( $approved_comments );
690 $pending_comments_number = number_format_i18n( $pending_comments );
691
692 $approved_only_phrase = sprintf( _n( '%s comment', '%s comments', $approved_comments ), $approved_comments_number );
693 $approved_phrase = sprintf( _n( '%s approved comment', '%s approved comments', $approved_comments ), $approved_comments_number );
694 $pending_phrase = sprintf( _n( '%s pending comment', '%s pending comments', $pending_comments ), $pending_comments_number );
695
696 // No comments at all.
697 if ( ! $approved_comments && ! $pending_comments ) {
698 printf( '<span aria-hidden="true">&#8212;</span><span class="screen-reader-text">%s</span>',
699 __( 'No comments' )
700 );
701 // Approved comments have different display depending on some conditions.
702 } elseif ( $approved_comments ) {
703 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>',
704 esc_url( add_query_arg( array( 'p' => $post_id, 'comment_status' => 'approved' ), admin_url( 'edit-comments.php' ) ) ),
705 $approved_comments_number,
706 $pending_comments ? $approved_phrase : $approved_only_phrase
707 );
708 } else {
709 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>',
710 $approved_comments_number,
711 $pending_comments ? __( 'No approved comments' ) : __( 'No comments' )
712 );
713 }
714
715 if ( $pending_comments ) {
716 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>',
717 esc_url( add_query_arg( array( 'p' => $post_id, 'comment_status' => 'moderated' ), admin_url( 'edit-comments.php' ) ) ),
718 $pending_comments_number,
719 $pending_phrase
720 );
721 } else {
722 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>',
723 $pending_comments_number,
724 $approved_comments ? __( 'No pending comments' ) : __( 'No comments' )
725 );
726 }
727 }
728
729 /**
730 * Get the current page number
731 *
732 * @since 3.1.0
733 *
734 * @return int
735 */
736 public function get_pagenum() {
737 $pagenum = isset( $_REQUEST['paged'] ) ? absint( $_REQUEST['paged'] ) : 0;
738
739 if ( isset( $this->_pagination_args['total_pages'] ) && $pagenum > $this->_pagination_args['total_pages'] )
740 $pagenum = $this->_pagination_args['total_pages'];
741
742 return max( 1, $pagenum );
743 }
744
745 /**
746 * Get number of items to display on a single page
747 *
748 * @since 3.1.0
749 *
750 * @param string $option
751 * @param int $default
752 * @return int
753 */
754 protected function get_items_per_page( $option, $default = 20 ) {
755 $per_page = (int) get_user_option( $option );
756 if ( empty( $per_page ) || $per_page < 1 )
757 $per_page = $default;
758
759 /**
760 * Filters the number of items to be displayed on each page of the list table.
761 *
762 * The dynamic hook name, $option, refers to the `per_page` option depending
763 * on the type of list table in use. Possible values include: 'edit_comments_per_page',
764 * 'sites_network_per_page', 'site_themes_network_per_page', 'themes_network_per_page',
765 * 'users_network_per_page', 'edit_post_per_page', 'edit_page_per_page',
766 * 'edit_{$post_type}_per_page', etc.
767 *
768 * @since 2.9.0
769 *
770 * @param int $per_page Number of items to be displayed. Default 20.
771 */
772 return (int) apply_filters( "{$option}", $per_page );
773 }
774
775 /**
776 * Display the pagination.
777 *
778 * @since 3.1.0
779 *
780 * @param string $which
781 */
782 protected function pagination( $which ) {
783 if ( empty( $this->_pagination_args ) ) {
784 return;
785 }
786
787 $total_items = $this->_pagination_args['total_items'];
788 $total_pages = $this->_pagination_args['total_pages'];
789 $infinite_scroll = false;
790 if ( isset( $this->_pagination_args['infinite_scroll'] ) ) {
791 $infinite_scroll = $this->_pagination_args['infinite_scroll'];
792 }
793
794 if ( 'top' === $which && $total_pages > 1 ) {
795 $this->screen->render_screen_reader_content( 'heading_pagination' );
796 }
797
798 $output = '<span class="displaying-num">' . sprintf( _n( '%s item', '%s items', $total_items ), number_format_i18n( $total_items ) ) . '</span>';
799
800 $current = $this->get_pagenum();
801 $removable_query_args = wp_removable_query_args();
802
803 $current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
804
805 $current_url = remove_query_arg( $removable_query_args, $current_url );
806
807 $page_links = array();
808
809 $total_pages_before = '<span class="paging-input">';
810 $total_pages_after = '</span></span>';
811
812 $disable_first = $disable_last = $disable_prev = $disable_next = false;
813
814 if ( $current == 1 ) {
815 $disable_first = true;
816 $disable_prev = true;
817 }
818 if ( $current == 2 ) {
819 $disable_first = true;
820 }
821 if ( $current == $total_pages ) {
822 $disable_last = true;
823 $disable_next = true;
824 }
825 if ( $current == $total_pages - 1 ) {
826 $disable_last = true;
827 }
828
829 if ( $disable_first ) {
830 $page_links[] = '<span class="tablenav-pages-navspan" aria-hidden="true">&laquo;</span>';
831 } else {
832 $page_links[] = sprintf( "<a class='first-page' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
833 esc_url( remove_query_arg( 'paged', $current_url ) ),
834 __( 'First page' ),
835 '&laquo;'
836 );
837 }
838
839 if ( $disable_prev ) {
840 $page_links[] = '<span class="tablenav-pages-navspan" aria-hidden="true">&lsaquo;</span>';
841 } else {
842 $page_links[] = sprintf( "<a class='prev-page' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
843 esc_url( add_query_arg( 'paged', max( 1, $current-1 ), $current_url ) ),
844 __( 'Previous page' ),
845 '&lsaquo;'
846 );
847 }
848
849 if ( 'bottom' === $which ) {
850 $html_current_page = $current;
851 $total_pages_before = '<span class="screen-reader-text">' . __( 'Current Page' ) . '</span><span id="table-paging" class="paging-input"><span class="tablenav-paging-text">';
852 } else {
853 $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'>",
854 '<label for="current-page-selector" class="screen-reader-text">' . __( 'Current Page' ) . '</label>',
855 $current,
856 strlen( $total_pages )
857 );
858 }
859 $html_total_pages = sprintf( "<span class='total-pages'>%s</span>", number_format_i18n( $total_pages ) );
860 $page_links[] = $total_pages_before . sprintf( _x( '%1$s of %2$s', 'paging' ), $html_current_page, $html_total_pages ) . $total_pages_after;
861
862 if ( $disable_next ) {
863 $page_links[] = '<span class="tablenav-pages-navspan" aria-hidden="true">&rsaquo;</span>';
864 } else {
865 $page_links[] = sprintf( "<a class='next-page' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
866 esc_url( add_query_arg( 'paged', min( $total_pages, $current+1 ), $current_url ) ),
867 __( 'Next page' ),
868 '&rsaquo;'
869 );
870 }
871
872 if ( $disable_last ) {
873 $page_links[] = '<span class="tablenav-pages-navspan" aria-hidden="true">&raquo;</span>';
874 } else {
875 $page_links[] = sprintf( "<a class='last-page' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
876 esc_url( add_query_arg( 'paged', $total_pages, $current_url ) ),
877 __( 'Last page' ),
878 '&raquo;'
879 );
880 }
881
882 $pagination_links_class = 'pagination-links';
883 if ( ! empty( $infinite_scroll ) ) {
884 $pagination_links_class .= ' hide-if-js';
885 }
886 $output .= "\n<span class='$pagination_links_class'>" . join( "\n", $page_links ) . '</span>';
887
888 if ( $total_pages ) {
889 $page_class = $total_pages < 2 ? ' one-page' : '';
890 } else {
891 $page_class = ' no-pages';
892 }
893 $this->_pagination = "<div class='tablenav-pages{$page_class}'>$output</div>";
894
895 echo $this->_pagination;
896 }
897
898 /**
899 * Get a list of columns. The format is:
900 * 'internal-name' => 'Title'
901 *
902 * @since 3.1.0
903 * @abstract
904 *
905 * @return array
906 */
907 public function get_columns() {
908 die( 'function Tutor_List_Table::get_columns() must be over-ridden in a sub-class.' );
909 }
910
911 /**
912 * Get a list of sortable columns. The format is:
913 * 'internal-name' => 'orderby'
914 * or
915 * 'internal-name' => array( 'orderby', true )
916 *
917 * The second format will make the initial sorting order be descending
918 *
919 * @since 3.1.0
920 *
921 * @return array
922 */
923 protected function get_sortable_columns() {
924 return array();
925 }
926
927 /**
928 * Gets the name of the default primary column.
929 *
930 * @since 4.3.0
931 *
932 * @return string Name of the default primary column, in this case, an empty string.
933 */
934 protected function get_default_primary_column_name() {
935 $columns = $this->get_columns();
936 $column = '';
937
938 if ( empty( $columns ) ) {
939 return $column;
940 }
941
942 // We need a primary defined so responsive views show something,
943 // so let's fall back to the first non-checkbox column.
944 foreach ( $columns as $col => $column_name ) {
945 if ( 'cb' === $col ) {
946 continue;
947 }
948
949 $column = $col;
950 break;
951 }
952
953 return $column;
954 }
955
956 /**
957 * Public wrapper for Tutor_List_Table::get_default_primary_column_name().
958 *
959 * @since 4.4.0
960 *
961 * @return string Name of the default primary column.
962 */
963 public function get_primary_column() {
964 return $this->get_primary_column_name();
965 }
966
967 /**
968 * Gets the name of the primary column.
969 *
970 * @since 4.3.0
971 *
972 * @return string The name of the primary column.
973 */
974 protected function get_primary_column_name() {
975 $columns = get_column_headers( $this->screen );
976 $default = $this->get_default_primary_column_name();
977
978 // If the primary column doesn't exist fall back to the
979 // first non-checkbox column.
980 if ( ! isset( $columns[ $default ] ) ) {
981 $default = Tutor_List_Table::get_default_primary_column_name();
982 }
983
984 /**
985 * Filters the name of the primary column for the current list table.
986 *
987 * @since 4.3.0
988 *
989 * @param string $default Column name default for the specific list table, e.g. 'name'.
990 * @param string $context Screen ID for specific list table, e.g. 'plugins'.
991 */
992 $column = apply_filters( 'list_table_primary_column', $default, $this->screen->id );
993
994 if ( empty( $column ) || ! isset( $columns[ $column ] ) ) {
995 $column = $default;
996 }
997
998 return $column;
999 }
1000
1001 /**
1002 * Get a list of all, hidden and sortable columns, with filter applied
1003 *
1004 * @since 3.1.0
1005 *
1006 * @return array
1007 */
1008 protected function get_column_info() {
1009 // $_column_headers is already set / cached
1010 if ( isset( $this->_column_headers ) && is_array( $this->_column_headers ) ) {
1011 // Back-compat for list tables that have been manually setting $_column_headers for horse reasons.
1012 // In 4.3, we added a fourth argument for primary column.
1013 $column_headers = array( array(), array(), array(), $this->get_primary_column_name() );
1014 foreach ( $this->_column_headers as $key => $value ) {
1015 $column_headers[ $key ] = $value;
1016 }
1017
1018 return $column_headers;
1019 }
1020
1021 $columns = get_column_headers( $this->screen );
1022 $hidden = get_hidden_columns( $this->screen );
1023
1024 $sortable_columns = $this->get_sortable_columns();
1025 /**
1026 * Filters the list table sortable columns for a specific screen.
1027 *
1028 * The dynamic portion of the hook name, `$this->screen->id`, refers
1029 * to the ID of the current screen, usually a string.
1030 *
1031 * @since 3.5.0
1032 *
1033 * @param array $sortable_columns An array of sortable columns.
1034 */
1035 $_sortable = apply_filters( "manage_{$this->screen->id}_sortable_columns", $sortable_columns );
1036
1037 $sortable = array();
1038 foreach ( $_sortable as $id => $data ) {
1039 if ( empty( $data ) )
1040 continue;
1041
1042 $data = (array) $data;
1043 if ( !isset( $data[1] ) )
1044 $data[1] = false;
1045
1046 $sortable[$id] = $data;
1047 }
1048
1049 $primary = $this->get_primary_column_name();
1050 $this->_column_headers = array( $columns, $hidden, $sortable, $primary );
1051
1052 return $this->_column_headers;
1053 }
1054
1055 /**
1056 * Return number of visible columns
1057 *
1058 * @since 3.1.0
1059 *
1060 * @return int
1061 */
1062 public function get_column_count() {
1063 list ( $columns, $hidden ) = $this->get_column_info();
1064 $hidden = array_intersect( array_keys( $columns ), array_filter( $hidden ) );
1065 return count( $columns ) - count( $hidden );
1066 }
1067
1068 /**
1069 * Print column headers, accounting for hidden and sortable columns.
1070 *
1071 * @since 3.1.0
1072 *
1073 * @staticvar int $cb_counter
1074 *
1075 * @param bool $with_id Whether to set the id attribute or not
1076 */
1077 public function print_column_headers( $with_id = true ) {
1078 list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
1079
1080 $current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
1081 $current_url = remove_query_arg( 'paged', $current_url );
1082
1083 if ( isset( $_GET['orderby'] ) ) {
1084 $current_orderby = $_GET['orderby'];
1085 } else {
1086 $current_orderby = '';
1087 }
1088
1089 if ( isset( $_GET['order'] ) && 'desc' === $_GET['order'] ) {
1090 $current_order = 'desc';
1091 } else {
1092 $current_order = 'asc';
1093 }
1094
1095 if ( ! empty( $columns['cb'] ) ) {
1096 static $cb_counter = 1;
1097 $columns['cb'] = '<label class="screen-reader-text" for="cb-select-all-' . $cb_counter . '">' . __( 'Select All' ) . '</label>'
1098 . '<input id="cb-select-all-' . $cb_counter . '" type="checkbox" />';
1099 $cb_counter++;
1100 }
1101
1102 foreach ( $columns as $column_key => $column_display_name ) {
1103 $class = array( 'manage-column', "column-$column_key" );
1104
1105 if ( in_array( $column_key, $hidden ) ) {
1106 $class[] = 'hidden';
1107 }
1108
1109 if ( 'cb' === $column_key )
1110 $class[] = 'check-column';
1111 elseif ( in_array( $column_key, array( 'posts', 'comments', 'links' ) ) )
1112 $class[] = 'num';
1113
1114 if ( $column_key === $primary ) {
1115 $class[] = 'column-primary';
1116 }
1117
1118 if ( isset( $sortable[$column_key] ) ) {
1119 list( $orderby, $desc_first ) = $sortable[$column_key];
1120
1121 if ( $current_orderby === $orderby ) {
1122 $order = 'asc' === $current_order ? 'desc' : 'asc';
1123 $class[] = 'sorted';
1124 $class[] = $current_order;
1125 } else {
1126 $order = $desc_first ? 'desc' : 'asc';
1127 $class[] = 'sortable';
1128 $class[] = $desc_first ? 'asc' : 'desc';
1129 }
1130
1131 $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>';
1132 }
1133
1134 $tag = ( 'cb' === $column_key ) ? 'td' : 'th';
1135 $scope = ( 'th' === $tag ) ? 'scope="col"' : '';
1136 $id = $with_id ? "id='$column_key'" : '';
1137
1138 if ( !empty( $class ) )
1139 $class = "class='" . join( ' ', $class ) . "'";
1140
1141 echo "<$tag $scope $id $class>$column_display_name</$tag>";
1142 }
1143 }
1144
1145 /**
1146 * Display the table
1147 *
1148 * @since 3.1.0
1149 */
1150 public function display($enable_sorting_field_with_bulk_action = false) {
1151 $singular = $this->_args['singular'];
1152 if ( $enable_sorting_field_with_bulk_action ) {
1153 $this->display_sorting_fields( );
1154 } else {
1155 $this->display_tablenav('top');
1156 }
1157
1158 $this->screen->render_screen_reader_content( 'heading_list' );
1159 ?>
1160 <table class="wp-list-table <?php echo implode( ' ', $this->get_table_classes() ); ?>">
1161 <thead>
1162 <tr>
1163 <?php $this->print_column_headers(); ?>
1164 </tr>
1165 </thead>
1166
1167 <tbody id="the-list"<?php
1168 if ( $singular ) {
1169 echo " data-wp-lists='list:$singular'";
1170 } ?>>
1171 <?php $this->display_rows_or_placeholder(); ?>
1172 </tbody>
1173
1174 <tfoot>
1175 <tr>
1176 <?php $this->print_column_headers( false ); ?>
1177 </tr>
1178 </tfoot>
1179
1180 </table>
1181 <?php
1182 $this->display_tablenav( 'bottom' );
1183 }
1184
1185 /**
1186 * Get a list of CSS classes for the Tutor_List_Table table tag.
1187 *
1188 * @since 3.1.0
1189 *
1190 * @return array List of CSS classes for the table tag.
1191 */
1192 protected function get_table_classes() {
1193 return array( 'widefat', 'fixed', 'striped', $this->_args['plural'] );
1194 }
1195
1196 /**
1197 * Generate the table navigation above or below the table
1198 *
1199 * @since 3.1.0
1200 * @param string $which
1201 */
1202 protected function display_tablenav( $which ) {
1203 if ( 'top' === $which ) {
1204 wp_nonce_field( 'bulk-' . $this->_args['plural'] );
1205 }
1206 ?>
1207 <div class="tablenav <?php echo esc_attr( $which ); ?>">
1208
1209 <?php if ( $this->has_items() ): ?>
1210 <div class="alignleft actions bulkactions">
1211 <?php $this->bulk_actions( $which ); ?>
1212 </div>
1213 <?php endif;
1214 $this->extra_tablenav( $which );
1215 $this->pagination( $which );
1216 ?>
1217
1218 <br class="clear" />
1219 </div>
1220 <?php
1221 }
1222
1223 /**
1224 * Sorting fields added on tutor table
1225 *
1226 * Course id | Search | Date | Order
1227 *
1228 * @since 1.9.5
1229 */
1230 protected function display_sorting_fields() {
1231 $search_filter = isset( $_GET['search'] ) ? sanitize_text_field( $_GET['search'] ) : '';
1232 $course_id = isset( $_GET['course-id'] ) ? sanitize_text_field( $_GET['course-id'] ) : '';
1233 $date_filter = isset( $_GET['date'] ) ? sanitize_text_field( $_GET['date'] ) : '';
1234 $order_filter = isset( $_GET['order'] ) ? sanitize_text_field( $_GET['order'] ) : '';
1235 $which = 'top';
1236 ?>
1237 <div class="tutor-sorting-bulk-action-wrapper">
1238 <div class="tablenav <?php echo esc_attr( $which ); ?>">
1239 <?php if ( $this->has_items() ): ?>
1240 <div class="alignleft actions bulkactions">
1241 <?php $this->bulk_actions( $which ); ?>
1242 </div>
1243 <?php endif;
1244 $this->extra_tablenav( $which );
1245
1246 ?>
1247 </div>
1248
1249 <div class="tutor-admin-search-box-container" style="margin:0px;">
1250
1251 <div>
1252 <div class="menu-label"><?php _e('Courses', 'tutor'); ?></div>
1253 <div>
1254 <?php
1255 //get courses
1256 $courses = (current_user_can('administrator')) ? tutils()->get_courses() : tutils()->get_courses_by_instructor();
1257 ?>
1258
1259 <select class="tutor-report-category tutor-announcement-course-sorting">
1260
1261 <option value=""><?php _e('All', 'tutor'); ?></option>
1262
1263 <?php if ($courses) : ?>
1264 <?php foreach ($courses as $course) : ?>
1265 <option value="<?php echo esc_attr($course->ID) ?>" <?php selected($course_id, $course->ID, 'selected') ?>>
1266 <?php echo $course->post_title; ?>
1267 </option>
1268 <?php endforeach; ?>
1269 <?php else : ?>
1270 <option value=""><?php _e('No course found', 'tutor'); ?></option>
1271 <?php endif; ?>
1272 </select>
1273 </div>
1274 </div>
1275
1276 <div>
1277 <div class="menu-label"><?php _e('Sort By', 'tutor'); ?></div>
1278 <div>
1279 <select class="tutor-report-sort tutor-announcement-order-sorting">
1280 <option <?php selected($order_filter, 'ASC'); ?>>ASC</option>
1281 <option <?php selected($order_filter, 'DESC'); ?>>DESC</option>
1282 </select>
1283 </div>
1284 </div>
1285
1286 <div>
1287 <div class="menu-label"><?php _e('Date', 'tutor'); ?></div>
1288 <div class="date-range-input">
1289 <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 ? tutor_get_formated_date( get_option( 'date_format' ), $date_filter ) : ''; ?>" autocomplete="off" />
1290 <i class="tutor-icon-calendar"></i>
1291 </div>
1292 </div>
1293
1294 <div class="tutor-search-form-group">
1295 <div class="menu-label"><?php _e('Search', 'tutor'); ?></div>
1296 <div style="position:relative;">
1297 <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'); ?>" />
1298 <button class="tutor-report-search-btn tutor-announcement-search-sorting"><i class="tutor-icon-magnifying-glass-1"></i></button>
1299 </div>
1300 </div>
1301
1302 </div>
1303 </div>
1304 <?php
1305 }
1306
1307 /**
1308 * Extra controls to be displayed between bulk actions and pagination
1309 *
1310 * @since 3.1.0
1311 *
1312 * @param string $which
1313 */
1314 protected function extra_tablenav( $which ) {}
1315
1316 /**
1317 * Generate the tbody element for the list table.
1318 *
1319 * @since 3.1.0
1320 */
1321 public function display_rows_or_placeholder() {
1322 if ( $this->has_items() ) {
1323 $this->display_rows();
1324 } else {
1325 echo '<tr class="no-items"><td class="colspanchange" colspan="' . $this->get_column_count() . '">';
1326 $this->no_items();
1327 echo '</td></tr>';
1328 }
1329 }
1330
1331 /**
1332 * Generate the table rows
1333 *
1334 * @since 3.1.0
1335 */
1336 public function display_rows() {
1337 foreach ( $this->items as $item )
1338 $this->single_row( $item );
1339 }
1340
1341 /**
1342 * Generates content for a single row of the table
1343 *
1344 * @since 3.1.0
1345 *
1346 * @param object $item The current item
1347 */
1348 public function single_row( $item ) {
1349 echo '<tr>';
1350 $this->single_row_columns( $item );
1351 echo '</tr>';
1352 }
1353
1354 /**
1355 *
1356 * @param object $item
1357 * @param string $column_name
1358 */
1359 protected function column_default( $item, $column_name ) {}
1360
1361 /**
1362 *
1363 * @param object $item
1364 */
1365 protected function column_cb( $item ) {}
1366
1367 /**
1368 * Generates the columns for a single row of the table
1369 *
1370 * @since 3.1.0
1371 *
1372 * @param object $item The current item
1373 */
1374 protected function single_row_columns( $item ) {
1375 list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
1376
1377 foreach ( $columns as $column_name => $column_display_name ) {
1378 $classes = "$column_name column-$column_name";
1379 if ( $primary === $column_name ) {
1380 $classes .= ' has-row-actions column-primary';
1381 }
1382
1383 if ( in_array( $column_name, $hidden ) ) {
1384 $classes .= ' hidden';
1385 }
1386
1387 // Comments column uses HTML in the display name with screen reader text.
1388 // Instead of using esc_attr(), we strip tags to get closer to a user-friendly string.
1389 $data = 'data-colname="' . wp_strip_all_tags( $column_display_name ) . '"';
1390
1391 $attributes = "class='$classes' $data";
1392
1393 if ( 'cb' === $column_name ) {
1394 echo '<th scope="row" class="check-column">';
1395 echo $this->column_cb( $item );
1396 echo '</th>';
1397 } elseif ( method_exists( $this, '_column_' . $column_name ) ) {
1398 echo call_user_func(
1399 array( $this, '_column_' . $column_name ),
1400 $item,
1401 $classes,
1402 $data,
1403 $primary
1404 );
1405 } elseif ( method_exists( $this, 'column_' . $column_name ) ) {
1406 echo "<td $attributes>";
1407 echo call_user_func( array( $this, 'column_' . $column_name ), $item );
1408 echo $this->handle_row_actions( $item, $column_name, $primary );
1409 echo "</td>";
1410 } else {
1411 echo "<td $attributes>";
1412 echo $this->column_default( $item, $column_name );
1413 echo $this->handle_row_actions( $item, $column_name, $primary );
1414 echo "</td>";
1415 }
1416 }
1417 }
1418
1419 /**
1420 * Generates and display row actions links for the list table.
1421 *
1422 * @since 4.3.0
1423 *
1424 * @param object $item The item being acted upon.
1425 * @param string $column_name Current column name.
1426 * @param string $primary Primary column name.
1427 * @return string The row actions HTML, or an empty string if the current column is the primary column.
1428 */
1429 protected function handle_row_actions( $item, $column_name, $primary ) {
1430 return $column_name === $primary ? '<button type="button" class="toggle-row"><span class="screen-reader-text">' . __( 'Show more details' ) . '</span></button>' : '';
1431 }
1432
1433 /**
1434 * Handle an incoming ajax request (called from admin-ajax.php)
1435 *
1436 * @since 3.1.0
1437 */
1438 public function ajax_response() {
1439 $this->prepare_items();
1440
1441 ob_start();
1442 if ( ! empty( $_REQUEST['no_placeholder'] ) ) {
1443 $this->display_rows();
1444 } else {
1445 $this->display_rows_or_placeholder();
1446 }
1447
1448 $rows = ob_get_clean();
1449
1450 $response = array( 'rows' => $rows );
1451
1452 if ( isset( $this->_pagination_args['total_items'] ) ) {
1453 $response['total_items_i18n'] = sprintf(
1454 _n( '%s item', '%s items', $this->_pagination_args['total_items'] ),
1455 number_format_i18n( $this->_pagination_args['total_items'] )
1456 );
1457 }
1458 if ( isset( $this->_pagination_args['total_pages'] ) ) {
1459 $response['total_pages'] = $this->_pagination_args['total_pages'];
1460 $response['total_pages_i18n'] = number_format_i18n( $this->_pagination_args['total_pages'] );
1461 }
1462
1463 die( wp_json_encode( $response ) );
1464 }
1465
1466 /**
1467 * Send required variables to JavaScript land
1468 *
1469 */
1470 public function _js_vars() {
1471 $args = array(
1472 'class' => get_class( $this ),
1473 'screen' => array(
1474 'id' => $this->screen->id,
1475 'base' => $this->screen->base,
1476 )
1477 );
1478
1479 printf( "<script type='text/javascript'>list_args = %s;</script>\n", wp_json_encode( $args ) );
1480 }
1481 }
1482