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