Completed
Push — master ( be9484...2a1678 )
by Dwain
04:58
created

Sensei_Learners_Main::get_row_data()   C

Complexity

Conditions 11
Paths 12

Size

Total Lines 100
Code Lines 57

Duplication

Lines 6
Ratio 6 %
Metric Value
dl 6
loc 100
rs 5.2653
cc 11
eloc 57
nc 12
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
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 WordPress
10
 * @subpackage Sensei
11
 * @category Core
12
 * @author WooThemes
13
 * @since 1.3.0
14
 */
15
class Sensei_Learners_Main extends WooThemes_Sensei_List_Table {
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
	 * @return  void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
25
	 */
26
	public function __construct ( $course_id = 0, $lesson_id = 0 ) {
27
		$this->course_id = intval( $course_id );
28
		$this->lesson_id = intval( $lesson_id );
29
30
		if( isset( $_GET['view'] ) && in_array( $_GET['view'], array( 'courses', 'lessons', 'learners' ) ) ) {
31
			$this->view = $_GET['view'];
32
		}
33
34
		// Viewing a single lesson always sets the view to Learners
35
		if( $this->lesson_id ) {
36
			$this->view = 'learners';
37
		}
38
39
		// Load Parent token into constructor
40
		parent::__construct( 'learners_main' );
41
42
		// Actions
43
		add_action( 'sensei_before_list_table', array( $this, 'data_table_header' ) );
44
		add_action( 'sensei_after_list_table', array( $this, 'data_table_footer' ) );
45
		add_action( 'sensei_learners_extra', array( $this, 'add_learners_box' ) );
46
47
		add_filter( 'sensei_list_table_search_button_text', array( $this, 'search_button' ) );
48
	} // End __construct()
49
50
	/**
51
	 * Define the columns that are going to be used in the table
52
	 * @since  1.7.0
53
	 * @return array $columns, the array of columns to use with the table
54
	 */
55
	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...
56
		$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...
57
		switch( $this->view ) {
58
			case 'learners':
59
				$columns = array(
60
					'title' => __( 'Learner', 'woothemes-sensei' ),
61
					'date_started' => __( 'Date Started', 'woothemes-sensei' ),
62
					'user_status' => __( 'Status', 'woothemes-sensei' ),
63
				);
64
				break;
65
66 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...
67
				$columns = array(
68
					'title' => __( 'Lesson', 'woothemes-sensei' ),
69
					'num_learners' => __( '# Learners', 'woothemes-sensei' ),
70
					'updated' => __( 'Last Updated', 'woothemes-sensei' ),
71
				);
72
				break;
73
74
			case 'courses':
75 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...
76
				$columns = array(
77
					'title' => __( 'Course', 'woothemes-sensei' ),
78
					'num_learners' => __( '# Learners', 'woothemes-sensei' ),
79
					'updated' => __( 'Last Updated', 'woothemes-sensei' ),
80
				);
81
				break;
82
		}
83
		$columns['actions'] = '';
84
		// Backwards compatible
85
		if ( 'learners' == $this->view ) {
86
			$columns = apply_filters( 'sensei_learners_learners_columns', $columns, $this );
87
		}
88
		$columns = apply_filters( 'sensei_learners_default_columns', $columns, $this );
89
		return $columns;
90
	}
91
92
	/**
93
	 * Define the columns that are going to be used in the table
94
	 * @since  1.7.0
95
	 * @return array $columns, the array of columns to use with the table
96
	 */
97
	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...
98
		$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...
99
		switch( $this->view ) {
100
			case 'learners':
101
				$columns = array(
102
					'title' => array( 'title', false ),
103
				);
104
				break;
105
106 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...
107
				$columns = array(
108
					'title' => array( 'title', false ),
109
					'updated' => array( 'post_modified', false ),
110
				);
111
				break;
112
113 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...
114
				$columns = array(
115
					'title' => array( 'title', false ),
116
					'updated' => array( 'post_modified', false ),
117
				);
118
				break;
119
		}
120
		// Backwards compatible
121
		if ( 'learners' == $this->view ) {
122
			$columns = apply_filters( 'sensei_learners_learners_columns_sortable', $columns, $this );
123
		}
124
		$columns = apply_filters( 'sensei_learners_default_columns_sortable', $columns, $this );
125
		return $columns;
126
	}
127
128
	/**
129
	 * Prepare the table with different parameters, pagination, columns and table elements
130
	 * @since  1.7.0
131
	 * @return void
132
	 */
133
	public function prepare_items() {
134
		global $avail_stati, $wpdb, $per_page;
135
136
		// Handle orderby
137
		$orderby = '';
138
		if ( !empty( $_GET['orderby'] ) ) {
139
			if ( array_key_exists( esc_html( $_GET['orderby'] ), $this->get_sortable_columns() ) ) {
140
				$orderby = esc_html( $_GET['orderby'] );
141
			} // End If Statement
142
		}
143
144
		// Handle order
145
		$order = 'DESC';
146
		if ( !empty( $_GET['order'] ) ) {
147
			$order = ( 'ASC' == strtoupper($_GET['order']) ) ? 'ASC' : 'DESC';
148
		}
149
150
		// Handle category selection
151
		$category = false;
152
		if ( !empty( $_GET['course_cat'] ) ) {
153
			$category = intval( $_GET['course_cat'] );
154
		} // End If Statement
155
156
		// Handle search
157
		$search = false;
158
		if ( !empty( $_GET['s'] ) ) {
159
			$search = esc_html( $_GET['s'] );
160
		} // End If Statement
161
162
		$per_page = $this->get_items_per_page( 'sensei_comments_per_page' );
163
		$per_page = apply_filters( 'sensei_comments_per_page', $per_page, 'sensei_comments' );
164
165
		$paged = $this->get_pagenum();
166
		$offset = 0;
167
		if ( !empty($paged) ) {
168
			$offset = $per_page * ( $paged - 1 );
169
		} // End If Statement
170
171
		switch( $this->view ) {
172 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...
173
				if ( empty($orderby) ) {
174
					$orderby = '';
175
				}
176
				$this->items = $this->get_learners( compact( 'per_page', 'offset', 'orderby', 'order', 'search' ) );
177
178
			break;
179
180 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...
181
				if ( empty($orderby) ) {
182
					$orderby = 'post_modified';
183
				}
184
				$this->items = $this->get_lessons( compact( 'per_page', 'offset', 'orderby', 'order', 'search' ) );
185
186
			break;
187
188 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...
189
				if ( empty($orderby) ) {
190
					$orderby = 'post_modified';
191
				}
192
				$this->items = $this->get_courses( compact( 'per_page', 'offset', 'orderby', 'order', 'category', 'search' ) );
193
194
			break;
195
		}
196
197
		$total_items = $this->total_items;
198
		$total_pages = ceil( $total_items / $per_page );
199
		$this->set_pagination_args( array(
200
			'total_items' => $total_items,
201
			'total_pages' => $total_pages,
202
			'per_page' => $per_page
203
		) );
204
205
	} // End prepare_items()
206
207
	/**
208
	 * Generates content for a single row of the table in the user management
209
     * screen.
210
     *
211
	 * @since  1.7.0
212
     *
213
	 * @param object $item The current item
214
     *
215
     * @return void
216
	 */
217
	protected function get_row_data( $item ) {
218
		global $wp_version;
219
220
		switch ( $this->view ) {
221
			case 'learners' :
222
223
                // in this case the item passed in is actually the users activity on course of lesson
224
                $user_activity = $item;
225
				$post_id = false;
226
227
				if( $this->lesson_id ) {
228
229
					$post_id = intval( $this->lesson_id );
230
					$object_type = __( 'lesson', 'woothemes-sensei' );
231
					$post_type = 'lesson';
232
233
				} elseif( $this->course_id ) {
234
235
					$post_id = intval( $this->course_id );
236
					$object_type = __( 'course', 'woothemes-sensei' );
237
					$post_type = 'course';
238
239
				}
240
241
				if( 'complete' == $user_activity->comment_approved || 'graded' == $user_activity->comment_approved || 'passed' == $user_activity->comment_approved ) {
242
243
                    $status_html = '<span class="graded">' .__( 'Completed', 'woothemes-sensei' ) . '</span>';
244
245
				} else {
246
247
                    $status_html = '<span class="in-progress">' . __( 'In Progress', 'woothemes-sensei' ) . '</span>';
248
249
				}
250
251
                $title = Sensei_Student::get_full_name( $user_activity->user_id );
252
				$a_title = sprintf( __( 'Edit &#8220;%s&#8221;' ), $title );
253
254
                /**
255
                 * sensei_learners_main_column_data filter
256
                 *
257
                 * This filter runs on the learner management screen for a specific course.
258
                 * It provides the learner row column details.
259
                 *
260
                 * @param array $columns{
261
                 *   type string $title
262
                 *   type string $date_started
263
                 *   type string $course_status (completed, started etc)
264
                 *   type html $action_buttons
265
                 * }
266
                 */
267
				$column_data = apply_filters( 'sensei_learners_main_column_data', array(
268
						'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>',
269
						'date_started' => get_comment_meta( $user_activity->comment_ID, 'start', true),
270
						'user_status' => $status_html,
271
						'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>',
0 ignored issues
show
Bug introduced by
The variable $post_type does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $object_type does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
272
					), $item, $post_id, $post_type );
273
274
				break;
275
276
			case 'lessons' :
277
				$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' ) ) );
278
				$title = get_the_title( $item );
279
				$a_title = sprintf( __( 'Edit &#8220;%s&#8221;' ), $title );
280
281
				$grading_action = '';
282 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...
283
					$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>';
284
				}
285
286
				$column_data = apply_filters( 'sensei_learners_main_column_data', array(
287
						'title' => '<strong><a class="row-title" href="' . admin_url( 'post.php?action=edit&post=' . $item->ID ) . '" title="' . esc_attr( $a_title ) . '">' . $title . '</a></strong>',
288
						'num_learners' => $lesson_learners,
289
						'updated' => $item->post_modified,
290
						'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,
291
					), $item, $this->course_id );
292
				break;
293
294
			case 'courses' :
295
			default:
296
                $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' ) ) );
297
				$title = get_the_title( $item );
298
				$a_title = sprintf( __( 'Edit &#8220;%s&#8221;' ), $title );
299
300
				$grading_action = '';
301 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...
302
					$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>';
303
				}
304
305
				$column_data = apply_filters( 'sensei_learners_main_column_data', array(
306
						'title' => '<strong><a class="row-title" href="' . admin_url( 'post.php?action=edit&post=' . $item->ID ) . '" title="' . esc_attr( $a_title ) . '">' . $title . '</a></strong>',
307
						'num_learners' => $course_learners,
308
						'updated' => $item->post_modified,
309
						'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,
310
					), $item );
311
312
				break;
313
		} // switch
314
315
		return $column_data;
316
	}
317
318
	/**
319
	 * Return array of course
320
	 * @since  1.7.0
321
	 * @return array courses
322
	 */
323
	private function get_courses( $args ) {
324
		$course_args = array(
325
			'post_type' => 'course',
326
			'post_status' => 'publish',
327
			'posts_per_page' => $args['per_page'],
328
			'offset' => $args['offset'],
329
			'orderby' => $args['orderby'],
330
			'order' => $args['order'],
331
		);
332
333
		if( $args['category'] ) {
334
			$course_args['tax_query'][] = array(
335
				'taxonomy' => 'course-category',
336
				'field' => 'id',
337
				'terms' => $args['category'],
338
			);
339
		}
340
341
		if( $args['search'] ) {
342
			$course_args['s'] = $args['search'];
343
		}
344
345
		$courses_query = new WP_Query( apply_filters( 'sensei_learners_filter_courses', $course_args ) );
346
347
		$this->total_items = $courses_query->found_posts;
348
		return $courses_query->posts;
349
	} // End get_courses()
350
351
	/**
352
	 * Return array of lessons
353
	 * @since  1.7.0
354
	 * @return array lessons
355
	 */
356 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...
357
		$lesson_args = array(
358
			'post_type' => 'lesson',
359
			'post_status' => 'publish',
360
			'posts_per_page' => $args['per_page'],
361
			'offset' => $args['offset'],
362
			'orderby' => $args['orderby'],
363
			'order' => $args['order'],
364
		);
365
366
		if( $this->course_id ) {
367
			$lesson_args['meta_query'][] = array(
368
				'key' => '_lesson_course',
369
				'value' => $this->course_id,
370
			);
371
		}
372
373
		if( $args['search'] ) {
374
			$lesson_args['s'] = $args['search'];
375
		}
376
377
		$lessons_query = new WP_Query( apply_filters( 'sensei_learners_filter_lessons', $lesson_args ) );
378
379
		$this->total_items = $lessons_query->found_posts;
380
		return $lessons_query->posts;
381
	} // End get_lessons()
382
383
	/**
384
	 * Return array of learners
385
	 * @since  1.7.0
386
	 * @return array learners
387
	 */
388
	private function get_learners( $args ) {
389
390
		$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...
391
		$post_id = 0;
392
		$activity = '';
393
394
		if( $this->lesson_id ) {
395
			$post_id = intval( $this->lesson_id );
396
			$activity = 'sensei_lesson_status';
397
		}
398
		elseif( $this->course_id ) {
399
			$post_id = intval( $this->course_id );
400
			$activity = 'sensei_course_status';
401
		}
402
403
		if( ! $post_id || ! $activity ) {
404
			$this->total_items = 0;
405
			return array();
406
		}
407
408
		$activity_args = array(
409
			'post_id' => $post_id,
410
			'type' => $activity,
411
			'status' => 'any',
412
			'number' => $args['per_page'],
413
			'offset' => $args['offset'],
414
			'orderby' => $args['orderby'],
415
			'order' => $args['order'],
416
			);
417
418
		// Searching users on statuses requires sub-selecting the statuses by user_ids
419
		if ( $args['search'] ) {
420
			$user_args = array(
421
				'search' => '*' . $args['search'] . '*',
422
				'fields' => 'ID'
423
			);
424
			// Filter for extending
425
			$user_args = apply_filters( 'sensei_learners_search_users', $user_args );
426
			if ( !empty( $user_args ) ) {
427
				$learners_search = new WP_User_Query( $user_args );
428
				$activity_args['user_id'] = $learners_search->get_results();
429
			}
430
		}
431
432
		$activity_args = apply_filters( 'sensei_learners_filter_users', $activity_args );
433
434
		// WP_Comment_Query doesn't support SQL_CALC_FOUND_ROWS, so instead do this twice
435
		$total_learners = Sensei_Utils::sensei_check_for_activity( array_merge( $activity_args, array('count' => true, 'offset' => 0, 'number' => 0) ) );
436
		// Ensure we change our range to fit (in case a search threw off the pagination) - Should this be added to all views?
437
		if ( $total_learners < $activity_args['offset'] ) {
438
			$new_paged = floor( $total_learners / $activity_args['number'] );
439
			$activity_args['offset'] = $new_paged * $activity_args['number'];
440
		}
441
		$learners = Sensei_Utils::sensei_check_for_activity( $activity_args, true );
442
		// Need to always return an array, even with only 1 item
443
		if ( !is_array($learners) ) {
444
			$learners = array( $learners );
445
		}
446
		$this->total_items = $total_learners;
447
		return $learners;
448
	} // End get_learners()
449
450
	/**
451
	 * Sets output when no items are found
452
	 * Overloads the parent method
453
	 * @since  1.6.0
454
	 * @return void
455
	 */
456 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...
457
		switch( $this->view ) {
458
			case 'learners' :
459
				$text = __( 'No learners found.', 'woothemes-sensei' );
460
				break;
461
462
			case 'lessons' :
463
				$text = __( 'No lessons found.', 'woothemes-sensei' );
464
				break;
465
466
			case 'courses':
467
			case 'default':
468
			default:
469
				$text = __( 'No courses found.', 'woothemes-sensei' );
470
				break;
471
		}
472
		echo apply_filters( 'sensei_learners_no_items_text', $text );
473
	} // End no_items()
474
475
	/**
476
	 * Output for table heading
477
	 * @since  1.6.0
478
	 * @return void
479
	 */
480
	public function data_table_header() {
481
482
		echo '<div class="learners-selects">';
483
		do_action( 'sensei_learners_before_dropdown_filters' );
484
485
		// Display Course Categories only on default view
486
		if( 'courses' == $this->view ) {
487
488
			$selected_cat = 0;
489
			if ( isset( $_GET['course_cat'] ) && '' != esc_html( $_GET['course_cat'] ) ) {
490
				$selected_cat = intval( $_GET['course_cat'] );
491
			}
492
493
			$cats = get_terms( 'course-category', array( 'hide_empty' => false ) );
494
495
			echo '<div class="select-box">' . "\n";
496
497
				echo '<select id="course-category-options" data-placeholder="' . __( 'Course Category', 'woothemes-sensei' ) . '" name="learners_course_cat" class="chosen_select widefat">' . "\n";
498
499
					echo '<option value="0">' . __( 'All Course Categories', 'woothemes-sensei' ) . '</option>' . "\n";
500
501
					foreach( $cats as $cat ) {
502
						echo '<option value="' . $cat->term_id . '"' . selected( $cat->term_id, $selected_cat, false ) . '>' . $cat->name . '</option>' . "\n";
503
					}
504
505
				echo '</select>' . "\n";
506
507
			echo '</div>' . "\n";
508
		}
509
		echo '</div><!-- /.learners-selects -->';
510
511
		$menu = array();
512
		// Have Course no Lesson
513
		if( $this->course_id && ! $this->lesson_id ) {
514
515
			$learners_class = $lessons_class = '';
516
			switch( $this->view ) {
517
				case 'learners':
518
					$learners_class = 'current';
519
				break;
520
521
				case 'lessons':
522
					$lessons_class = 'current';
523
				break;
524
			}
525
526
			$query_args = array(
527
				'page' => $this->page_slug,
528
				'course_id' => $this->course_id,
529
			);
530
531
			$learner_args = $lesson_args = $query_args;
532
			$learner_args['view'] = 'learners';
533
			$lesson_args['view'] = 'lessons';
534
535
			$menu['learners'] = '<a class="' . $learners_class . '" href="' . esc_url( add_query_arg( $learner_args, admin_url( 'admin.php' ) ) ) . '">' . __( 'Learners', 'woothemes-sensei' ) . '</a>';
536
			$menu['lessons'] = '<a class="' . $lessons_class . '" href="' . esc_url( add_query_arg( $lesson_args, admin_url( 'admin.php' ) ) ) . '">' . __( 'Lessons', 'woothemes-sensei' ) . '</a>';
537
538
		} 
539
		// Have Course and Lesson
540
		elseif( $this->course_id && $this->lesson_id ) {
541
542
			$query_args = array(
543
				'page' => $this->page_slug,
544
				'course_id' => $this->course_id,
545
				'view' => 'lessons'
546
			);
547
548
			$course = get_the_title( $this->course_id );
549
550
			$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>';
551
		}
552
		$menu = apply_filters( 'sensei_learners_sub_menu', $menu );
553 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...
554
			echo '<ul class="subsubsub">' . "\n";
555
			foreach ( $menu as $class => $item ) {
556
				$menu[ $class ] = "\t<li class='$class'>$item";
557
			}
558
			echo implode( " |</li>\n", $menu ) . "</li>\n";
559
			echo '</ul>' . "\n";
560
		}
561
562
	} // End data_table_header()
563
564
	/**
565
	 * Output for table footer
566
	 * @since  1.6.0
567
	 * @return void
568
	 */
569
	public function data_table_footer() {
570
		// Nothing right now
571
	} // End data_table_footer()
572
573
	/**
574
	 * Add learners (to Course or Lesson) box to bottom of table display
575
	 * @since  1.6.0
576
	 * @return void
577
	 */
578
	public function add_learners_box() {
579
		$post_type = '';
580
		$post_title = '';
581
		$form_post_type = '';
582
		$form_course_id = 0;
583
		$form_lesson_id = 0;
584
		if( $this->course_id && ! $this->lesson_id ) {
585
			$post_title = get_the_title( $this->course_id );
586
			$post_type = __( 'Course', 'woothemes-sensei' );
587
			$form_post_type = 'course';
588
			$form_course_id = $this->course_id;
589
		}
590
		elseif( $this->course_id && $this->lesson_id ) {
591
			$post_title = get_the_title( $this->lesson_id );
592
			$post_type = __( 'Lesson', 'woothemes-sensei' );
593
			$form_post_type = 'lesson';
594
			$form_course_id = $this->course_id;
595
			$form_lesson_id = $this->lesson_id;
596
			$course_title = get_the_title( $this->course_id );
597
		}
598
		if ( empty($form_post_type) ) {
599
			return;
600
		}
601
		?>
602
		<div class="postbox">
603
			<h3><span><?php printf( __( 'Add Learner to %1$s', 'woothemes-sensei' ), $post_type ); ?></span></h3>
604
			<div class="inside">
605
				<form name="add_learner" action="" method="post">
606
					<p>
607
						<input name="add_user_id" placeholder="<?php _e( 'Find learner', 'woothemes-sensei' ) ;?>" id="add_learner_search" style="min-width:300px;" />
608
						<?php if( 'lesson' == $form_post_type ) { ?>
609
							<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>
610
						<?php } elseif( 'course' == $form_post_type ) { ?>
611
							<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>
612
						<?php } ?>
613
						<br/>
614
						<span class="description"><?php _e( 'Search for a user by typing their name or username.', 'woothemes-sensei' ); ?></span>
615
					</p>
616
					<p><?php submit_button( sprintf( __( 'Add to \'%1$s\'', 'woothemes-sensei' ), $post_title ), 'primary', 'add_learner_submit', false, array() ); ?></p>
617
					<?php if( 'lesson' == $form_post_type ) { ?>
618
						<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>
0 ignored issues
show
Bug introduced by
The variable $course_title does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
619
					<?php } ?>
620
621
					<input type="hidden" name="add_post_type" value="<?php echo $form_post_type; ?>" />
622
					<input type="hidden" name="add_course_id" value="<?php echo $form_course_id; ?>" />
623
					<input type="hidden" name="add_lesson_id" value="<?php echo $form_lesson_id; ?>" />
624
					<?php
625
						do_action( 'sensei_learners_add_learner_form' );
626
					?>
627
					<?php wp_nonce_field( 'add_learner_to_sensei', 'add_learner_nonce' ); ?>
628
				</form>
629
			</div>
630
		</div>
631
		<?php
632
	}
633
634
	/**
635
	 * The text for the search button
636
	 * @since  1.7.0
637
	 * @return void
638
	 */
639 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...
640
641
		switch( $this->view ) {
642
			case 'learners':
643
				$text = __( 'Search Learners', 'woothemes-sensei' );
644
			break;
645
646
			case 'lessons':
647
				$text = __( 'Search Lessons', 'woothemes-sensei' );
648
			break;
649
650
			default:
651
				$text = __( 'Search Courses', 'woothemes-sensei' );
652
			break;
653
		}
654
655
		return $text;
656
	}
657
658
} // End Class
659
660
/**
661
 * Class WooThemes_Sensei_Learners_Main
662
 * for backward compatibility
663
 * @since 1.9.0
664
 */
665
class WooThemes_Sensei_Learners_Main extends Sensei_Learners_Main {}
666