1: <?php
2: if ( ! defined( 'ABSPATH' ) ) exit;
3:
4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
14: class Sensei_Learners_Main extends WooThemes_Sensei_List_Table {
15:
16: public $course_id = 0;
17: public $lesson_id = 0;
18: public $view = 'courses';
19: public $page_slug = 'sensei_learners';
20:
21: 22: 23: 24:
25: public function __construct ( $course_id = 0, $lesson_id = 0 ) {
26: $this->course_id = intval( $course_id );
27: $this->lesson_id = intval( $lesson_id );
28:
29: if( isset( $_GET['view'] ) && in_array( $_GET['view'], array( 'courses', 'lessons', 'learners' ) ) ) {
30: $this->view = $_GET['view'];
31: }
32:
33:
34: if( $this->lesson_id ) {
35: $this->view = 'learners';
36: }
37:
38:
39: parent::__construct( 'learners_main' );
40:
41:
42: add_action( 'sensei_before_list_table', array( $this, 'data_table_header' ) );
43: add_action( 'sensei_after_list_table', array( $this, 'data_table_footer' ) );
44: add_action( 'sensei_learners_extra', array( $this, 'add_learners_box' ) );
45:
46: add_filter( 'sensei_list_table_search_button_text', array( $this, 'search_button' ) );
47: }
48:
49: 50: 51: 52: 53:
54: function get_columns() {
55: $columns = array();
56: switch( $this->view ) {
57: case 'learners':
58: $columns = array(
59: 'title' => __( 'Learner', 'woothemes-sensei' ),
60: 'date_started' => __( 'Date Started', 'woothemes-sensei' ),
61: 'user_status' => __( 'Status', 'woothemes-sensei' ),
62: );
63: break;
64:
65: case 'lessons':
66: $columns = array(
67: 'title' => __( 'Lesson', 'woothemes-sensei' ),
68: 'num_learners' => __( '# Learners', 'woothemes-sensei' ),
69: 'updated' => __( 'Last Updated', 'woothemes-sensei' ),
70: );
71: break;
72:
73: case 'courses':
74: default:
75: $columns = array(
76: 'title' => __( 'Course', 'woothemes-sensei' ),
77: 'num_learners' => __( '# Learners', 'woothemes-sensei' ),
78: 'updated' => __( 'Last Updated', 'woothemes-sensei' ),
79: );
80: break;
81: }
82: $columns['actions'] = '';
83:
84: if ( 'learners' == $this->view ) {
85: $columns = apply_filters( 'sensei_learners_learners_columns', $columns, $this );
86: }
87: $columns = apply_filters( 'sensei_learners_default_columns', $columns, $this );
88: return $columns;
89: }
90:
91: 92: 93: 94: 95:
96: function get_sortable_columns() {
97: $columns = array();
98: switch( $this->view ) {
99: case 'learners':
100: $columns = array(
101: 'title' => array( 'title', false ),
102: );
103: break;
104:
105: case 'lessons':
106: $columns = array(
107: 'title' => array( 'title', false ),
108: 'updated' => array( 'post_modified', false ),
109: );
110: break;
111:
112: default:
113: $columns = array(
114: 'title' => array( 'title', false ),
115: 'updated' => array( 'post_modified', false ),
116: );
117: break;
118: }
119:
120: if ( 'learners' == $this->view ) {
121: $columns = apply_filters( 'sensei_learners_learners_columns_sortable', $columns, $this );
122: }
123: $columns = apply_filters( 'sensei_learners_default_columns_sortable', $columns, $this );
124: return $columns;
125: }
126:
127: 128: 129: 130: 131:
132: public function prepare_items() {
133: global $avail_stati, $wpdb, $per_page;
134:
135:
136: $orderby = '';
137: if ( !empty( $_GET['orderby'] ) ) {
138: if ( array_key_exists( esc_html( $_GET['orderby'] ), $this->get_sortable_columns() ) ) {
139: $orderby = esc_html( $_GET['orderby'] );
140: }
141: }
142:
143:
144: $order = 'DESC';
145: if ( !empty( $_GET['order'] ) ) {
146: $order = ( 'ASC' == strtoupper($_GET['order']) ) ? 'ASC' : 'DESC';
147: }
148:
149:
150: $category = false;
151: if ( !empty( $_GET['course_cat'] ) ) {
152: $category = intval( $_GET['course_cat'] );
153: }
154:
155:
156: $search = false;
157: if ( !empty( $_GET['s'] ) ) {
158: $search = esc_html( $_GET['s'] );
159: }
160:
161: $per_page = $this->get_items_per_page( 'sensei_comments_per_page' );
162: $per_page = apply_filters( 'sensei_comments_per_page', $per_page, 'sensei_comments' );
163:
164: $paged = $this->get_pagenum();
165: $offset = 0;
166: if ( !empty($paged) ) {
167: $offset = $per_page * ( $paged - 1 );
168: }
169:
170: switch( $this->view ) {
171: case 'learners':
172: if ( empty($orderby) ) {
173: $orderby = '';
174: }
175: $this->items = $this->get_learners( compact( 'per_page', 'offset', 'orderby', 'order', 'search' ) );
176:
177: break;
178:
179: case 'lessons':
180: if ( empty($orderby) ) {
181: $orderby = 'post_modified';
182: }
183: $this->items = $this->get_lessons( compact( 'per_page', 'offset', 'orderby', 'order', 'search' ) );
184:
185: break;
186:
187: default:
188: if ( empty($orderby) ) {
189: $orderby = 'post_modified';
190: }
191: $this->items = $this->get_courses( compact( 'per_page', 'offset', 'orderby', 'order', 'category', 'search' ) );
192:
193: break;
194: }
195:
196: $total_items = $this->total_items;
197: $total_pages = ceil( $total_items / $per_page );
198: $this->set_pagination_args( array(
199: 'total_items' => $total_items,
200: 'total_pages' => $total_pages,
201: 'per_page' => $per_page
202: ) );
203:
204: }
205:
206: 207: 208: 209: 210: 211: 212: 213: 214: 215:
216: protected function get_row_data( $item ) {
217: global $wp_version;
218:
219: if( ! $item ) {
220: return array(
221: 'title' => __( 'No results found', 'woothemes-sensei' ),
222: 'num_learners' => '',
223: 'updated' => '',
224: 'actions' => '',
225: );
226: }
227: switch ( $this->view ) {
228: case 'learners' :
229:
230:
231: $user_activity = $item;
232: $post_id = false;
233:
234: if( $this->lesson_id ) {
235:
236: $post_id = intval( $this->lesson_id );
237: $object_type = __( 'lesson', 'woothemes-sensei' );
238: $post_type = 'lesson';
239:
240: } elseif( $this->course_id ) {
241:
242: $post_id = intval( $this->course_id );
243: $object_type = __( 'course', 'woothemes-sensei' );
244: $post_type = 'course';
245:
246: }
247:
248: if( 'complete' == $user_activity->comment_approved || 'graded' == $user_activity->comment_approved || 'passed' == $user_activity->comment_approved ) {
249:
250: $status_html = '<span class="graded">' .__( 'Completed', 'woothemes-sensei' ) . '</span>';
251:
252: } else {
253:
254: $status_html = '<span class="in-progress">' . __( 'In Progress', 'woothemes-sensei' ) . '</span>';
255:
256: }
257:
258: $title = Sensei_Learner::get_full_name( $user_activity->user_id );
259: $a_title = sprintf( __( 'Edit “%s”' ), $title );
260:
261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273:
274: $column_data = apply_filters( 'sensei_learners_main_column_data', array(
275: 'title' => '<strong><a class="row-title" href="' . admin_url( 'user-edit.php?user_id=' . $user_activity->user_id ) . '" title="' . esc_attr( $a_title ) . '">' . $title . '</a></strong>',
276: 'date_started' => get_comment_meta( $user_activity->comment_ID, 'start', true),
277: 'user_status' => $status_html,
278: 'actions' => '<a class="remove-learner button" data-user_id="' . $user_activity->user_id . '" data-post_id="' . $post_id . '" data-post_type="' . $post_type . '">' . sprintf( __( 'Remove from %1$s', 'woothemes-sensei' ), $object_type ) . '</a>',
279: ), $item, $post_id, $post_type );
280:
281: break;
282:
283: case 'lessons' :
284: $lesson_learners = Sensei_Utils::sensei_check_for_activity( apply_filters( 'sensei_learners_lesson_learners', array( 'post_id' => $item->ID, 'type' => 'sensei_lesson_status', 'status' => 'any' ) ) );
285: $title = get_the_title( $item );
286: $a_title = sprintf( __( 'Edit “%s”' ), $title );
287:
288: $grading_action = '';
289: if ( get_post_meta( $item->ID, '_quiz_has_questions', true ) ) {
290: $grading_action = ' <a class="button" href="' . esc_url( add_query_arg( array( 'page' => 'sensei_grading', 'lesson_id' => $item->ID, 'course_id' => $this->course_id ), admin_url( 'admin.php' ) ) ) . '">' . __( 'Grading', 'woothemes-sensei' ) . '</a>';
291: }
292:
293: $column_data = apply_filters( 'sensei_learners_main_column_data', array(
294: 'title' => '<strong><a class="row-title" href="' . admin_url( 'post.php?action=edit&post=' . $item->ID ) . '" title="' . esc_attr( $a_title ) . '">' . $title . '</a></strong>',
295: 'num_learners' => $lesson_learners,
296: 'updated' => $item->post_modified,
297: 'actions' => '<a class="button" href="' . esc_url( add_query_arg( array( 'page' => $this->page_slug, 'lesson_id' => $item->ID, 'course_id' => $this->course_id, 'view' => 'learners' ), admin_url( 'admin.php' ) ) ) . '">' . __( 'Manage learners', 'woothemes-sensei' ) . '</a> ' . $grading_action,
298: ), $item, $this->course_id );
299: break;
300:
301: case 'courses' :
302: default:
303: $course_learners = Sensei_Utils::sensei_check_for_activity( apply_filters( 'sensei_learners_course_learners', array( 'post_id' => $item->ID, 'type' => 'sensei_course_status', 'status' => 'any' ) ) );
304: $title = get_the_title( $item );
305: $a_title = sprintf( __( 'Edit “%s”' ), $title );
306:
307: $grading_action = '';
308: if ( version_compare($wp_version, '4.1', '>=') ) {
309: $grading_action = ' <a class="button" href="' . esc_url( add_query_arg( array( 'page' => 'sensei_grading', 'course_id' => $item->ID ), admin_url( 'admin.php' ) ) ) . '">' . __( 'Grading', 'woothemes-sensei' ) . '</a>';
310: }
311:
312: $column_data = apply_filters( 'sensei_learners_main_column_data', array(
313: 'title' => '<strong><a class="row-title" href="' . esc_url( add_query_arg( array( 'page' => 'sensei_learners', 'course_id' => $item->ID, 'view' => 'learners' ), admin_url( 'admin.php') ) ) . '" title="' . esc_attr( $a_title ) . '">' . $title . '</a></strong>',
314: 'num_learners' => $course_learners,
315: 'updated' => $item->post_modified,
316: 'actions' => '<a class="button" href="' . esc_url( add_query_arg( array( 'page' => $this->page_slug, 'course_id' => $item->ID, 'view' => 'learners' ), admin_url( 'admin.php' ) ) ) . '">' . __( 'Manage learners', 'woothemes-sensei' ) . '</a> ' . $grading_action,
317: ), $item );
318:
319: break;
320: }
321:
322: return $column_data;
323: }
324:
325: 326: 327: 328: 329:
330: private function get_courses( $args ) {
331: $course_args = array(
332: 'post_type' => 'course',
333: 'post_status' => 'publish',
334: 'posts_per_page' => $args['per_page'],
335: 'offset' => $args['offset'],
336: 'orderby' => $args['orderby'],
337: 'order' => $args['order'],
338: );
339:
340: if( $args['category'] ) {
341: $course_args['tax_query'][] = array(
342: 'taxonomy' => 'course-category',
343: 'field' => 'id',
344: 'terms' => $args['category'],
345: );
346: }
347:
348: if( $args['search'] ) {
349: $course_args['s'] = $args['search'];
350: }
351:
352: $courses_query = new WP_Query( apply_filters( 'sensei_learners_filter_courses', $course_args ) );
353:
354: $this->total_items = $courses_query->found_posts;
355: return $courses_query->posts;
356: }
357:
358: 359: 360: 361: 362:
363: private function get_lessons( $args ) {
364: $lesson_args = array(
365: 'post_type' => 'lesson',
366: 'post_status' => 'publish',
367: 'posts_per_page' => $args['per_page'],
368: 'offset' => $args['offset'],
369: 'orderby' => $args['orderby'],
370: 'order' => $args['order'],
371: );
372:
373: if( $this->course_id ) {
374: $lesson_args['meta_query'][] = array(
375: 'key' => '_lesson_course',
376: 'value' => $this->course_id,
377: );
378: }
379:
380: if( $args['search'] ) {
381: $lesson_args['s'] = $args['search'];
382: }
383:
384: $lessons_query = new WP_Query( apply_filters( 'sensei_learners_filter_lessons', $lesson_args ) );
385:
386: $this->total_items = $lessons_query->found_posts;
387: return $lessons_query->posts;
388: }
389:
390: 391: 392: 393: 394:
395: private function get_learners( $args ) {
396:
397: $user_ids = false;
398: $post_id = 0;
399: $activity = '';
400:
401: if( $this->lesson_id ) {
402: $post_id = intval( $this->lesson_id );
403: $activity = 'sensei_lesson_status';
404: }
405: elseif( $this->course_id ) {
406: $post_id = intval( $this->course_id );
407: $activity = 'sensei_course_status';
408: }
409:
410: if( ! $post_id || ! $activity ) {
411: $this->total_items = 0;
412: return array();
413: }
414:
415: $activity_args = array(
416: 'post_id' => $post_id,
417: 'type' => $activity,
418: 'status' => 'any',
419: 'number' => $args['per_page'],
420: 'offset' => $args['offset'],
421: 'orderby' => $args['orderby'],
422: 'order' => $args['order'],
423: );
424:
425:
426: if ( $args['search'] ) {
427: $user_args = array(
428: 'search' => '*' . $args['search'] . '*',
429: 'fields' => 'ID'
430: );
431:
432: $user_args = apply_filters( 'sensei_learners_search_users', $user_args );
433: if ( !empty( $user_args ) ) {
434: $learners_search = new WP_User_Query( $user_args );
435: $activity_args['user_id'] = $learners_search->get_results();
436: }
437: }
438:
439: $activity_args = apply_filters( 'sensei_learners_filter_users', $activity_args );
440:
441:
442: $total_learners = Sensei_Utils::sensei_check_for_activity( array_merge( $activity_args, array('count' => true, 'offset' => 0, 'number' => 0) ) );
443:
444: if ( $total_learners < $activity_args['offset'] ) {
445: $new_paged = floor( $total_learners / $activity_args['number'] );
446: $activity_args['offset'] = $new_paged * $activity_args['number'];
447: }
448: $learners = Sensei_Utils::sensei_check_for_activity( $activity_args, true );
449:
450: if ( !is_array($learners) ) {
451: $learners = array( $learners );
452: }
453: $this->total_items = $total_learners;
454: return $learners;
455: }
456:
457: 458: 459: 460: 461: 462:
463: public function no_items() {
464: switch( $this->view ) {
465: case 'learners' :
466: $text = __( 'No learners found.', 'woothemes-sensei' );
467: break;
468:
469: case 'lessons' :
470: $text = __( 'No lessons found.', 'woothemes-sensei' );
471: break;
472:
473: case 'courses':
474: case 'default':
475: default:
476: $text = __( 'No courses found.', 'woothemes-sensei' );
477: break;
478: }
479: echo apply_filters( 'sensei_learners_no_items_text', $text );
480: }
481:
482: 483: 484: 485: 486:
487: public function data_table_header() {
488:
489: echo '<div class="learners-selects">';
490: do_action( 'sensei_learners_before_dropdown_filters' );
491:
492:
493: if( 'courses' == $this->view ) {
494:
495: $selected_cat = 0;
496: if ( isset( $_GET['course_cat'] ) && '' != esc_html( $_GET['course_cat'] ) ) {
497: $selected_cat = intval( $_GET['course_cat'] );
498: }
499:
500: $cats = get_terms( 'course-category', array( 'hide_empty' => false ) );
501:
502: echo '<div class="select-box">' . "\n";
503:
504: echo '<select id="course-category-options" data-placeholder="' . __( 'Course Category', 'woothemes-sensei' ) . '" name="learners_course_cat" class="chosen_select widefat">' . "\n";
505:
506: echo '<option value="0">' . __( 'All Course Categories', 'woothemes-sensei' ) . '</option>' . "\n";
507:
508: foreach( $cats as $cat ) {
509: echo '<option value="' . $cat->term_id . '"' . selected( $cat->term_id, $selected_cat, false ) . '>' . $cat->name . '</option>' . "\n";
510: }
511:
512: echo '</select>' . "\n";
513:
514: echo '</div>' . "\n";
515: }
516: echo '</div><!-- /.learners-selects -->';
517:
518: $menu = array();
519:
520: if( $this->course_id && ! $this->lesson_id ) {
521:
522: $learners_class = $lessons_class = '';
523: switch( $this->view ) {
524: case 'learners':
525: $learners_class = 'current';
526: break;
527:
528: case 'lessons':
529: $lessons_class = 'current';
530: break;
531: }
532:
533: $query_args = array(
534: 'page' => $this->page_slug,
535: 'course_id' => $this->course_id,
536: );
537:
538: $learner_args = $lesson_args = $query_args;
539: $learner_args['view'] = 'learners';
540: $lesson_args['view'] = 'lessons';
541:
542: $menu['learners'] = '<a class="' . $learners_class . '" href="' . esc_url( add_query_arg( $learner_args, admin_url( 'admin.php' ) ) ) . '">' . __( 'Learners', 'woothemes-sensei' ) . '</a>';
543: $menu['lessons'] = '<a class="' . $lessons_class . '" href="' . esc_url( add_query_arg( $lesson_args, admin_url( 'admin.php' ) ) ) . '">' . __( 'Lessons', 'woothemes-sensei' ) . '</a>';
544:
545: }
546:
547: elseif( $this->course_id && $this->lesson_id ) {
548:
549: $query_args = array(
550: 'page' => $this->page_slug,
551: 'course_id' => $this->course_id,
552: 'view' => 'lessons'
553: );
554:
555: $course = get_the_title( $this->course_id );
556:
557: $menu['back'] = '<a href="' . esc_url( add_query_arg( $query_args, admin_url( 'admin.php' ) ) ) . '">' . sprintf( __( '%1$sBack to %2$s%3$s', 'woothemes-sensei' ), '<em>← ', $course, '</em>' ) . '</a>';
558: }
559: $menu = apply_filters( 'sensei_learners_sub_menu', $menu );
560: if ( !empty($menu) ) {
561: echo '<ul class="subsubsub">' . "\n";
562: foreach ( $menu as $class => $item ) {
563: $menu[ $class ] = "\t<li class='$class'>$item";
564: }
565: echo implode( " |</li>\n", $menu ) . "</li>\n";
566: echo '</ul>' . "\n";
567: }
568:
569: }
570:
571: 572: 573: 574: 575:
576: public function data_table_footer() {
577:
578: }
579:
580: 581: 582: 583: 584:
585: public function add_learners_box() {
586: $post_type = '';
587: $post_title = '';
588: $form_post_type = '';
589: $form_course_id = 0;
590: $form_lesson_id = 0;
591: if( $this->course_id && ! $this->lesson_id ) {
592: $post_title = get_the_title( $this->course_id );
593: $post_type = __( 'Course', 'woothemes-sensei' );
594: $form_post_type = 'course';
595: $form_course_id = $this->course_id;
596: }
597: elseif( $this->course_id && $this->lesson_id ) {
598: $post_title = get_the_title( $this->lesson_id );
599: $post_type = __( 'Lesson', 'woothemes-sensei' );
600: $form_post_type = 'lesson';
601: $form_course_id = $this->course_id;
602: $form_lesson_id = $this->lesson_id;
603: $course_title = get_the_title( $this->course_id );
604: }
605: if ( empty($form_post_type) ) {
606: return;
607: }
608: ?>
609: <div class="postbox">
610: <h3><span><?php printf( __( 'Add Learner to %1$s', 'woothemes-sensei' ), $post_type ); ?></span></h3>
611: <div class="inside">
612: <form name="add_learner" action="" method="post">
613: <p>
614: <input name="add_user_id" placeholder="<?php _e( 'Find learner', 'woothemes-sensei' ) ;?>" id="add_learner_search" style="min-width:300px;" />
615: <?php if( 'lesson' == $form_post_type ) { ?>
616: <label for="add_complete_lesson"><input type="checkbox" id="add_complete_lesson" name="add_complete_lesson" value="yes" /> <?php _e( 'Complete lesson for learner', 'woothemes-sensei' ); ?></label>
617: <?php } elseif( 'course' == $form_post_type ) { ?>
618: <label for="add_complete_course"><input type="checkbox" id="add_complete_course" name="add_complete_course" value="yes" /> <?php _e( 'Complete course for learner', 'woothemes-sensei' ); ?></label>
619: <?php } ?>
620: <br/>
621: <span class="description"><?php _e( 'Search for a user by typing their name or username.', 'woothemes-sensei' ); ?></span>
622: </p>
623: <p><?php submit_button( sprintf( __( 'Add to \'%1$s\'', 'woothemes-sensei' ), $post_title ), 'primary', 'add_learner_submit', false, array() ); ?></p>
624: <?php if( 'lesson' == $form_post_type ) { ?>
625: <p><span class="description"><?php printf( __( 'Learner will also be added to the course \'%1$s\' if they are not already taking it.', 'woothemes-sensei' ), $course_title ); ?></span></p>
626: <?php } ?>
627:
628: <input type="hidden" name="add_post_type" value="<?php echo $form_post_type; ?>" />
629: <input type="hidden" name="add_course_id" value="<?php echo $form_course_id; ?>" />
630: <input type="hidden" name="add_lesson_id" value="<?php echo $form_lesson_id; ?>" />
631: <?php
632: do_action( 'sensei_learners_add_learner_form' );
633: ?>
634: <?php wp_nonce_field( 'add_learner_to_sensei', 'add_learner_nonce' ); ?>
635: </form>
636: </div>
637: </div>
638: <?php
639: }
640:
641: 642: 643: 644: 645:
646: public function search_button( $text = '' ) {
647:
648: switch( $this->view ) {
649: case 'learners':
650: $text = __( 'Search Learners', 'woothemes-sensei' );
651: break;
652:
653: case 'lessons':
654: $text = __( 'Search Lessons', 'woothemes-sensei' );
655: break;
656:
657: default:
658: $text = __( 'Search Courses', 'woothemes-sensei' );
659: break;
660: }
661:
662: return $text;
663: }
664:
665: }
666:
667: 668: 669: 670: 671:
672: class WooThemes_Sensei_Learners_Main extends Sensei_Learners_Main {}
673: