Sensei_Learners_Main   D
last analyzed

Complexity

Total Complexity 83

Size/Duplication

Total Lines 644
Duplicated Lines 19.1 %

Coupling/Cohesion

Components 1
Dependencies 3
Metric Value
wmc 83
lcom 1
cbo 3
dl 123
loc 644
rs 4.6921

13 Methods

Rating   Name   Duplication   Size   Complexity  
A data_table_footer() 0 3 1
B __construct() 0 23 4
B get_columns() 14 36 5
B get_sortable_columns() 12 30 4
F prepare_items() 21 73 13
C get_row_data() 6 100 11
B get_courses() 0 27 3
B get_lessons() 26 26 3
C get_learners() 0 61 9
B no_items() 18 18 5
D data_table_header() 8 83 13
B add_learners_box() 0 55 9
A search_button() 18 18 3

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Sensei_Learners_Main often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Sensei_Learners_Main, and based on these observations, apply Extract Interface, too.

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 14 and the first side effect is on line 2.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
3
4
/**
5
 * Sensei Learners Overview List Table Class
6
 *
7
 * All functionality pertaining to the Admin Learners Overview Data Table in Sensei.
8
 *
9
 * @package Assessment
10
 * @author Automattic
11
 *
12
 * @since 1.3.0
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
	 * Constructor
23
	 * @since  1.6.0
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
		// Viewing a single lesson always sets the view to Learners
34
		if( $this->lesson_id ) {
35
			$this->view = 'learners';
36
		}
37
38
		// Load Parent token into constructor
39
		parent::__construct( 'learners_main' );
40
41
		// Actions
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
	} // End __construct()
48
49
	/**
50
	 * Define the columns that are going to be used in the table
51
	 * @since  1.7.0
52
	 * @return array $columns, the array of columns to use with the table
53
	 */
54
	function get_columns() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
55
		$columns = array();
0 ignored issues
show
Unused Code introduced by
$columns is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
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 View Code Duplication
			case 'lessons':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
			default:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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
		// Backwards compatible
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
	 * Define the columns that are going to be used in the table
93
	 * @since  1.7.0
94
	 * @return array $columns, the array of columns to use with the table
95
	 */
96
	function get_sortable_columns() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
97
		$columns = array();
0 ignored issues
show
Unused Code introduced by
$columns is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
98
		switch( $this->view ) {
99
			case 'learners':
100
				$columns = array(
101
					'title' => array( 'title', false ),
102
				);
103
				break;
104
105 View Code Duplication
			case 'lessons':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
106
				$columns = array(
107
					'title' => array( 'title', false ),
108
					'updated' => array( 'post_modified', false ),
109
				);
110
				break;
111
112 View Code Duplication
			default:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
113
				$columns = array(
114
					'title' => array( 'title', false ),
115
					'updated' => array( 'post_modified', false ),
116
				);
117
				break;
118
		}
119
		// Backwards compatible
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
	 * Prepare the table with different parameters, pagination, columns and table elements
129
	 * @since  1.7.0
130
	 * @return void
131
	 */
132
	public function prepare_items() {
133
		global $avail_stati, $wpdb, $per_page;
134
135
		// Handle orderby
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
			} // End If Statement
141
		}
142
143
		// Handle order
144
		$order = 'DESC';
145
		if ( !empty( $_GET['order'] ) ) {
146
			$order = ( 'ASC' == strtoupper($_GET['order']) ) ? 'ASC' : 'DESC';
147
		}
148
149
		// Handle category selection
150
		$category = false;
151
		if ( !empty( $_GET['course_cat'] ) ) {
152
			$category = intval( $_GET['course_cat'] );
153
		} // End If Statement
154
155
		// Handle search
156
		$search = false;
157
		if ( !empty( $_GET['s'] ) ) {
158
			$search = esc_html( $_GET['s'] );
159
		} // End If Statement
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
		} // End If Statement
169
170
		switch( $this->view ) {
171 View Code Duplication
			case 'learners':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
			case 'lessons':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
			default:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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
	} // End prepare_items()
205
206
	/**
207
	 * Generates content for a single row of the table in the user management
208
     * screen.
209
     *
210
	 * @since  1.7.0
211
     *
212
	 * @param object $item The current item
213
     *
214
     * @return void
215
	 */
216
	protected function get_row_data( $item ) {
217
		global $wp_version;
218
219
		switch ( $this->view ) {
220
			case 'learners' :
221
222
                // in this case the item passed in is actually the users activity on course of lesson
223
                $user_activity = $item;
224
				$post_id = false;
225
226
				if( $this->lesson_id ) {
227
228
					$post_id = intval( $this->lesson_id );
229
					$object_type = __( 'lesson', 'woothemes-sensei' );
230
					$post_type = 'lesson';
231
232
				} elseif( $this->course_id ) {
233
234
					$post_id = intval( $this->course_id );
235
					$object_type = __( 'course', 'woothemes-sensei' );
236
					$post_type = 'course';
237
238
				}
239
240
				if( 'complete' == $user_activity->comment_approved || 'graded' == $user_activity->comment_approved || 'passed' == $user_activity->comment_approved ) {
241
242
                    $status_html = '<span class="graded">' .__( 'Completed', 'woothemes-sensei' ) . '</span>';
243
244
				} else {
245
246
                    $status_html = '<span class="in-progress">' . __( 'In Progress', 'woothemes-sensei' ) . '</span>';
247
248
				}
249
250
                $title = Sensei_Learner::get_full_name( $user_activity->user_id );
251
				$a_title = sprintf( __( 'Edit &#8220;%s&#8221;' ), $title );
252
253
                /**
254
                 * sensei_learners_main_column_data filter
255
                 *
256
                 * This filter runs on the learner management screen for a specific course.
257
                 * It provides the learner row column details.
258
                 *
259
                 * @param array $columns{
260
                 *   type string $title
261
                 *   type string $date_started
262
                 *   type string $course_status (completed, started etc)
263
                 *   type html $action_buttons
264
                 * }
265
                 */
266
				$column_data = apply_filters( 'sensei_learners_main_column_data', array(
267
						'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>',
268
						'date_started' => get_comment_meta( $user_activity->comment_ID, 'start', true),
269
						'user_status' => $status_html,
270
						'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>',
271
					), $item, $post_id, $post_type );
272
273
				break;
274
275
			case 'lessons' :
276
				$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' ) ) );
277
				$title = get_the_title( $item );
278
				$a_title = sprintf( __( 'Edit &#8220;%s&#8221;' ), $title );
279
280
				$grading_action = '';
281 View Code Duplication
				if ( get_post_meta( $item->ID, '_quiz_has_questions', true ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
282
					$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>';
283
				}
284
285
				$column_data = apply_filters( 'sensei_learners_main_column_data', array(
286
						'title' => '<strong><a class="row-title" href="' . admin_url( 'post.php?action=edit&post=' . $item->ID ) . '" title="' . esc_attr( $a_title ) . '">' . $title . '</a></strong>',
287
						'num_learners' => $lesson_learners,
288
						'updated' => $item->post_modified,
289
						'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,
290
					), $item, $this->course_id );
291
				break;
292
293
			case 'courses' :
294
			default:
295
                $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' ) ) );
296
				$title = get_the_title( $item );
297
				$a_title = sprintf( __( 'Edit &#8220;%s&#8221;' ), $title );
298
299
				$grading_action = '';
300 View Code Duplication
				if ( version_compare($wp_version, '4.1', '>=') ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
301
					$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>';
302
				}
303
304
				$column_data = apply_filters( 'sensei_learners_main_column_data', array(
305
						'title' => '<strong><a class="row-title" href="' . admin_url( 'post.php?action=edit&post=' . $item->ID ) . '" title="' . esc_attr( $a_title ) . '">' . $title . '</a></strong>',
306
						'num_learners' => $course_learners,
307
						'updated' => $item->post_modified,
308
						'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,
309
					), $item );
310
311
				break;
312
		} // switch
313
314
		return $column_data;
315
	}
316
317
	/**
318
	 * Return array of course
319
	 * @since  1.7.0
320
	 * @return array courses
321
	 */
322
	private function get_courses( $args ) {
323
		$course_args = array(
324
			'post_type' => 'course',
325
			'post_status' => 'publish',
326
			'posts_per_page' => $args['per_page'],
327
			'offset' => $args['offset'],
328
			'orderby' => $args['orderby'],
329
			'order' => $args['order'],
330
		);
331
332
		if( $args['category'] ) {
333
			$course_args['tax_query'][] = array(
334
				'taxonomy' => 'course-category',
335
				'field' => 'id',
336
				'terms' => $args['category'],
337
			);
338
		}
339
340
		if( $args['search'] ) {
341
			$course_args['s'] = $args['search'];
342
		}
343
344
		$courses_query = new WP_Query( apply_filters( 'sensei_learners_filter_courses', $course_args ) );
345
346
		$this->total_items = $courses_query->found_posts;
347
		return $courses_query->posts;
348
	} // End get_courses()
349
350
	/**
351
	 * Return array of lessons
352
	 * @since  1.7.0
353
	 * @return array lessons
354
	 */
355 View Code Duplication
	private function get_lessons( $args ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
356
		$lesson_args = array(
357
			'post_type' => 'lesson',
358
			'post_status' => 'publish',
359
			'posts_per_page' => $args['per_page'],
360
			'offset' => $args['offset'],
361
			'orderby' => $args['orderby'],
362
			'order' => $args['order'],
363
		);
364
365
		if( $this->course_id ) {
366
			$lesson_args['meta_query'][] = array(
367
				'key' => '_lesson_course',
368
				'value' => $this->course_id,
369
			);
370
		}
371
372
		if( $args['search'] ) {
373
			$lesson_args['s'] = $args['search'];
374
		}
375
376
		$lessons_query = new WP_Query( apply_filters( 'sensei_learners_filter_lessons', $lesson_args ) );
377
378
		$this->total_items = $lessons_query->found_posts;
379
		return $lessons_query->posts;
380
	} // End get_lessons()
381
382
	/**
383
	 * Return array of learners
384
	 * @since  1.7.0
385
	 * @return array learners
386
	 */
387
	private function get_learners( $args ) {
388
389
		$user_ids = false;
0 ignored issues
show
Unused Code introduced by
$user_ids is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
390
		$post_id = 0;
391
		$activity = '';
392
393
		if( $this->lesson_id ) {
394
			$post_id = intval( $this->lesson_id );
395
			$activity = 'sensei_lesson_status';
396
		}
397
		elseif( $this->course_id ) {
398
			$post_id = intval( $this->course_id );
399
			$activity = 'sensei_course_status';
400
		}
401
402
		if( ! $post_id || ! $activity ) {
403
			$this->total_items = 0;
404
			return array();
405
		}
406
407
		$activity_args = array(
408
			'post_id' => $post_id,
409
			'type' => $activity,
410
			'status' => 'any',
411
			'number' => $args['per_page'],
412
			'offset' => $args['offset'],
413
			'orderby' => $args['orderby'],
414
			'order' => $args['order'],
415
			);
416
417
		// Searching users on statuses requires sub-selecting the statuses by user_ids
418
		if ( $args['search'] ) {
419
			$user_args = array(
420
				'search' => '*' . $args['search'] . '*',
421
				'fields' => 'ID'
422
			);
423
			// Filter for extending
424
			$user_args = apply_filters( 'sensei_learners_search_users', $user_args );
425
			if ( !empty( $user_args ) ) {
426
				$learners_search = new WP_User_Query( $user_args );
427
				$activity_args['user_id'] = $learners_search->get_results();
428
			}
429
		}
430
431
		$activity_args = apply_filters( 'sensei_learners_filter_users', $activity_args );
432
433
		// WP_Comment_Query doesn't support SQL_CALC_FOUND_ROWS, so instead do this twice
434
		$total_learners = Sensei_Utils::sensei_check_for_activity( array_merge( $activity_args, array('count' => true, 'offset' => 0, 'number' => 0) ) );
435
		// Ensure we change our range to fit (in case a search threw off the pagination) - Should this be added to all views?
436
		if ( $total_learners < $activity_args['offset'] ) {
437
			$new_paged = floor( $total_learners / $activity_args['number'] );
438
			$activity_args['offset'] = $new_paged * $activity_args['number'];
439
		}
440
		$learners = Sensei_Utils::sensei_check_for_activity( $activity_args, true );
441
		// Need to always return an array, even with only 1 item
442
		if ( !is_array($learners) ) {
443
			$learners = array( $learners );
444
		}
445
		$this->total_items = $total_learners;
446
		return $learners;
447
	} // End get_learners()
448
449
	/**
450
	 * Sets output when no items are found
451
	 * Overloads the parent method
452
	 * @since  1.6.0
453
	 * @return void
454
	 */
455 View Code Duplication
	public function no_items() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
456
		switch( $this->view ) {
457
			case 'learners' :
458
				$text = __( 'No learners found.', 'woothemes-sensei' );
459
				break;
460
461
			case 'lessons' :
462
				$text = __( 'No lessons found.', 'woothemes-sensei' );
463
				break;
464
465
			case 'courses':
466
			case 'default':
467
			default:
468
				$text = __( 'No courses found.', 'woothemes-sensei' );
469
				break;
470
		}
471
		echo apply_filters( 'sensei_learners_no_items_text', $text );
472
	} // End no_items()
473
474
	/**
475
	 * Output for table heading
476
	 * @since  1.6.0
477
	 * @return void
478
	 */
479
	public function data_table_header() {
480
481
		echo '<div class="learners-selects">';
482
		do_action( 'sensei_learners_before_dropdown_filters' );
483
484
		// Display Course Categories only on default view
485
		if( 'courses' == $this->view ) {
486
487
			$selected_cat = 0;
488
			if ( isset( $_GET['course_cat'] ) && '' != esc_html( $_GET['course_cat'] ) ) {
489
				$selected_cat = intval( $_GET['course_cat'] );
490
			}
491
492
			$cats = get_terms( 'course-category', array( 'hide_empty' => false ) );
493
494
			echo '<div class="select-box">' . "\n";
495
496
				echo '<select id="course-category-options" data-placeholder="' . __( 'Course Category', 'woothemes-sensei' ) . '" name="learners_course_cat" class="chosen_select widefat">' . "\n";
497
498
					echo '<option value="0">' . __( 'All Course Categories', 'woothemes-sensei' ) . '</option>' . "\n";
499
500
					foreach( $cats as $cat ) {
501
						echo '<option value="' . $cat->term_id . '"' . selected( $cat->term_id, $selected_cat, false ) . '>' . $cat->name . '</option>' . "\n";
502
					}
503
504
				echo '</select>' . "\n";
505
506
			echo '</div>' . "\n";
507
		}
508
		echo '</div><!-- /.learners-selects -->';
509
510
		$menu = array();
511
		// Have Course no Lesson
512
		if( $this->course_id && ! $this->lesson_id ) {
513
514
			$learners_class = $lessons_class = '';
515
			switch( $this->view ) {
516
				case 'learners':
517
					$learners_class = 'current';
518
				break;
519
520
				case 'lessons':
521
					$lessons_class = 'current';
522
				break;
523
			}
524
525
			$query_args = array(
526
				'page' => $this->page_slug,
527
				'course_id' => $this->course_id,
528
			);
529
530
			$learner_args = $lesson_args = $query_args;
531
			$learner_args['view'] = 'learners';
532
			$lesson_args['view'] = 'lessons';
533
534
			$menu['learners'] = '<a class="' . $learners_class . '" href="' . esc_url( add_query_arg( $learner_args, admin_url( 'admin.php' ) ) ) . '">' . __( 'Learners', 'woothemes-sensei' ) . '</a>';
535
			$menu['lessons'] = '<a class="' . $lessons_class . '" href="' . esc_url( add_query_arg( $lesson_args, admin_url( 'admin.php' ) ) ) . '">' . __( 'Lessons', 'woothemes-sensei' ) . '</a>';
536
537
		} 
538
		// Have Course and Lesson
539
		elseif( $this->course_id && $this->lesson_id ) {
540
541
			$query_args = array(
542
				'page' => $this->page_slug,
543
				'course_id' => $this->course_id,
544
				'view' => 'lessons'
545
			);
546
547
			$course = get_the_title( $this->course_id );
548
549
			$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>&larr; ', $course, '</em>' ) . '</a>';
550
		}
551
		$menu = apply_filters( 'sensei_learners_sub_menu', $menu );
552 View Code Duplication
		if ( !empty($menu) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
553
			echo '<ul class="subsubsub">' . "\n";
554
			foreach ( $menu as $class => $item ) {
555
				$menu[ $class ] = "\t<li class='$class'>$item";
556
			}
557
			echo implode( " |</li>\n", $menu ) . "</li>\n";
558
			echo '</ul>' . "\n";
559
		}
560
561
	} // End data_table_header()
562
563
	/**
564
	 * Output for table footer
565
	 * @since  1.6.0
566
	 * @return void
567
	 */
568
	public function data_table_footer() {
569
		// Nothing right now
570
	} // End data_table_footer()
571
572
	/**
573
	 * Add learners (to Course or Lesson) box to bottom of table display
574
	 * @since  1.6.0
575
	 * @return void
576
	 */
577
	public function add_learners_box() {
578
		$post_type = '';
579
		$post_title = '';
580
		$form_post_type = '';
581
		$form_course_id = 0;
582
		$form_lesson_id = 0;
583
		if( $this->course_id && ! $this->lesson_id ) {
584
			$post_title = get_the_title( $this->course_id );
585
			$post_type = __( 'Course', 'woothemes-sensei' );
586
			$form_post_type = 'course';
587
			$form_course_id = $this->course_id;
588
		}
589
		elseif( $this->course_id && $this->lesson_id ) {
590
			$post_title = get_the_title( $this->lesson_id );
591
			$post_type = __( 'Lesson', 'woothemes-sensei' );
592
			$form_post_type = 'lesson';
593
			$form_course_id = $this->course_id;
594
			$form_lesson_id = $this->lesson_id;
595
			$course_title = get_the_title( $this->course_id );
596
		}
597
		if ( empty($form_post_type) ) {
598
			return;
599
		}
600
		?>
601
		<div class="postbox">
602
			<h3><span><?php printf( __( 'Add Learner to %1$s', 'woothemes-sensei' ), $post_type ); ?></span></h3>
603
			<div class="inside">
604
				<form name="add_learner" action="" method="post">
605
					<p>
606
						<input name="add_user_id" placeholder="<?php _e( 'Find learner', 'woothemes-sensei' ) ;?>" id="add_learner_search" style="min-width:300px;" />
607
						<?php if( 'lesson' == $form_post_type ) { ?>
608
							<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>
609
						<?php } elseif( 'course' == $form_post_type ) { ?>
610
							<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>
611
						<?php } ?>
612
						<br/>
613
						<span class="description"><?php _e( 'Search for a user by typing their name or username.', 'woothemes-sensei' ); ?></span>
614
					</p>
615
					<p><?php submit_button( sprintf( __( 'Add to \'%1$s\'', 'woothemes-sensei' ), $post_title ), 'primary', 'add_learner_submit', false, array() ); ?></p>
616
					<?php if( 'lesson' == $form_post_type ) { ?>
617
						<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>
618
					<?php } ?>
619
620
					<input type="hidden" name="add_post_type" value="<?php echo $form_post_type; ?>" />
621
					<input type="hidden" name="add_course_id" value="<?php echo $form_course_id; ?>" />
622
					<input type="hidden" name="add_lesson_id" value="<?php echo $form_lesson_id; ?>" />
623
					<?php
624
						do_action( 'sensei_learners_add_learner_form' );
625
					?>
626
					<?php wp_nonce_field( 'add_learner_to_sensei', 'add_learner_nonce' ); ?>
627
				</form>
628
			</div>
629
		</div>
630
		<?php
631
	}
632
633
	/**
634
	 * The text for the search button
635
	 * @since  1.7.0
636
	 * @return string $text
637
	 */
638 View Code Duplication
	public function search_button( $text = '' ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
639
640
		switch( $this->view ) {
641
			case 'learners':
642
				$text = __( 'Search Learners', 'woothemes-sensei' );
643
			break;
644
645
			case 'lessons':
646
				$text = __( 'Search Lessons', 'woothemes-sensei' );
647
			break;
648
649
			default:
650
				$text = __( 'Search Courses', 'woothemes-sensei' );
651
			break;
652
		}
653
654
		return $text;
655
	}
656
657
} // End Class
658
659
/**
660
 * Class WooThemes_Sensei_Learners_Main
661
 * @ignore only for backward compatibility
662
 * @since 1.9.0
663
 */
664
class WooThemes_Sensei_Learners_Main extends Sensei_Learners_Main {}
665