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