Completed
Push — master ( 7d92ba...201c1b )
by Dwain
05:05
created

Sensei_Course::load_single_course_lessons_query()   B

Complexity

Conditions 6
Paths 3

Size

Total Lines 49
Code Lines 28

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 49
rs 8.5907
cc 6
eloc 28
nc 3
nop 0
1
<?php
2
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
3
4
/**
5
 * Sensei Course Class
6
 *
7
 * All functionality pertaining to the Courses Post Type in Sensei.
8
 *
9
 * @package WordPress
10
 * @subpackage Sensei
11
 * @category Core
12
 * @author WooThemes
13
 * @since 1.0.0
14
 */
15
class Sensei_Course {
16
    /**
17
     * @var $token
18
     */
19
	public $token;
20
21
    /**
22
     * @var array $meta_fields
23
     */
24
	public $meta_fields;
25
26
    /**
27
     * @var string|bool $my_courses_page reference to the sites
28
     * my courses page, false if none was set
29
     */
30
    public  $my_courses_page;
31
32
	/**
33
	 * Constructor.
34
	 * @since  1.0.0
35
	 */
36
	public function __construct () {
37
		// Setup meta fields for this post type
38
		$this->meta_fields = array( 'course_prerequisite', 'course_featured', 'course_video_embed', 'course_woocommerce_product' );
39
		// Admin actions
40
		if ( is_admin() ) {
41
			// Metabox functions
42
            add_action( 'add_meta_boxes', array( $this, 'meta_box_setup' ), 20 );
43
			add_action( 'save_post', array( $this, 'meta_box_save' ) );
44
			// Custom Write Panel Columns
45
			add_filter( 'manage_edit-course_columns', array( $this, 'add_column_headings' ), 10, 1 );
46
			add_action( 'manage_posts_custom_column', array( $this, 'add_column_data' ), 10, 2 );
47
		} else {
48
			$this->my_courses_page = false;
49
		} // End If Statement
50
51
		// Update course completion upon completion of a lesson
52
		add_action( 'sensei_user_lesson_end', array( $this, 'update_status_after_lesson_change' ), 10, 2 );
53
		// Update course completion upon reset of a lesson
54
		add_action( 'sensei_user_lesson_reset', array( $this, 'update_status_after_lesson_change' ), 10, 2 );
55
		// Update course completion upon grading of a quiz
56
		add_action( 'sensei_user_quiz_grade', array( $this, 'update_status_after_quiz_submission' ), 10, 2 );
57
58
        // show the progress bar ont he single course page
59
        add_action( 'sensei_single_course_content_inside_before' , array( $this, 'the_progress_statement' ), 15 );
60
        add_action( 'sensei_single_course_content_inside_before' , array( $this, 'the_progress_meter' ), 16 );
61
62
        // provide an option to block all emails related to a selected course
63
        add_filter( 'sensei_send_emails', array( $this, 'block_notification_emails' ) );
64
        add_action( 'save_post', array( $this, 'save_course_notification_meta_box' ) );
65
66
        // preview lessons on the course content
67
        add_action( 'sensei_course_content_inside_after',array( $this, 'the_course_free_lesson_preview' ) );
68
69
        // the course meta
70
        add_action('sensei_course_content_inside_before', array( $this, 'the_course_meta' ) );
71
72
        // backwards compatible template hooks
73
        add_action('sensei_course_content_inside_before', array( $this, 'content_before_backwards_compatibility_hooks' ));
74
        add_action('sensei_loop_course_before', array( $this,'loop_before_backwards_compatibility_hooks' ) );
75
76
        // add the user status on the course to the markup as a class
77
        add_filter('post_class', array( __CLASS__ , 'add_course_user_status_class' ), 20, 3 );
78
79
        //filter the course query in Sensei specific instances
80
        add_filter( 'pre_get_posts', array( __CLASS__, 'course_query_filter' ) );
81
82
        //attache the sorting to the course archive
83
        add_action ( 'sensei_archive_before_course_loop' , array( 'Sensei_Course', 'course_archive_sorting' ) );
84
85
        //attach the filter links to the course archive
86
        add_action ( 'sensei_archive_before_course_loop' , array( 'Sensei_Course', 'course_archive_filters' ) );
87
88
        //filter the course query when featured filter is applied
89
        add_filter( 'pre_get_posts',  array( __CLASS__, 'course_archive_featured_filter'));
90
91
        // handle the order by title post submission
92
        add_filter( 'pre_get_posts',  array( __CLASS__, 'course_archive_order_by_title'));
93
94
        // ensure the course category page respects the manual order set for courses
95
        add_filter( 'pre_get_posts',  array( __CLASS__, 'alter_course_category_order'));
96
97
        // flush rewrite rules when saving a course
98
        add_action('save_post', array( 'Sensei_Course', 'flush_rewrite_rules' ) );
99
100
	} // End __construct()
101
102
	/**
103
	 * Fires when a quiz has been graded to check if the Course status needs changing
104
	 *
105
	 * @param type $user_id
106
	 * @param type $quiz_id
107
	 */
108
	public function update_status_after_quiz_submission( $user_id, $quiz_id ) {
109
		if ( intval( $user_id ) > 0 && intval( $quiz_id ) > 0 ) {
110
			$lesson_id = get_post_meta( $quiz_id, '_quiz_lesson', true );
111
			$this->update_status_after_lesson_change( $user_id, $lesson_id );
112
		}
113
	}
114
115
	/**
116
	 * Fires when a lesson has changed to check if the Course status needs changing
117
	 *
118
	 * @param int $user_id
119
	 * @param int $lesson_id
120
	 */
121
	public function update_status_after_lesson_change( $user_id, $lesson_id ) {
122
		if ( intval( $user_id ) > 0 && intval( $lesson_id ) > 0 ) {
123
			$course_id = get_post_meta( $lesson_id, '_lesson_course', true );
124
			if ( intval( $course_id ) > 0 ) {
125
				// Updates the Course status and it's meta data
126
				WooThemes_Sensei_Utils::user_complete_course( $course_id, $user_id );
127
			}
128
		}
129
	}
130
131
	/**
132
	 * meta_box_setup function.
133
	 *
134
	 * @access public
135
	 * @return void
136
	 */
137
	public function meta_box_setup () {
138
139
		if ( WooThemes_Sensei_Utils::sensei_is_woocommerce_activated() ) {
140
			// Add Meta Box for WooCommerce Course
141
			add_meta_box( 'course-wc-product', __( 'WooCommerce Product', 'woothemes-sensei' ), array( $this, 'course_woocommerce_product_meta_box_content' ), $this->token, 'side', 'default' );
142
		} // End If Statement
143
		// Add Meta Box for Prerequisite Course
144
		add_meta_box( 'course-prerequisite', __( 'Course Prerequisite', 'woothemes-sensei' ), array( $this, 'course_prerequisite_meta_box_content' ), $this->token, 'side', 'default' );
145
		// Add Meta Box for Featured Course
146
		add_meta_box( 'course-featured', __( 'Featured Course', 'woothemes-sensei' ), array( $this, 'course_featured_meta_box_content' ), $this->token, 'side', 'default' );
147
		// Add Meta Box for Course Meta
148
		add_meta_box( 'course-video', __( 'Course Video', 'woothemes-sensei' ), array( $this, 'course_video_meta_box_content' ), $this->token, 'normal', 'default' );
149
		// Add Meta Box for Course Lessons
150
		add_meta_box( 'course-lessons', __( 'Course Lessons', 'woothemes-sensei' ), array( $this, 'course_lessons_meta_box_content' ), $this->token, 'normal', 'default' );
151
        // Add Meta Box to link to Manage Learners
152
        add_meta_box( 'course-manage', __( 'Course Management', 'woothemes-sensei' ), array( $this, 'course_manage_meta_box_content' ), $this->token, 'side', 'default' );
153
        // Remove "Custom Settings" meta box.
154
		remove_meta_box( 'woothemes-settings', $this->token, 'normal' );
155
156
        // add Disable email notification box
157
        add_meta_box( 'course-notifications', __( 'Course Notifications', 'woothemes-sensei' ), array( $this, 'course_notification_meta_box_content' ), 'course', 'normal', 'default' );
158
159
	} // End meta_box_setup()
160
161
	/**
162
	 * course_woocommerce_product_meta_box_content function.
163
	 *
164
	 * @access public
165
	 * @return void
166
	 */
167
	public function course_woocommerce_product_meta_box_content () {
168
		global $post;
169
170
		$select_course_woocommerce_product = get_post_meta( $post->ID, '_course_woocommerce_product', true );
171
172
		$post_args = array(	'post_type' 		=> array( 'product', 'product_variation' ),
173
							'posts_per_page' 		=> -1,
174
							'orderby'         	=> 'title',
175
    						'order'           	=> 'DESC',
176
    						'exclude' 			=> $post->ID,
177
    						'post_status'		=> array( 'publish', 'private', 'draft' ),
178
    						'tax_query'			=> array(
179
								array(
180
									'taxonomy'	=> 'product_type',
181
									'field'		=> 'slug',
182
									'terms'		=> array( 'variable', 'grouped' ),
183
									'operator'	=> 'NOT IN'
184
								)
185
							),
186
							'suppress_filters' 	=> 0
187
							);
188
		$posts_array = get_posts( $post_args );
189
190
		$html = '';
191
192
		$html .= '<input type="hidden" name="' . esc_attr( 'woo_' . $this->token . '_noonce' ) . '" id="' . esc_attr( 'woo_' . $this->token . '_noonce' ) . '" value="' . esc_attr( wp_create_nonce( plugin_basename(__FILE__) ) ) . '" />';
193
194
		if ( count( $posts_array ) > 0 ) {
195
196
			$html .= '<select id="course-woocommerce-product-options" name="course_woocommerce_product" class="chosen_select widefat">' . "\n";
197
			$html .= '<option value="-">' . __( 'None', 'woothemes-sensei' ) . '</option>';
198
				$prev_parent_id = 0;
199
				foreach ( $posts_array as $post_item ) {
200
201
					if ( 'product_variation' == $post_item->post_type ) {
202
203
						$product_object = get_product( $post_item->ID );
204
						$parent_id = wp_get_post_parent_id( $post_item->ID );
205
206 View Code Duplication
                        if( sensei_check_woocommerce_version( '2.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...
207
							$formatted_variation = wc_get_formatted_variation( $product_object->variation_data, true );
208
209
						} else {
210
                            // fall back to pre wc 2.1
211
							$formatted_variation = woocommerce_get_formatted_variation( $product_object->variation_data, true );
212
213
						}
214
215
                        $product_name = ucwords( $formatted_variation );
216
                        if( empty( $product_name ) ){
217
218
                            $product_name = __( 'Variation #', 'woothemes-sensei' ) . $product_object->variation_id;
219
220
                        }
221
222
					} else {
223
224
						$parent_id = false;
225
						$prev_parent_id = 0;
226
						$product_name = $post_item->post_title;
227
228
					}
229
230
					// Show variations in groups
231 View Code Duplication
					if( $parent_id && $parent_id != $prev_parent_id ) {
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...
232
233
						if( 0 != $prev_parent_id ) {
234
235
							$html .= '</optgroup>';
236
237
						}
238
						$html .= '<optgroup label="' . get_the_title( $parent_id ) . '">';
239
						$prev_parent_id = $parent_id;
240
241
					} elseif( ! $parent_id && 0 == $prev_parent_id ) {
242
243
						$html .= '</optgroup>';
244
245
					}
246
247
					$html .= '<option value="' . esc_attr( absint( $post_item->ID ) ) . '"' . selected( $post_item->ID, $select_course_woocommerce_product, false ) . '>' . esc_html( $product_name ) . '</option>' . "\n";
248
249
				} // End For Loop
250
251
			$html .= '</select>' . "\n";
252
			if ( current_user_can( 'publish_product' )) {
253
254
				$html .= '<p>' . "\n";
255
					$html .= '<a href="' . admin_url( 'post-new.php?post_type=product' ) . '" title="' . esc_attr( __( 'Add a Product', 'woothemes-sensei' ) ) . '">' . __( 'Add a Product', 'woothemes-sensei' ) . '</a>' . "\n";
256
				$html .= '</p>'."\n";
257
258
			} // End If Statement
259
260
		} else {
261
262
			if ( current_user_can( 'publish_product' )) {
263
264
				$html .= '<p>' . "\n";
265
					$html .= esc_html( __( 'No products exist yet.', 'woothemes-sensei' ) ) . '&nbsp;<a href="' . admin_url( 'post-new.php?post_type=product' ) . '" title="' . esc_attr( __( 'Add a Product', 'woothemes-sensei' ) ) . '">' . __( 'Please add some first', 'woothemes-sensei' ) . '</a>' . "\n";
266
				$html .= '</p>'."\n";
267
268
			} else {
269
270
                $html .= '<p>' . "\n";
271
					$html .= esc_html( __( 'No products exist yet.', 'woothemes-sensei' ) ) . "\n";
272
				$html .= '</p>'."\n";
273
274
			} // End If Statement
275
276
		} // End If Statement
277
278
		echo $html;
279
280
	} // End course_woocommerce_product_meta_box_content()
281
282
	/**
283
	 * course_prerequisite_meta_box_content function.
284
	 *
285
	 * @access public
286
	 * @return void
287
	 */
288
	public function course_prerequisite_meta_box_content () {
289
		global $post;
290
291
		$select_course_prerequisite = get_post_meta( $post->ID, '_course_prerequisite', true );
292
293
		$post_args = array(	'post_type' 		=> 'course',
294
							'posts_per_page' 		=> -1,
295
							'orderby'         	=> 'title',
296
    						'order'           	=> 'DESC',
297
    						'exclude' 			=> $post->ID,
298
							'suppress_filters' 	=> 0
299
							);
300
		$posts_array = get_posts( $post_args );
301
302
		$html = '';
303
304
		$html .= '<input type="hidden" name="' . esc_attr( 'woo_' . $this->token . '_noonce' ) . '" id="' . esc_attr( 'woo_' . $this->token . '_noonce' ) . '" value="' . esc_attr( wp_create_nonce( plugin_basename(__FILE__) ) ) . '" />';
305
306 View Code Duplication
		if ( count( $posts_array ) > 0 ) {
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...
307
			$html .= '<select id="course-prerequisite-options" name="course_prerequisite" class="chosen_select widefat">' . "\n";
308
			$html .= '<option value="">' . __( 'None', 'woothemes-sensei' ) . '</option>';
309
				foreach ($posts_array as $post_item){
310
					$html .= '<option value="' . esc_attr( absint( $post_item->ID ) ) . '"' . selected( $post_item->ID, $select_course_prerequisite, false ) . '>' . esc_html( $post_item->post_title ) . '</option>' . "\n";
311
				} // End For Loop
312
			$html .= '</select>' . "\n";
313
		} else {
314
			$html .= '<p>' . esc_html( __( 'No courses exist yet. Please add some first.', 'woothemes-sensei' ) ) . '</p>';
315
		} // End If Statement
316
317
		echo $html;
318
319
	} // End course_prerequisite_meta_box_content()
320
321
	/**
322
	 * course_featured_meta_box_content function.
323
	 *
324
	 * @access public
325
	 * @return void
326
	 */
327
	public function course_featured_meta_box_content () {
328
		global $post;
329
330
		$course_featured = get_post_meta( $post->ID, '_course_featured', true );
331
332
		$html = '';
333
334
		$html .= '<input type="hidden" name="' . esc_attr( 'woo_' . $this->token . '_noonce' ) . '" id="' . esc_attr( 'woo_' . $this->token . '_noonce' ) . '" value="' . esc_attr( wp_create_nonce( plugin_basename(__FILE__) ) ) . '" />';
335
336
		$checked = '';
337
		if ( isset( $course_featured ) && ( '' != $course_featured ) ) {
338
	 	    $checked = checked( 'featured', $course_featured, false );
339
	 	} // End If Statement
340
341
	 	$html .= '<input type="checkbox" name="course_featured" value="featured" ' . $checked . '>&nbsp;' . __( 'Feature this course', 'woothemes-sensei' ) . '<br>';
342
343
		echo $html;
344
345
	} // End course_featured_meta_box_content()
346
347
	/**
348
	 * course_video_meta_box_content function.
349
	 *
350
	 * @access public
351
	 * @return void
352
	 */
353
	public function course_video_meta_box_content () {
354
		global $post;
355
356
		$course_video_embed = get_post_meta( $post->ID, '_course_video_embed', true );
357
358
		$html = '';
359
360
		$html .= '<label class="screen-reader-text" for="course_video_embed">' . __( 'Video Embed Code', 'woothemes-sensei' ) . '</label>';
361
		$html .= '<textarea rows="5" cols="50" name="course_video_embed" tabindex="6" id="course-video-embed">' . $course_video_embed . '</textarea>';
362
		$html .= '<p>' .  __( 'Paste the embed code for your video (e.g. YouTube, Vimeo etc.) in the box above.', 'woothemes-sensei' ) . '</p>';
363
364
		echo $html;
365
366
	} // End course_video_meta_box_content()
367
368
	/**
369
	 * meta_box_save function.
370
	 *
371
	 * Handles saving the meta data
372
	 *
373
	 * @access public
374
	 * @param int $post_id
375
	 * @return void
376
	 */
377
	public function meta_box_save ( $post_id ) {
378
		global $post, $messages;
379
380
		/* Verify the nonce before proceeding. */
381
		if ( ( get_post_type() != $this->token ) || ! wp_verify_nonce( $_POST['woo_' . $this->token . '_noonce'], plugin_basename(__FILE__) ) ) {
382
			return $post_id;
383
		}
384
385
		/* Get the post type object. */
386
		$post_type = get_post_type_object( $post->post_type );
387
388
		/* Check if the current user has permission to edit the post. */
389
		if ( !current_user_can( $post_type->cap->edit_post, $post_id ) ) {
390
			return $post_id;
391
		} // End If Statement
392
393 View Code Duplication
		if ( 'page' == $_POST['post_type'] ) {
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...
394
			if ( ! current_user_can( 'edit_page', $post_id ) ) {
395
				return $post_id;
396
			} // End If Statement
397
		} else {
398
			if ( ! current_user_can( 'edit_post', $post_id ) ) {
399
				return $post_id;
400
			} // End If Statement
401
		} // End If Statement
402
403
		// Save the post meta data fields
404 View Code Duplication
		if ( isset($this->meta_fields) && is_array($this->meta_fields) ) {
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...
405
			foreach ( $this->meta_fields as $meta_key ) {
406
				$this->save_post_meta( $meta_key, $post_id );
407
			} // End For Loop
408
		} // End If Statement
409
410
	} // End meta_box_save()
411
412
413
	/**
414
	 * save_post_meta function.
415
	 *
416
	 * Does the save
417
	 *
418
	 * @access private
419
	 * @param string $post_key (default: '')
420
	 * @param int $post_id (default: 0)
421
	 * @return int new meta id | bool meta value saved status
422
	 */
423
	private function save_post_meta( $post_key = '', $post_id = 0 ) {
424
		// Get the meta key.
425
		$meta_key = '_' . $post_key;
426
		// Get the posted data and sanitize it for use as an HTML class.
427 View Code Duplication
		if ( 'course_video_embed' == $post_key) {
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...
428
			$new_meta_value = esc_html( $_POST[$post_key] );
429
		} else {
430
			$new_meta_value = ( isset( $_POST[$post_key] ) ? sanitize_html_class( $_POST[$post_key] ) : '' );
431
		} // End If Statement
432
433
        // update field with the new value
434
        return update_post_meta( $post_id, $meta_key, $new_meta_value );
435
436
	} // End save_post_meta()
437
438
	/**
439
	 * course_lessons_meta_box_content function.
440
	 *
441
	 * @access public
442
	 * @return void
443
	 */
444
	public function course_lessons_meta_box_content () {
445
446
		global $post;
447
448
		// Setup Lesson Query
449
		$posts_array = array();
450
		if ( 0 < $post->ID ) {
451
452
			$posts_array = $this->course_lessons( $post->ID, 'any' );
453
454
		} // End If Statement
455
456
		$html = '';
457
		$html .= '<input type="hidden" name="' . esc_attr( 'woo_' . $this->token . '_noonce' ) . '" id="'
458
                 . esc_attr( 'woo_' . $this->token . '_noonce' )
459
                 . '" value="' . esc_attr( wp_create_nonce( plugin_basename(__FILE__) ) ) . '" />';
460
461
		if ( count( $posts_array ) > 0 ) {
462
463
			foreach ($posts_array as $post_item){
464
465
				$html .= '<p>'."\n";
466
467
					$html .= $post_item->post_title."\n";
468
					$html .= '<a href="' . esc_url( get_edit_post_link( $post_item->ID ) ) . '" title="' . esc_attr( sprintf( __( 'Edit %s', 'woothemes-sensei' ), $post_item->post_title ) ) . '" class="edit-lesson-action">' . __( 'Edit this lesson', 'woothemes-sensei' ) . '</a>';
469
470
				$html .= '</p>'."\n";
471
472
			} // End For Loop
473
474
		} else {
475
			$course_id = '';
476
			if ( 0 < $post->ID ) { $course_id = '&course_id=' . $post->ID; }
477
			$html .= '<p>' . esc_html( __( 'No lessons exist yet for this course.', 'woothemes-sensei' ) ) . "\n";
478
479
				$html .= '<a href="' . admin_url( 'post-new.php?post_type=lesson' . $course_id )
480
                         . '" title="' . esc_attr( __( 'Add a Lesson', 'woothemes-sensei' ) ) . '">'
481
                         . __( 'Please add some.', 'woothemes-sensei' ) . '</a>' . "\n";
482
483
			$html .= '</p>'."\n";
484
		} // End If Statement
485
486
		echo $html;
487
488
	} // End course_lessons_meta_box_content()
489
490
    /**
491
     * course_manage_meta_box_content function.
492
     *
493
     * @since 1.9.0
494
     * @access public
495
     * @return void
496
     */
497
498
    public function course_manage_meta_box_content () {
499
        global $post;
500
        
501
        $manage_url = esc_url( add_query_arg( array( 'page' => 'sensei_learners', 'course_id' => $post->ID, 'view' => 'learners' ), admin_url( 'admin.php') ) );
502
503
        $grading_url = esc_url( add_query_arg( array( 'page' => 'sensei_grading', 'course_id' => $post->ID, 'view' => 'learners' ), admin_url( 'admin.php') ) );
504
505
506
        echo "<ul><li><a href='$manage_url'>".__("Manage Learners", 'woothemes-sensei')."</a></li>";
507
508
        echo "<li><a href='$grading_url'>".__("Manage Grading", 'woothemes-sensei')."</a></li></ul>";
509
510
511
512
    } // End course_manage_meta_box_content()
513
514
	/**
515
	 * Add column headings to the "lesson" post list screen.
516
	 * @access public
517
	 * @since  1.0.0
518
	 * @param  array $defaults
519
	 * @return array $new_columns
520
	 */
521
	public function add_column_headings ( $defaults ) {
522
		$new_columns['cb'] = '<input type="checkbox" />';
0 ignored issues
show
Coding Style Comprehensibility introduced by
$new_columns was never initialized. Although not strictly required by PHP, it is generally a good practice to add $new_columns = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
523
		// $new_columns['id'] = __( 'ID' );
0 ignored issues
show
Unused Code Comprehensibility introduced by
54% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
524
		$new_columns['title'] = _x( 'Course Title', 'column name', 'woothemes-sensei' );
525
		$new_columns['course-prerequisite'] = _x( 'Pre-requisite Course', 'column name', 'woothemes-sensei' );
526
		if ( WooThemes_Sensei_Utils::sensei_is_woocommerce_activated() ) {
527
			$new_columns['course-woocommerce-product'] = _x( 'WooCommerce Product', 'column name', 'woothemes-sensei' );
528
		} // End If Statement
529
		$new_columns['course-category'] = _x( 'Category', 'column name', 'woothemes-sensei' );
530
		if ( isset( $defaults['date'] ) ) {
531
			$new_columns['date'] = $defaults['date'];
532
		}
533
534
		return $new_columns;
535
	} // End add_column_headings()
536
537
	/**
538
	 * Add data for our newly-added custom columns.
539
	 * @access public
540
	 * @since  1.0.0
541
	 * @param  string $column_name
542
	 * @param  int $id
543
	 * @return void
544
	 */
545
	public function add_column_data ( $column_name, $id ) {
546
		global $wpdb, $post;
547
548
		switch ( $column_name ) {
549
			case 'id':
550
				echo $id;
551
			break;
552
553 View Code Duplication
			case 'course-prerequisite':
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
				$course_prerequisite_id = get_post_meta( $id, '_course_prerequisite', true);
555
				if ( 0 < absint( $course_prerequisite_id ) ) { echo '<a href="' . esc_url( get_edit_post_link( absint( $course_prerequisite_id ) ) ) . '" title="' . esc_attr( sprintf( __( 'Edit %s', 'woothemes-sensei' ), get_the_title( absint( $course_prerequisite_id ) ) ) ) . '">' . get_the_title( absint( $course_prerequisite_id ) ) . '</a>'; }
556
557
			break;
558
559
			case 'course-woocommerce-product':
560
				if ( WooThemes_Sensei_Utils::sensei_is_woocommerce_activated() ) {
561
					$course_woocommerce_product_id = get_post_meta( $id, '_course_woocommerce_product', true);
562
					if ( 0 < absint( $course_woocommerce_product_id ) ) {
563
						if ( 'product_variation' == get_post_type( $course_woocommerce_product_id ) ) {
564
							$product_object = get_product( $course_woocommerce_product_id );
565 View Code Duplication
							if( sensei_check_woocommerce_version( '2.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...
566
								$formatted_variation = wc_get_formatted_variation( $product_object->variation_data, true );
567
							} else {
568
								$formatted_variation = woocommerce_get_formatted_variation( $product_object->variation_data, true );
569
							}
570
							$course_woocommerce_product_id = $product_object->parent->post->ID;
571
							$product_name = $product_object->parent->post->post_title . '<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;' . ucwords( $formatted_variation );
572
						} else {
573
							$product_name = get_the_title( absint( $course_woocommerce_product_id ) );
574
						} // End If Statement
575
						echo '<a href="' . esc_url( get_edit_post_link( absint( $course_woocommerce_product_id ) ) ) . '" title="' . esc_attr( sprintf( __( 'Edit %s', 'woothemes-sensei' ), $product_name ) ) . '">' . $product_name . '</a>';
576
					} // End If Statement
577
				} // End If Statement
578
			break;
579
580
			case 'course-category':
581
				$output = get_the_term_list( $id, 'course-category', '', ', ', '' );
582
				if ( '' == $output ) {
583
					$output = __( 'None', 'woothemes-sensei' );
584
				} // End If Statement
585
				echo $output;
586
			break;
587
588
			default:
589
			break;
590
		}
591
	} // End add_column_data()
592
593
594
	/**
595
	 * course_query function.
596
	 *
597
	 * @access public
598
	 * @param int $amount (default: 0)
599
	 * @param string $type (default: 'default')
600
	 * @param array $includes (default: array())
601
	 * @return array
602
	 */
603
	public function course_query( $amount = 0, $type = 'default', $includes = array(), $excludes = array() ) {
604
		global $my_courses_page ;
605
606
		$results_array = array();
607
608
		if( $my_courses_page ) { add_action( 'pre_get_posts', array( $this, 'filter_my_courses' ) ); }
609
610
		$post_args = $this->get_archive_query_args( $type, $amount, $includes, $excludes );
611
612
		// get the posts
613
		if( empty( $post_args ) ) {
614
615
			return $results_array;
616
617
		}else{
618
619
			//reset the pagination as this widgets do not need it
620
			$post_args['paged'] = 1;
621
			$results_array = get_posts( $post_args );
622
623
		}
624
625
		if( $my_courses_page ) { remove_action( 'pre_get_posts', array( $this, 'filter_my_courses' ) ); }
626
627
		return $results_array;
628
629
	} // End course_query()
630
631
632
	/**
633
	 * get_archive_query_args function.
634
	 *
635
	 * @access public
636
	 * @param string $type (default: '')
637
	 * @param int $amount (default: 0)
638
	 * @param array $includes (default: array())
639
	 * @return array
640
	 */
641
	public function get_archive_query_args( $type = '', $amount = 0 , $includes = array(), $excludes = array() ) {
642
643
		global $wp_query;
644
645
		if ( 0 == $amount && ( isset( Sensei()->settings->settings[ 'course_archive_amount' ] ) && 'usercourses' != $type && ( 0 < absint( Sensei()->settings->settings[ 'course_archive_amount' ] ) ) ) ) {
646
			$amount = absint( Sensei()->settings->settings[ 'course_archive_amount' ] );
647
		} else {
648
			if ( 0 == $amount) {
649
				$amount = $wp_query->get( 'posts_per_page' );
650
			} // End If Statement
651
		} // End If Statement
652
653
        $stored_order = get_option( 'sensei_course_order', '' );
654
        $order = 'ASC';
655
        $orderby = 'menu_order';
656
        if( empty( $stored_order ) ){
657
658
            $order = 'DESC';
659
            $orderby = 'date';
660
661
        }
662
663
		switch ($type) {
664
665 View Code Duplication
			case 'usercourses':
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...
666
				$post_args = array(	'post_type' 		=> 'course',
667
									'orderby'         	=> $orderby,
668
    								'order'           	=> $order,
669
    								'post_status'      	=> 'publish',
670
    								'include'			=> $includes,
671
    								'exclude'			=> $excludes,
672
    								'suppress_filters' 	=> 0
673
									);
674
				break;
675 View Code Duplication
			case 'freecourses':
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...
676
677
                $post_args = array(
678
                    'post_type' 		=> 'course',
679
                    'orderby'         	=> $orderby,
680
                    'order'           	=> $order,
681
                    'post_status'      	=> 'publish',
682
                    'exclude'			=> $excludes,
683
                    'suppress_filters' 	=> 0
684
                );
685
                // Sub Query to get all WooCommerce Products that have Zero price
686
                $post_args['meta_query'] = Sensei_WC::get_free_courses_meta_query_args();
687
688
                break;
689
690 View Code Duplication
			case 'paidcourses':
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...
691
692
                $post_args = array(
693
                    'post_type' 		=> 'course',
694
                    'orderby'         	=> $orderby,
695
                    'order'           	=> $order,
696
                    'post_status'      	=> 'publish',
697
                    'exclude'			=> $excludes,
698
                    'suppress_filters' 	=> 0
699
                );
700
701
                // Sub Query to get all WooCommerce Products that have price greater than zero
702
                $post_args['meta_query'] = Sensei_WC::get_paid_courses_meta_query_args();
703
704
				break;
705
706
			case 'featuredcourses':
707
                $post_args = array(	'post_type' 		=> 'course',
708
                                    'orderby'         	=> $orderby,
709
                                    'order'           	=> $order,
710
    								'post_status'      	=> 'publish',
711
    								'meta_value' 		=> 'featured',
712
    								'meta_key' 			=> '_course_featured',
713
    								'meta_compare' 		=> '=',
714
    								'exclude'			=> $excludes,
715
    								'suppress_filters' 	=> 0
716
									);
717
				break;
718 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...
719
				$post_args = array(	'post_type' 		=> 'course',
720
                                    'orderby'         	=> $orderby,
721
                                    'order'           	=> $order,
722
    								'post_status'      	=> 'publish',
723
    								'exclude'			=> $excludes,
724
    								'suppress_filters' 	=> 0
725
									);
726
				break;
727
728
		}
729
730
        $post_args['posts_per_page'] = $amount;
731
        $paged = $wp_query->get( 'paged' );
732
        $post_args['paged'] = empty( $paged) ? 1 : $paged;
733
734
        if( 'newcourses' == $type ){
735
736
            $post_args[ 'orderby' ] = 'date';
737
            $post_args[ 'order' ] = 'DESC';
738
        }
739
740
		return $post_args;
741
	}
742
743
744
	/**
745
	 * course_image function.
746
	 *
747
	 * Outputs the courses image, or first image from a lesson within a course
748
     *
749
     * Will echo the image unless return true is specified.
750
	 *
751
	 * @access public
752
	 * @param int | WP_Post $course_id (default: 0)
753
	 * @param string $width (default: '100')
754
	 * @param string $height (default: '100')
755
     * @param bool $return default false
756
     *
757
	 * @return string | void
758
	 */
759
	public function course_image( $course_id = 0, $width = '100', $height = '100', $return = false ) {
760
761
        if( is_a( $course_id, 'WP_Post' ) ){
762
            $course_id = $course_id->ID;
763
        }
764
765
		$html = '';
766
767
		// Get Width and Height settings
768
		if ( ( $width == '100' ) && ( $height == '100' ) ) {
769
770
			if ( is_singular( 'course' ) ) {
771
772
				if ( !Sensei()->settings->settings[ 'course_single_image_enable' ] ) {
773
					return '';
774
				} // End If Statement
775
				$image_thumb_size = 'course_single_image';
776
				$dimensions = Sensei()->get_image_size( $image_thumb_size );
777
				$width = $dimensions['width'];
778
				$height = $dimensions['height'];
779
780
			} else {
781
782
				if ( !Sensei()->settings->settings[ 'course_archive_image_enable' ] ) {
783
					return '';
784
				} // End If Statement
785
786
				$image_thumb_size = 'course_archive_image';
787
				$dimensions = Sensei()->get_image_size( $image_thumb_size );
788
				$width = $dimensions['width'];
789
				$height = $dimensions['height'];
790
791
			} // End If Statement
792
793
		} // End If Statement
794
795
		$img_url = '';
796
		if ( has_post_thumbnail( $course_id ) ) {
797
   			// Get Featured Image
798
   			$img_url = get_the_post_thumbnail( $course_id, array( $width, $height ), array( 'class' => 'woo-image thumbnail alignleft') );
799
 		} else {
800
801
			// Check for a Lesson Image
802
			$course_lessons = $this->course_lessons( $course_id );
803
804
			foreach ($course_lessons as $lesson_item){
805
				if ( has_post_thumbnail( $lesson_item->ID ) ) {
806
					// Get Featured Image
807
					$img_url = get_the_post_thumbnail( $lesson_item->ID, array( $width, $height ), array( 'class' => 'woo-image thumbnail alignleft') );
808
					if ( '' != $img_url ) {
809
						break;
810
					} // End If Statement
811
812
				} // End If Statement
813
			} // End For Loop
814
815 View Code Duplication
 			if ( '' == $img_url ) {
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...
816
817
 				// Display Image Placeholder if none
818
				if ( Sensei()->settings->get( 'placeholder_images_enable' ) ) {
819
820
                    $img_url = apply_filters( 'sensei_course_placeholder_image_url', '<img src="http://placehold.it/' . $width . 'x' . $height . '" class="woo-image thumbnail alignleft" />' );
821
822
				} // End If Statement
823
824
 			} // End If Statement
825
826
		} // End If Statement
827
828
		if ( '' != $img_url ) {
829
830
			$html .= '<a href="' . get_permalink( $course_id ) . '" title="' . esc_attr( get_post_field( 'post_title', $course_id ) ) . '">' . $img_url  .'</a>';
831
832
		} // End If Statement
833
834
        if( $return ){
835
836
            return $html;
837
838
        }else{
839
840
            echo $html;
841
842
        }
843
844
	} // End course_image()
845
846
847
	/**
848
	 * course_count function.
849
	 *
850
	 * @access public
851
	 * @param array $exclude (default: array())
0 ignored issues
show
Bug introduced by
There is no parameter named $exclude. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
852
	 * @param string $post_status (default: 'publish')
853
	 * @return int
854
	 */
855
	public function course_count( $post_status = 'publish' ) {
856
857
		$post_args = array(	'post_type'         => 'course',
858
							'posts_per_page'    => -1,
859
//							'orderby'           => 'menu_order date',
0 ignored issues
show
Unused Code Comprehensibility introduced by
54% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
860
//							'order'             => 'ASC',
861
							'post_status'       => $post_status,
862
							'suppress_filters'  => 0,
863
							'fields'            => 'ids',
864
							);
865
866
		// Allow WP to generate the complex final query, just shortcut to only do an overall count
867
//		add_filter( 'posts_clauses', array( 'WooThemes_Sensei_Utils', 'get_posts_count_only_filter' ) );
868
		$courses_query = new WP_Query( apply_filters( 'sensei_course_count', $post_args ) );
869
//		remove_filter( 'posts_clauses', array( 'WooThemes_Sensei_Utils', 'get_posts_count_only_filter' ) );
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
870
871
		return count( $courses_query->posts );
872
	} // End course_count()
873
874
875
	/**
876
	 * course_lessons function.
877
	 *
878
	 * @access public
879
	 * @param int $course_id (default: 0)
880
	 * @param string $post_status (default: 'publish')
881
	 * @param string $fields (default: 'all'). WP only allows 3 types, but we will limit it to only 'ids' or 'all'
882
	 * @return array{ type WP_Post }  $posts_array
0 ignored issues
show
Documentation introduced by
The doc-type array{ could not be parsed: Unknown type name "array{" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
883
	 */
884
	public function course_lessons( $course_id = 0, $post_status = 'publish', $fields = 'all' ) {
885
886
        if( is_a( $course_id, 'WP_Post' ) ){
887
            $course_id = $course_id->ID;
888
        }
889
890
		$post_args = array(	'post_type'         => 'lesson',
891
							'posts_per_page'       => -1,
892
							'orderby'           => 'date',
893
							'order'             => 'ASC',
894
							'meta_query'        => array(
895
								array(
896
									'key' => '_lesson_course',
897
									'value' => intval( $course_id ),
898
								),
899
							),
900
							'post_status'       => $post_status,
901
							'suppress_filters'  => 0,
902
							);
903
		$query_results = new WP_Query( $post_args );
904
        $lessons = $query_results->posts;
905
906
        // re order the lessons. This could not be done via the OR meta query as there may be lessons
907
        // with the course order for a different course and this should not be included. It could also not
908
        // be done via the AND meta query as it excludes lesson that does not have the _order_$course_id but
909
        // that have been added to the course.
910
        if( count( $lessons) > 1  ){
911
912
            foreach( $lessons as $lesson ){
913
914
                $order = intval( get_post_meta( $lesson->ID, '_order_'. $course_id, true ) );
915
                // for lessons with no order set it to be 10000 so that it show up at the end
916
                $lesson->course_order = $order ? $order : 100000;
917
            }
918
919
            uasort( $lessons, array( $this, '_short_course_lessons_callback' )   );
920
        }
921
922
        /**
923
         * Filter runs inside Sensei_Course::course_lessons function
924
         *
925
         * Returns all lessons for a given course
926
         *
927
         * @param array $lessons
928
         * @param int $course_id
929
         */
930
        $lessons = apply_filters( 'sensei_course_get_lessons', $lessons, $course_id  );
931
932
        //return the requested fields
933
        // runs after the sensei_course_get_lessons filter so the filter always give an array of lesson
934
        // objects
935
        if( 'ids' == $fields ) {
936
            $lesson_objects = $lessons;
937
            $lessons = array();
938
939
            foreach ($lesson_objects as $lesson) {
940
                $lessons[] = $lesson->ID;
941
            }
942
        }
943
944
        return $lessons;
945
946
	} // End course_lessons()
947
948
    /**
949
     * Used for the uasort in $this->course_lessons()
950
     * @since 1.8.0
951
     * @access protected
952
     *
953
     * @param array $lesson_1
954
     * @param array $lesson_2
955
     * @return int
956
     */
957
    protected function _short_course_lessons_callback( $lesson_1, $lesson_2 ){
958
959
        if ( $lesson_1->course_order == $lesson_2->course_order ) {
960
            return 0;
961
        }
962
963
        return ($lesson_1->course_order < $lesson_2->course_order) ? -1 : 1;
964
    }
965
966
	/**
967
	 * Fetch all quiz ids in a course
968
	 * @since  1.5.0
969
	 * @param  integer $course_id ID of course
970
	 * @param  boolean $boolean_check True if a simple yes/no is required
971
	 * @return array              Array of quiz post objects
972
	 */
973
	public function course_quizzes( $course_id = 0, $boolean_check = false ) {
974
975
976
		$course_quizzes = array();
977
978
		if( $course_id ) {
979
			$lesson_ids = Sensei()->course->course_lessons( $course_id, 'any', 'ids' );
980
981
			foreach( $lesson_ids as $lesson_id ) {
982
				$has_questions = get_post_meta( $lesson_id, '_quiz_has_questions', true );
983
				if ( $has_questions && $boolean_check ) {
984
					return true;
985
				}
986
				elseif ( $has_questions ) {
987
					$quiz_id = Sensei()->lesson->lesson_quizzes( $lesson_id );
988
//					$questions = Sensei()->lesson->lesson_quiz_questions( $quiz_id );
0 ignored issues
show
Unused Code Comprehensibility introduced by
46% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
989
//					if( count( $questions ) > 0 ) {
990
						$course_quizzes[] = $quiz_id;
991
//					}
992
				}
993
			}
994
		}
995
		if ( $boolean_check && empty($course_quizzes) ) {
996
			$course_quizzes = false;
997
		}
998
		return $course_quizzes;
999
	}
1000
1001
1002
	/**
1003
	 * course_lessons_completed function. Appears to be completely unused and a duplicate of course_lessons()!
1004
	 *
1005
	 * @access public
1006
	 * @param  int $course_id (default: 0)
1007
	 * @param  string $post_status (default: 'publish')
1008
	 * @return array
1009
	 */
1010
	public function course_lessons_completed( $course_id = 0, $post_status = 'publish' ) {
1011
1012
		return $this->course_lessons( $course_id, $post_status );
1013
1014
	} // End course_lessons_completed()
1015
1016
1017
	/**
1018
	 * course_author_lesson_count function.
1019
	 *
1020
	 * @access public
1021
	 * @param  int $author_id (default: 0)
1022
	 * @param  int $course_id (default: 0)
1023
	 * @return int
1024
	 */
1025 View Code Duplication
	public function course_author_lesson_count( $author_id = 0, $course_id = 0 ) {
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...
1026
1027
        $lesson_args = array(	'post_type' 		=> 'lesson',
1028
								'posts_per_page' 		=> -1,
1029
		    					'author'         	=> $author_id,
1030
		    					'meta_key'        	=> '_lesson_course',
1031
    							'meta_value'      	=> $course_id,
1032
    	    					'post_status'      	=> 'publish',
1033
    	    					'suppress_filters' 	=> 0,
1034
								'fields'            => 'ids', // less data to retrieve
1035
		    				);
1036
		$lessons_array = get_posts( $lesson_args );
1037
		$count = count( $lessons_array );
1038
		return $count;
1039
1040
	} // End course_author_lesson_count()
1041
1042
	/**
1043
	 * course_lesson_count function.
1044
	 *
1045
	 * @access public
1046
	 * @param  int $course_id (default: 0)
1047
	 * @return int
1048
	 */
1049 View Code Duplication
	public function course_lesson_count( $course_id = 0 ) {
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...
1050
1051
		$lesson_args = array(	'post_type' 		=> 'lesson',
1052
								'posts_per_page' 		=> -1,
1053
		    					'meta_key'        	=> '_lesson_course',
1054
    							'meta_value'      	=> $course_id,
1055
    	    					'post_status'      	=> 'publish',
1056
    	    					'suppress_filters' 	=> 0,
1057
								'fields'            => 'ids', // less data to retrieve
1058
		    				);
1059
		$lessons_array = get_posts( $lesson_args );
1060
1061
        $count = count( $lessons_array );
1062
1063
        return $count;
1064
1065
	} // End course_lesson_count()
1066
1067
	/**
1068
	 * course_lesson_preview_count function.
1069
	 *
1070
	 * @access public
1071
	 * @param  int $course_id (default: 0)
1072
	 * @return int
1073
	 */
1074 View Code Duplication
	public function course_lesson_preview_count( $course_id = 0 ) {
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...
1075
1076
		$lesson_args = array(	'post_type' 		=> 'lesson',
1077
								'posts_per_page' 		=> -1,
1078
    	    					'post_status'      	=> 'publish',
1079
    	    					'suppress_filters' 	=> 0,
1080
    	    					'meta_query' => array(
1081
									array(
1082
										'key' => '_lesson_course',
1083
										'value' => $course_id
1084
									),
1085
									array(
1086
										'key' => '_lesson_preview',
1087
										'value' => 'preview'
1088
									)
1089
								),
1090
								'fields'            => 'ids', // less data to retrieve
1091
		    				);
1092
		$lessons_array = get_posts( $lesson_args );
1093
1094
		$count = count( $lessons_array );
1095
1096
        return $count;
1097
1098
	} // End course_lesson_count()
1099
1100
	/**
1101
	 * get_product_courses function.
1102
	 *
1103
	 * @access public
1104
	 * @param  int $product_id (default: 0)
1105
	 * @return array
1106
	 */
1107 View Code Duplication
	public function get_product_courses( $product_id = 0 ) {
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...
1108
1109
		$posts_array = array();
1110
		// Check for WooCommerce
1111
		if ( WooThemes_Sensei_Utils::sensei_is_woocommerce_activated() && 0 < $product_id ) {
1112
			$post_args = array(	'post_type' 		=> 'course',
1113
								'posts_per_page' 		=> -1,
1114
								'meta_key'        	=> '_course_woocommerce_product',
1115
	    						'meta_value'      	=> $product_id,
1116
	    						'post_status'       => 'publish',
1117
								'suppress_filters' 	=> 0,
1118
								'orderby' 			=> 'menu_order date',
1119
								'order' 			=> 'ASC',
1120
								);
1121
			$posts_array = get_posts( $post_args );
1122
		} // End If Statement
1123
		return $posts_array;
1124
1125
	} // End get_product_courses()
1126
1127
	/**
1128
	 * single_course_lesson_data sets up frontend data for single course lesson output
1129
	 * @since  1.2.1
1130
	 * @return void
1131
	 */
1132
	public function single_course_lesson_data() {
1133
1134
	} // End single_course_lesson_data()
1135
1136
	/**
1137
	 * Fix posts_per_page for My Courses page
1138
	 * @param  WP_Query $query
1139
	 * @return void
1140
	 */
1141
	public function filter_my_courses( $query ) {
1142
		global  $my_courses_section;
1143
1144 View Code Duplication
		if ( isset( Sensei()->settings->settings[ 'my_course_amount' ] ) && ( 0 < absint( Sensei()->settings->settings[ 'my_course_amount' ] ) ) ) {
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...
1145
			$amount = absint( Sensei()->settings->settings[ 'my_course_amount' ] );
1146
			$query->set( 'posts_per_page', $amount );
1147
		}
1148
1149
		if( isset( $_GET[ $my_courses_section . '_page' ] ) && 0 < intval( $_GET[ $my_courses_section . '_page' ] ) ) {
1150
			$page = intval( $_GET[ $my_courses_section . '_page' ] );
1151
			$query->set( 'paged', $page );
1152
		}
1153
	}
1154
1155
	/**
1156
	 * load_user_courses_content generates HTML for user's active & completed courses
1157
     *
1158
     * This function also ouputs the html so no need to echo the content.
1159
     *
1160
	 * @since  1.4.0
1161
	 * @param  object  $user   Queried user object
1162
	 * @param  boolean $manage Whether the user has permission to manage the courses
0 ignored issues
show
Bug introduced by
There is no parameter named $manage. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
1163
	 * @return string          HTML displayng course data
1164
	 */
1165
	public function load_user_courses_content( $user = false ) {
1166
		global $course, $my_courses_page, $my_courses_section;
1167
1168
        if( ! isset( Sensei()->settings->settings[ 'learner_profile_show_courses' ] )
1169
            || ! Sensei()->settings->settings[ 'learner_profile_show_courses' ] ) {
1170
1171
            // do not show the content if the settings doesn't allow for it
1172
            return;
1173
1174
        }
1175
1176
        $manage = ( $user->ID == get_current_user_id() ) ? true : false;
1177
1178
        do_action( 'sensei_before_learner_course_content', $user );
1179
1180
		// Build Output HTML
1181
		$complete_html = $active_html = '';
1182
1183
		if( is_a( $user, 'WP_User' ) ) {
1184
1185
			$my_courses_page = true;
1186
1187
			// Allow action to be run before My Courses content has loaded
1188
			do_action( 'sensei_before_my_courses', $user->ID );
1189
1190
			// Logic for Active and Completed Courses
1191
			$per_page = 20;
1192
			if ( isset( Sensei()->settings->settings[ 'my_course_amount' ] )
1193
                && ( 0 < absint( Sensei()->settings->settings[ 'my_course_amount' ] ) ) ) {
1194
1195
				$per_page = absint( Sensei()->settings->settings[ 'my_course_amount' ] );
1196
1197
			}
1198
1199
			$course_statuses = WooThemes_Sensei_Utils::sensei_check_for_activity( array( 'user_id' => $user->ID, 'type' => 'sensei_course_status' ), true );
1200
			// User may only be on 1 Course
1201
			if ( !is_array($course_statuses) ) {
1202
				$course_statuses = array( $course_statuses );
1203
			}
1204
			$completed_ids = $active_ids = array();
1205
			foreach( $course_statuses as $course_status ) {
1206
				if ( WooThemes_Sensei_Utils::user_completed_course( $course_status, $user->ID ) ) {
1207
					$completed_ids[] = $course_status->comment_post_ID;
1208
				} else {
1209
					$active_ids[] = $course_status->comment_post_ID;
1210
				}
1211
			}
1212
1213
			$active_count = $completed_count = 0;
1214
1215
			$active_courses = array();
1216 View Code Duplication
			if ( 0 < intval( count( $active_ids ) ) ) {
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...
1217
				$my_courses_section = 'active';
1218
				$active_courses = Sensei()->course->course_query( $per_page, 'usercourses', $active_ids );
1219
				$active_count = count( $active_ids );
1220
			} // End If Statement
1221
1222
			$completed_courses = array();
1223 View Code Duplication
			if ( 0 < intval( count( $completed_ids ) ) ) {
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...
1224
				$my_courses_section = 'completed';
1225
				$completed_courses = Sensei()->course->course_query( $per_page, 'usercourses', $completed_ids );
1226
				$completed_count = count( $completed_ids );
1227
			} // End If Statement
1228
1229
			foreach ( $active_courses as $course_item ) {
1230
1231
				$course_lessons =  Sensei()->course->course_lessons( $course_item->ID );
1232
				$lessons_completed = 0;
1233
				foreach ( $course_lessons as $lesson ) {
1234
					if ( WooThemes_Sensei_Utils::user_completed_lesson( $lesson->ID, $user->ID ) ) {
1235
						++$lessons_completed;
1236
					}
1237
				}
1238
1239
			    // Get Course Categories
1240
			    $category_output = get_the_term_list( $course_item->ID, 'course-category', '', ', ', '' );
1241
1242
                $active_html .= '<article class="' . esc_attr( join( ' ', get_post_class( array( 'course', 'post' ), $course_item->ID ) ) ) . '">';
1243
1244
                // Image
1245
                $active_html .= Sensei()->course->course_image( absint( $course_item->ID ), '100','100', true );
1246
1247
                // Title
1248
                $active_html .= '<header>';
1249
1250
                $active_html .= '<h2><a href="' . esc_url( get_permalink( absint( $course_item->ID ) ) ) . '" title="' . esc_attr( $course_item->post_title ) . '">' . esc_html( $course_item->post_title ) . '</a></h2>';
1251
1252
                $active_html .= '</header>';
1253
1254
                $active_html .= '<section class="entry">';
1255
1256
                $active_html .= '<p class="sensei-course-meta">';
1257
1258
                // Author
1259
                $user_info = get_userdata( absint( $course_item->post_author ) );
1260 View Code Duplication
                if ( isset( Sensei()->settings->settings[ 'course_author' ] )
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...
1261
                    && ( Sensei()->settings->settings[ 'course_author' ] ) ) {
1262
1263
                    $active_html .= '<span class="course-author">'
1264
                        . __( 'by ', 'woothemes-sensei' )
1265
                        . '<a href="' . esc_url( get_author_posts_url( absint( $course_item->post_author ) ) )
1266
                        . '" title="' . esc_attr( $user_info->display_name ) . '">'
1267
                        . esc_html( $user_info->display_name )
1268
                        . '</a></span>';
1269
1270
                } // End If Statement
1271
1272
                // Lesson count for this author
1273
                $lesson_count = Sensei()->course->course_lesson_count( absint( $course_item->ID ) );
1274
                // Handle Division by Zero
1275
                if ( 0 == $lesson_count ) {
1276
1277
                    $lesson_count = 1;
1278
1279
                } // End If Statement
1280
                $active_html .= '<span class="course-lesson-count">' . $lesson_count . '&nbsp;' .  __( 'Lessons', 'woothemes-sensei' ) . '</span>';
1281
                // Course Categories
1282
                if ( '' != $category_output ) {
1283
1284
                    $active_html .= '<span class="course-category">' . sprintf( __( 'in %s', 'woothemes-sensei' ), $category_output ) . '</span>';
1285
1286
                } // End If Statement
1287
                $active_html .= '<span class="course-lesson-progress">' . sprintf( __( '%1$d of %2$d lessons completed', 'woothemes-sensei' ) , $lessons_completed, $lesson_count  ) . '</span>';
1288
1289
                $active_html .= '</p>';
1290
1291
                $active_html .= '<p class="course-excerpt">' . $course_item->post_excerpt . '</p>';
1292
1293
1294
1295
                $progress_percentage = abs( round( ( doubleval( $lessons_completed ) * 100 ) / ( $lesson_count ), 0 ) );
1296
1297
                $active_html .= $this->get_progress_meter( $progress_percentage );
1298
1299
                $active_html .= '</section>';
1300
1301
                if( is_user_logged_in() ) {
1302
1303
                    $active_html .= '<section class="entry-actions">';
1304
1305
                    $active_html .= '<form method="POST" action="' . esc_url( remove_query_arg( array( 'active_page', 'completed_page' ) ) ) . '">';
1306
1307
                    $active_html .= '<input type="hidden" name="' . esc_attr( 'woothemes_sensei_complete_course_noonce' ) . '" id="' . esc_attr( 'woothemes_sensei_complete_course_noonce' ) . '" value="' . esc_attr( wp_create_nonce( 'woothemes_sensei_complete_course_noonce' ) ) . '" />';
1308
1309
                    $active_html .= '<input type="hidden" name="course_complete_id" id="course-complete-id" value="' . esc_attr( absint( $course_item->ID ) ) . '" />';
1310
1311
                    if ( 0 < absint( count( $course_lessons ) ) && Sensei()->settings->settings['course_completion'] == 'complete' ) {
1312
1313
                        $active_html .= '<span><input name="course_complete" type="submit" class="course-complete" value="'
1314
                            .  __( 'Mark as Complete', 'woothemes-sensei' ) . '"/> </span>';
1315
1316
                    } // End If Statement
1317
1318
                    $course_purchased = false;
1319
                    if ( Sensei_WC::is_woocommerce_active() ) {
1320
1321
                        // Get the product ID
1322
                        $wc_post_id = get_post_meta( absint( $course_item->ID ), '_course_woocommerce_product', true );
1323
                        if ( 0 < $wc_post_id ) {
1324
1325
                            $course_purchased = Sensei_WC::has_customer_bought_product(  $user->ID, $wc_post_id );
1326
1327
                        } // End If Statement
1328
1329
                    } // End If Statement
1330
1331
                    if ( false == $course_purchased ) {
1332
1333
                        $active_html .= '<span><input name="course_complete" type="submit" class="course-delete" value="'
1334
                            .  __( 'Delete Course', 'woothemes-sensei' ) . '"/></span>';
1335
1336
                    } // End If Statement
1337
1338
                    $active_html .= '</form>';
1339
1340
                    $active_html .= '</section>';
1341
                }
1342
1343
                $active_html .= '</article>';
1344
			}
1345
1346
			// Active pagination
1347 View Code Duplication
			if( $active_count > $per_page ) {
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...
1348
1349
				$current_page = 1;
1350
				if( isset( $_GET['active_page'] ) && 0 < intval( $_GET['active_page'] ) ) {
1351
					$current_page = $_GET['active_page'];
1352
				}
1353
1354
				$active_html .= '<nav class="pagination woo-pagination">';
1355
				$total_pages = ceil( $active_count / $per_page );
1356
1357
				if( $current_page > 1 ) {
1358
					$prev_link = add_query_arg( 'active_page', $current_page - 1 );
1359
					$active_html .= '<a class="prev page-numbers" href="' . esc_url( $prev_link ) . '">' . __( 'Previous' , 'woothemes-sensei' ) . '</a> ';
1360
				}
1361
1362
				for ( $i = 1; $i <= $total_pages; $i++ ) {
1363
					$link = add_query_arg( 'active_page', $i );
1364
1365
					if( $i == $current_page ) {
1366
						$active_html .= '<span class="page-numbers current">' . $i . '</span> ';
1367
					} else {
1368
						$active_html .= '<a class="page-numbers" href="' . esc_url( $link ). '">' . $i . '</a> ';
1369
					}
1370
				}
1371
1372
				if( $current_page < $total_pages ) {
1373
					$next_link = add_query_arg( 'active_page', $current_page + 1 );
1374
					$active_html .= '<a class="next page-numbers" href="' . esc_url( $next_link ) . '">' . __( 'Next' , 'woothemes-sensei' ) . '</a> ';
1375
				}
1376
1377
				$active_html .= '</nav>';
1378
			}
1379
1380
			foreach ( $completed_courses as $course_item ) {
1381
				$course = $course_item;
1382
1383
			    // Get Course Categories
1384
			    $category_output = get_the_term_list( $course_item->ID, 'course-category', '', ', ', '' );
1385
1386
		    	$complete_html .= '<article class="' . join( ' ', get_post_class( array( 'course', 'post' ), $course_item->ID ) ) . '">';
1387
1388
		    	    // Image
1389
		    		$complete_html .= Sensei()->course->course_image( absint( $course_item->ID ),100, 100, true );
1390
1391
		    		// Title
1392
		    		$complete_html .= '<header>';
1393
1394
		    		    $complete_html .= '<h2><a href="' . esc_url( get_permalink( absint( $course_item->ID ) ) ) . '" title="' . esc_attr( $course_item->post_title ) . '">' . esc_html( $course_item->post_title ) . '</a></h2>';
1395
1396
		    		$complete_html .= '</header>';
1397
1398
		    		$complete_html .= '<section class="entry">';
1399
1400
		    			$complete_html .= '<p class="sensei-course-meta">';
1401
1402
		    		    	// Author
1403
		    		    	$user_info = get_userdata( absint( $course_item->post_author ) );
1404 View Code Duplication
		    		    	if ( isset( Sensei()->settings->settings[ 'course_author' ] ) && ( Sensei()->settings->settings[ 'course_author' ] ) ) {
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...
1405
		    		    		$complete_html .= '<span class="course-author">' . __( 'by ', 'woothemes-sensei' ) . '<a href="' . esc_url( get_author_posts_url( absint( $course_item->post_author ) ) ) . '" title="' . esc_attr( $user_info->display_name ) . '">' . esc_html( $user_info->display_name ) . '</a></span>';
1406
		    		    	} // End If Statement
1407
1408
		    		    	// Lesson count for this author
1409
		    		    	$complete_html .= '<span class="course-lesson-count">'
1410
                                . Sensei()->course->course_lesson_count( absint( $course_item->ID ) )
1411
                                . '&nbsp;' .  __( 'Lessons', 'woothemes-sensei' )
1412
                                . '</span>';
1413
1414
		    		    	// Course Categories
1415
		    		    	if ( '' != $category_output ) {
1416
1417
		    		    		$complete_html .= '<span class="course-category">' . sprintf( __( 'in %s', 'woothemes-sensei' ), $category_output ) . '</span>';
1418
1419
		    		    	} // End If Statement
1420
1421
						$complete_html .= '</p>';
1422
1423
						$complete_html .= '<p class="course-excerpt">' . $course_item->post_excerpt . '</p>';
1424
1425
                        $complete_html .= $this->get_progress_meter( 100 );
1426
1427
						if( $manage ) {
1428
							$has_quizzes = Sensei()->course->course_quizzes( $course_item->ID, true );
1429
							// Output only if there is content to display
1430
							if ( has_filter( 'sensei_results_links' ) || $has_quizzes ) {
1431
1432
1433
								$complete_html .= '<p class="sensei-results-links">';
1434
								$results_link = '';
1435 View Code Duplication
								if( $has_quizzes ) {
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...
1436
1437
									$results_link = '<a class="button view-results" href="'
1438
                                        . Sensei()->course_results->get_permalink( $course_item->ID )
1439
                                        . '">' . __( 'View results', 'woothemes-sensei' )
1440
                                        . '</a>';
1441
								}
1442
								$complete_html .= apply_filters( 'sensei_results_links', $results_link );
1443
								$complete_html .= '</p>';
1444
1445
							}
1446
						}
1447
1448
		    		$complete_html .= '</section>';
1449
1450
		    	$complete_html .= '</article>';
1451
			}
1452
1453
			// Active pagination
1454 View Code Duplication
			if( $completed_count > $per_page ) {
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...
1455
1456
				$current_page = 1;
1457
				if( isset( $_GET['completed_page'] ) && 0 < intval( $_GET['completed_page'] ) ) {
1458
					$current_page = $_GET['completed_page'];
1459
				}
1460
1461
				$complete_html .= '<nav class="pagination woo-pagination">';
1462
				$total_pages = ceil( $completed_count / $per_page );
1463
1464
1465
				if( $current_page > 1 ) {
1466
					$prev_link = add_query_arg( 'completed_page', $current_page - 1 );
1467
					$complete_html .= '<a class="prev page-numbers" href="' . esc_url( $prev_link ) . '">' . __( 'Previous' , 'woothemes-sensei' ) . '</a> ';
1468
				}
1469
1470
				for ( $i = 1; $i <= $total_pages; $i++ ) {
1471
					$link = add_query_arg( 'completed_page', $i );
1472
1473
					if( $i == $current_page ) {
1474
						$complete_html .= '<span class="page-numbers current">' . $i . '</span> ';
1475
					} else {
1476
						$complete_html .= '<a class="page-numbers" href="' . esc_url( $link ) . '">' . $i . '</a> ';
1477
					}
1478
				}
1479
1480
				if( $current_page < $total_pages ) {
1481
					$next_link = add_query_arg( 'completed_page', $current_page + 1 );
1482
					$complete_html .= '<a class="next page-numbers" href="' . esc_url( $next_link ) . '">' . __( 'Next' , 'woothemes-sensei' ) . '</a> ';
1483
				}
1484
1485
				$complete_html .= '</nav>';
1486
			}
1487
1488
		} // End If Statement
1489
1490
		if( $manage ) {
1491
			$no_active_message = __( 'You have no active courses.', 'woothemes-sensei' );
1492
			$no_complete_message = __( 'You have not completed any courses yet.', 'woothemes-sensei' );
1493
		} else {
1494
			$no_active_message =  __( 'This learner has no active courses.', 'woothemes-sensei' );
1495
			$no_complete_message =  __( 'This learner has not completed any courses yet.', 'woothemes-sensei' );
1496
		}
1497
1498
		ob_start();
1499
		?>
1500
1501
		<?php do_action( 'sensei_before_user_courses' ); ?>
1502
1503
		<?php
1504
		if( $manage && ( ! isset( Sensei()->settings->settings['messages_disable'] ) || ! Sensei()->settings->settings['messages_disable'] ) ) {
1505
			?>
1506
			<p class="my-messages-link-container">
1507
                <a class="my-messages-link" href="<?php echo get_post_type_archive_link( 'sensei_message' ); ?>"
1508
                   title="<?php _e( 'View & reply to private messages sent to your course & lesson teachers.', 'woothemes-sensei' ); ?>">
1509
                    <?php _e( 'My Messages', 'woothemes-sensei' ); ?>
1510
                </a>
1511
            </p>
1512
			<?php
1513
		}
1514
		?>
1515
		<div id="my-courses">
1516
1517
		    <ul>
1518
		    	<li><a href="#active-courses"><?php  _e( 'Active Courses', 'woothemes-sensei' ); ?></a></li>
1519
		    	<li><a href="#completed-courses"><?php  _e( 'Completed Courses', 'woothemes-sensei' ); ?></a></li>
1520
		    </ul>
1521
1522
		    <?php do_action( 'sensei_before_active_user_courses' ); ?>
1523
1524
		    <?php
1525
            $course_page_url = Sensei_Course::get_courses_page_url();
1526
            ?>
1527
1528
		    <div id="active-courses">
1529
1530
		    	<?php if ( '' != $active_html ) {
1531
1532
		    		echo $active_html;
1533
1534
		    	} else { ?>
1535
1536
		    		<div class="sensei-message info">
1537
1538
                        <?php echo $no_active_message; ?>
1539
1540
                        <a href="<?php echo $course_page_url; ?>">
1541
1542
                            <?php  _e( 'Start a Course!', 'woothemes-sensei' ); ?>
1543
1544
                        </a>
1545
1546
                    </div>
1547
1548
		    	<?php } // End If Statement ?>
1549
1550
		    </div>
1551
1552
		    <?php do_action( 'sensei_after_active_user_courses' ); ?>
1553
1554
		    <?php do_action( 'sensei_before_completed_user_courses' ); ?>
1555
1556
		    <div id="completed-courses">
1557
1558
		    	<?php if ( '' != $complete_html ) {
1559
1560
		    		echo $complete_html;
1561
1562
		    	} else { ?>
1563
1564
		    		<div class="sensei-message info">
1565
1566
                        <?php echo $no_complete_message; ?>
1567
1568
                    </div>
1569
1570
		    	<?php } // End If Statement ?>
1571
1572
		    </div>
1573
1574
		    <?php do_action( 'sensei_after_completed_user_courses' ); ?>
1575
1576
		</div>
1577
1578
		<?php do_action( 'sensei_after_user_courses' ); ?>
1579
1580
		<?php
1581
        echo ob_get_clean();
1582
1583
        do_action( 'sensei_after_learner_course_content', $user );
1584
1585
	} // end load_user_courses_content
1586
1587
    /**
1588
     * Returns a list of all courses
1589
     *
1590
     * @since 1.8.0
1591
     * @return array $courses{
1592
     *  @type $course WP_Post
1593
     * }
1594
     */
1595
    public static function get_all_courses(){
1596
1597
        $args = array(
1598
               'post_type' => 'course',
1599
                'posts_per_page' 		=> -1,
1600
                'orderby'         	=> 'title',
1601
                'order'           	=> 'ASC',
1602
                'post_status'      	=> 'any',
1603
                'suppress_filters' 	=> 0,
1604
        );
1605
1606
        $wp_query_obj =  new WP_Query( $args );
1607
1608
        /**
1609
         * sensei_get_all_courses filter
1610
         *
1611
         * This filter runs inside Sensei_Course::get_all_courses.
1612
         *
1613
         * @param array $courses{
1614
         *  @type WP_Post
1615
         * }
1616
         * @param array $attributes
1617
         */
1618
        return apply_filters( 'sensei_get_all_courses' , $wp_query_obj->posts );
1619
1620
    }// end get_all_courses
1621
1622
    /**
1623
     * Generate the course meter component
1624
     *
1625
     * @since 1.8.0
1626
     * @param int $progress_percentage 0 - 100
1627
     * @return string $progress_bar_html
1628
     */
1629
    public function get_progress_meter( $progress_percentage ){
1630
1631
        if ( 50 < $progress_percentage ) {
1632
            $class = ' green';
1633
        } elseif ( 25 <= $progress_percentage && 50 >= $progress_percentage ) {
1634
            $class = ' orange';
1635
        } else {
1636
            $class = ' red';
1637
        }
1638
        $progress_bar_html = '<div class="meter' . esc_attr( $class ) . '"><span style="width: ' . $progress_percentage . '%">' . round( $progress_percentage ) . '%</span></div>';
1639
1640
        return $progress_bar_html;
1641
1642
    }// end get_progress_meter
1643
1644
    /**
1645
     * Generate a statement that tells users
1646
     * how far they are in the course.
1647
     *
1648
     * @param int $course_id
1649
     * @param int $user_id
1650
     *
1651
     * @return string $statement_html
1652
     */
1653
    public function get_progress_statement( $course_id, $user_id ){
1654
1655
        if( empty( $course_id ) || empty( $user_id )
1656
        || ! WooThemes_Sensei_Utils::user_started_course( $course_id, $user_id ) ){
0 ignored issues
show
Bug Best Practice introduced by
The expression \WooThemes_Sensei_Utils:...e($course_id, $user_id) of type false|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1657
            return '';
1658
        }
1659
1660
        $completed = count( $this->get_completed_lesson_ids( $course_id, $user_id ) );
1661
        $total_lessons = count( $this->course_lessons( $course_id ) );
1662
1663
        $statement = sprintf( _n('Currently completed %s lesson of %s in total', 'Currently completed %s lessons of %s in total', $completed, 'woothemes-sensei'), $completed, $total_lessons );
1664
1665
        /**
1666
         * Filter the course completion statement.
1667
         * Default Currently completed $var lesson($plural) of $var in total
1668
         *
1669
         * @param string $statement
1670
         */
1671
        return apply_filters( 'sensei_course_completion_statement', $statement );
1672
1673
    }// end generate_progress_statement
1674
1675
    /**
1676
     * Output the course progress statement
1677
     *
1678
     * @param $course_id
1679
     * @return void
1680
     */
1681
    public function the_progress_statement( $course_id = 0, $user_id = 0 ){
1682
        if( empty( $course_id ) ){
1683
            global $post;
1684
            $course_id = $post->ID;
1685
        }
1686
1687
        if( empty( $user_id ) ){
1688
            $user_id = get_current_user_id();
1689
        }
1690
1691
        echo '<span class="progress statement  course-completion-rate">' . $this->get_progress_statement( $course_id, $user_id  ) . '</span>';
1692
    }
1693
1694
    /**
1695
     * Output the course progress bar
1696
     *
1697
     * @param $course_id
1698
     * @return void
1699
     */
1700
    public function the_progress_meter( $course_id = 0, $user_id = 0 ){
1701
1702
        if( empty( $course_id ) ){
1703
            global $post;
1704
            $course_id = $post->ID;
1705
        }
1706
1707
        if( empty( $user_id ) ){
1708
            $user_id = get_current_user_id();
1709
        }
1710
1711
        if( 'course' != get_post_type( $course_id ) || ! get_userdata( $user_id )
1712
            || ! WooThemes_Sensei_Utils::user_started_course( $course_id ,$user_id ) ){
0 ignored issues
show
Bug Best Practice introduced by
The expression \WooThemes_Sensei_Utils:...e($course_id, $user_id) of type false|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1713
            return;
1714
        }
1715
        $percentage_completed = $this->get_completion_percentage( $course_id, $user_id );
1716
1717
        echo $this->get_progress_meter( $percentage_completed );
1718
1719
    }// end the_progress_meter
1720
1721
    /**
1722
     * Checks how many lessons are completed
1723
     *
1724
     * @since 1.8.0
1725
     *
1726
     * @param int $course_id
1727
     * @param int $user_id
1728
     * @return array $completed_lesson_ids
1729
     */
1730
    public function get_completed_lesson_ids( $course_id, $user_id = 0 ){
1731
1732
        if( !( intval( $user_id ) ) > 0 ){
1733
            $user_id = get_current_user_id();
1734
        }
1735
1736
        $completed_lesson_ids = array();
1737
1738
        $course_lessons = $this->course_lessons( $course_id );
1739
1740
        foreach( $course_lessons as $lesson ){
1741
1742
            $is_lesson_completed = WooThemes_Sensei_Utils::user_completed_lesson( $lesson->ID, $user_id );
1743
            if( $is_lesson_completed ){
1744
                $completed_lesson_ids[] = $lesson->ID;
1745
            }
1746
1747
        }
1748
1749
        return $completed_lesson_ids;
1750
1751
    }// end get_completed_lesson_ids
1752
1753
    /**
1754
     * Calculate the perceantage completed in the course
1755
     *
1756
     * @since 1.8.0
1757
     *
1758
     * @param int $course_id
1759
     * @param int $user_id
1760
     * @return int $percentage
1761
     */
1762
    public function get_completion_percentage( $course_id, $user_id = 0 ){
1763
1764
        if( !( intval( $user_id ) ) > 0 ){
1765
            $user_id = get_current_user_id();
1766
        }
1767
1768
        $completed = count( $this->get_completed_lesson_ids( $course_id, $user_id ) );
1769
1770
        if( ! (  $completed  > 0 ) ){
1771
            return 0;
1772
        }
1773
1774
        $total_lessons = count( $this->course_lessons( $course_id ) );
1775
        $percentage = $completed / $total_lessons * 100;
1776
1777
        /**
1778
         *
1779
         * Filter the percentage returned for a users course.
1780
         *
1781
         * @param $percentage
1782
         * @param $course_id
1783
         * @param $user_id
1784
         * @since 1.8.0
1785
         */
1786
        return apply_filters( 'sensei_course_completion_percentage', $percentage, $course_id, $user_id );
1787
1788
    }// end get_completed_lesson_ids
1789
1790
    /**
1791
     * Block email notifications for the specific courses
1792
     * that the user disabled the notifications.
1793
     *
1794
     * @since 1.8.0
1795
     * @param $should_send
1796
     * @return bool
1797
     */
1798
    public function block_notification_emails( $should_send ){
1799
        global $sensei_email_data;
1800
        $email = $sensei_email_data;
1801
1802
        $course_id = '';
1803
1804
        if( isset( $email['course_id'] ) ){
1805
1806
            $course_id = $email['course_id'];
1807
1808
        }elseif( isset( $email['lesson_id'] ) ){
1809
1810
            $course_id = Sensei()->lesson->get_course_id( $email['lesson_id'] );
1811
1812
        }elseif( isset( $email['quiz_id'] ) ){
1813
1814
            $lesson_id = Sensei()->quiz->get_lesson_id( $email['quiz_id'] );
1815
            $course_id = Sensei()->lesson->get_course_id( $lesson_id );
1816
1817
        }
1818
1819
        if( !empty( $course_id ) && 'course'== get_post_type( $course_id ) ) {
1820
1821
            $course_emails_disabled = get_post_meta($course_id, 'disable_notification', true);
1822
1823
            if ($course_emails_disabled) {
1824
1825
                return false;
1826
1827
            }
1828
1829
        }// end if
1830
1831
        return $should_send;
1832
    }// end block_notification_emails
1833
1834
    /**
1835
     * Render the course notification setting meta box
1836
     *
1837
     * @since 1.8.0
1838
     * @param $course
1839
     */
1840
    public function course_notification_meta_box_content( $course ){
1841
1842
        $checked = get_post_meta( $course->ID , 'disable_notification', true );
1843
1844
        // generate checked html
1845
        $checked_html = '';
1846
        if( $checked ){
1847
            $checked_html = 'checked="checked"';
1848
        }
1849
        wp_nonce_field( 'update-course-notification-setting','_sensei_course_notification' );
1850
1851
        echo '<input id="disable_sensei_course_notification" '.$checked_html .' type="checkbox" name="disable_sensei_course_notification" >';
1852
        echo '<label for="disable_sensei_course_notification">'.__('Disable notifications on this course ?', 'woothemes-sensei'). '</label>';
1853
1854
    }// end course_notification_meta_box_content
1855
1856
    /**
1857
     * Store the setting for the course notification setting.
1858
     *
1859
     * @hooked int save_post
1860
     * @since 1.8.0
1861
     *
1862
     * @param $course_id
1863
     */
1864
    public function save_course_notification_meta_box( $course_id ){
1865
1866
        if( !isset( $_POST['_sensei_course_notification']  )
1867
            || ! wp_verify_nonce( $_POST['_sensei_course_notification'], 'update-course-notification-setting' ) ){
1868
            return;
1869
        }
1870
1871
        if( isset( $_POST['disable_sensei_course_notification'] ) && 'on'== $_POST['disable_sensei_course_notification']  ) {
1872
            $new_val = true;
1873
        }else{
1874
            $new_val = false;
1875
        }
1876
1877
       update_post_meta( $course_id , 'disable_notification', $new_val );
1878
1879
    }// end save notification meta box
1880
1881
    /**
1882
     * Backwards compatibility hooks added to ensure that
1883
     * plugins and other parts of sensei still works.
1884
     *
1885
     * This function hooks into `sensei_course_content_inside_before`
1886
     *
1887
     * @since 1.9
1888
     *
1889
     * @param WP_Post $post
1890
     */
1891
    public function content_before_backwards_compatibility_hooks( $post ){
1892
1893
        if( has_action( 'sensei_course_image' ) ){
1894
1895
            _doing_it_wrong('sensei_course_image','This action has been retired: . Please use sensei_course_content_inside_before instead.', '1.9' );
1896
            do_action('sensei_course_image', $post->ID );
1897
1898
        }
1899
1900
        if( has_action( 'sensei_course_archive_course_title' ) ){
1901
1902
            _doing_it_wrong('sensei_course_archive_course_title','This action has been retired: . Please use sensei_course_content_inside_before instead.', '1.9' );
1903
            do_action('sensei_course_archive_course_title', $post );
1904
1905
        }
1906
1907
    }
1908
1909
    /**
1910
     * Backwards compatibility hooks that should be hooked into sensei_loop_course_before
1911
     *
1912
     * hooked into 'sensei_loop_course_before'
1913
     *
1914
     * @since 1.9
1915
     *
1916
     * @global WP_Post $post
1917
     */
1918
    public  function loop_before_backwards_compatibility_hooks( ){
1919
1920
        global $post;
1921
        sensei_do_deprecated_action( 'sensei_course_archive_header','1.9.0','sensei_course_content_inside_before', $post->post_type  );
1922
1923
    }
1924
1925
    /**
1926
     * Output a link to view course. The button text is different depending on the amount of preview lesson available.
1927
     *
1928
     * hooked into 'sensei_course_content_inside_after'
1929
     *
1930
     * @since 1.9.0
1931
     *
1932
     * @param WP_Post $course
1933
     */
1934
    public function the_course_free_lesson_preview( $course ){
1935
        // Meta data
1936
        $preview_lesson_count = intval( Sensei()->course->course_lesson_preview_count( $course->ID ) );
1937
        $is_user_taking_course = WooThemes_Sensei_Utils::user_started_course( $course->ID, get_current_user_id() );
1938
1939 View Code Duplication
        if ( 0 < $preview_lesson_count && !$is_user_taking_course ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $is_user_taking_course of type false|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
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...
1940
            ?>
1941
            <p class="sensei-free-lessons">
1942
                <a href="<?php echo get_permalink(); ?>">
1943
                    <?php _e( 'Preview this course', 'woothemes-sensei' ) ?>
1944
                </a>
1945
                - <?php echo sprintf( __( '(%d preview lessons)', 'woothemes-sensei' ), $preview_lesson_count ) ; ?>
1946
            </p>
1947
1948
        <?php
1949
        }
1950
    }
1951
1952
    /**
1953
     * Add course mata to the course meta hook
1954
     *
1955
     * @since 1.9.0
1956
     * @param WP_Post $course
1957
     */
1958
    public function the_course_meta( $course ){
1959
        echo '<p class="sensei-course-meta">';
1960
1961
        $category_output = get_the_term_list( $course->ID, 'course-category', '', ', ', '' );
1962
        $author_display_name = get_the_author_meta( 'display_name', $course->post_author  );
1963
1964
        if ( isset( Sensei()->settings->settings[ 'course_author' ] ) && ( Sensei()->settings->settings[ 'course_author' ] ) ) {?>
1965
1966
            <span class="course-author"><?php _e( 'by ', 'woothemes-sensei' ); ?>
1967
1968
                <a href="<?php esc_attr_e( get_author_posts_url( $course->post_author ) ); ?>" title="<?php esc_attr_e( $author_display_name ); ?>"><?php esc_attr_e( $author_display_name   ); ?></a>
1969
1970
            </span>
1971
1972
        <?php } // End If Statement ?>
1973
1974
        <span class="course-lesson-count"><?php echo Sensei()->course->course_lesson_count( $course->ID ) . '&nbsp;' .  __( 'Lessons', 'woothemes-sensei' ); ?></span>
1975
1976
       <?php if ( '' != $category_output ) { ?>
1977
1978
            <span class="course-category"><?php echo sprintf( __( 'in %s', 'woothemes-sensei' ), $category_output ); ?></span>
1979
1980
        <?php } // End If Statement
1981
1982
        // number of completed lessons
1983
        if( is_user_logged_in() ){
1984
            $completed = count( $this->get_completed_lesson_ids( $course->ID, get_current_user_id() ) );
1985
            $lesson_count = count( $this->course_lessons( $course->ID ) );
1986
            echo '<span class="course-lesson-progress">' . sprintf( __( '%1$d of %2$d lessons completed', 'woothemes-sensei' ) , $completed, $lesson_count  ) . '</span>';
1987
        }
1988
1989
        sensei_simple_course_price( $course->ID );
1990
1991
        echo '</p>';
1992
    } // end the course meta
1993
1994
    /**
1995
     * Filter the classes attached to a post types for courses
1996
     * and add a status class for when the user is logged in.
1997
     *
1998
     * @param $classes
1999
     * @param $class
2000
     * @param $post_id
2001
     *
2002
     * @return array $classes
2003
     */
2004
    public static function add_course_user_status_class( $classes, $class, $course_id ){
2005
2006
        if( 'course' == get_post_type( $course_id )  &&  is_user_logged_in() ){
2007
2008
            if( WooThemes_Sensei_Utils::user_completed_course( $course_id, get_current_user_id() ) ){
2009
2010
                $classes[] = 'user-status-completed';
2011
2012
            }else{
2013
2014
                $classes[] = 'user-status-active';
2015
2016
            }
2017
2018
        }
2019
2020
        return $classes;
2021
2022
    }// end add_course_user_status_class
2023
2024
    /**
2025
     * Prints out the course action buttons links
2026
     *
2027
     * - complete course
2028
     * - delete course
2029
     *
2030
     * @param WP_Post $course
2031
     */
2032
    public static function the_course_action_buttons( $course ){
2033
2034
        if( is_user_logged_in() ) { ?>
2035
2036
            <section class="entry-actions">
2037
                <form method="POST" action="<?php  echo esc_url( remove_query_arg( array( 'active_page', 'completed_page' ) ) ); ?>">
2038
2039
                    <input type="hidden"
2040
                           name="<?php esc_attr_e( 'woothemes_sensei_complete_course_noonce' ) ?>"
2041
                           id="<?php  esc_attr_e( 'woothemes_sensei_complete_course_noonce' ); ?>"
2042
                           value="<?php esc_attr_e( wp_create_nonce( 'woothemes_sensei_complete_course_noonce' ) ); ?>"
2043
                        />
2044
2045
                    <input type="hidden" name="course_complete_id" id="course-complete-id" value="<?php esc_attr_e( intval( $course->ID ) ); ?>" />
2046
2047
                    <?php if ( 0 < absint( count( Sensei()->course->course_lessons( $course->ID ) ) ) && Sensei()->settings->settings['course_completion'] == 'complete' ) { ?>
2048
2049
                        <span><input name="course_complete" type="submit" class="course-complete" value="<?php  _e( 'Mark as Complete', 'woothemes-sensei' ); ?>" /></span>
2050
2051
                   <?php  } // End If Statement
2052
2053
                    $course_purchased = false;
2054
                    if ( WooThemes_Sensei_Utils::sensei_is_woocommerce_activated() ) {
2055
                        // Get the product ID
2056
                        $wc_post_id = get_post_meta( intval( $course->ID ), '_course_woocommerce_product', true );
2057
                        if ( 0 < $wc_post_id ) {
2058
2059
                            $user = wp_get_current_user();
2060
                            $course_purchased = WooThemes_Sensei_Utils::sensei_customer_bought_product( $user->user_email, $user->ID, $wc_post_id );
0 ignored issues
show
Deprecated Code introduced by
The method Sensei_Utils::sensei_customer_bought_product() has been deprecated with message: since 1.9.0 use Sensei_WC::has_customer_bought_product($user_id, $product_id)

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
2061
2062
                        } // End If Statement
2063
                    } // End If Statement
2064
2065
                    if ( ! $course_purchased && ! WooThemes_Sensei_Utils::user_completed_course( $course->ID, get_current_user_id() ) ) {?>
0 ignored issues
show
Bug Best Practice introduced by
The expression $course_purchased of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
2066
2067
                        <span><input name="course_complete" type="submit" class="course-delete" value="<?php echo __( 'Delete Course', 'woothemes-sensei' ); ?>"/></span>
2068
2069
                    <?php } // End If Statement
2070
2071
                    $has_quizzes = Sensei()->course->course_quizzes( $course->ID, true );
2072
                    $results_link = '';
2073 View Code Duplication
                    if( $has_quizzes ){
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...
2074
                        $results_link = '<a class="button view-results" href="' . Sensei()->course_results->get_permalink( $course->ID ) . '">' . __( 'View results', 'woothemes-sensei' ) . '</a>';
2075
                    }
2076
2077
                    // Output only if there is content to display
2078
                    if ( has_filter( 'sensei_results_links' ) || $has_quizzes ) { ?>
2079
2080
                        <p class="sensei-results-links">
2081
                            <?php echo apply_filters( 'sensei_results_links', $results_link ); ?>
2082
                        </p>
2083
2084
                    <?php } // end if has filter  ?>
2085
                </form>
2086
            </section>
2087
2088
        <?php  }// end if is user logged in
2089
2090
    }// end the_course_action_buttons
2091
2092
    /**
2093
     * This function alter the main query on the course archive page.
2094
     * This also gives Sensei specific filters that allows variables to be altered specifically on the course archive.
2095
     *
2096
     * This function targets only the course archives and the my courses page. Shortcodes can set their own
2097
     * query parameters via the arguments.
2098
     *
2099
     * This function is hooked into pre_get_posts filter
2100
     *
2101
     * @since 1.9.0
2102
     *
2103
     * @param WP_Query $query
2104
     * @return WP_Query $query
2105
     */
2106
    public static function course_query_filter( $query ){
2107
2108
        // exit early for no course queries and admin queries
2109
        if( is_admin( ) || 'course' != $query->get( 'post_type' ) ){
2110
            return $query;
2111
        }
2112
2113
        global $post; // used to get the current page id for my courses
2114
2115
        // for the course archive page
2116
        if( $query->is_main_query() && is_post_type_archive('course') )
2117
        {
2118
2119
            $query->set( 'posts_per_page', apply_filters( 'sensei_archive_courses_per_page', get_option( 'posts_per_page' ) ) );
2120
2121
        }
2122
        // for the my courses page
2123
        elseif( is_page() && Sensei()->settings->get( 'my_course_page' ) == $post->ID  )
2124
        {
2125
2126
            $query->set( 'posts_per_page', apply_filters( 'sensei_my_courses_per_page', get_option( 'posts_per_page' ) ) );
2127
2128
        }
2129
2130
        return $query;
2131
2132
    }// end course_query_filter
2133
2134
    /**
2135
     * Determine the class of the course loop
2136
     *
2137
     * This will output .first or .last and .course-item-number-x
2138
     *
2139
     * @return array $extra_classes
2140
     * @since 1.9.0
2141
     */
2142
    public static function get_course_loop_content_class ()
2143
    {
2144
2145
        global $sensei_course_loop;
2146
2147
2148
        if( !isset( $sensei_course_loop ) ){
2149
            $sensei_course_loop = array();
2150
        }
2151
2152
        if (!isset($sensei_course_loop['counter'])) {
2153
            $sensei_course_loop['counter'] = 0;
2154
        }
2155
2156
        if (!isset($sensei_course_loop['columns'])) {
2157
            $sensei_course_loop['columns'] = self::get_loop_number_of_columns();
2158
        }
2159
2160
        // increment the counter
2161
        $sensei_course_loop['counter']++;
2162
2163
        $extra_classes = array();
2164
        if( 0 == ( $sensei_course_loop['counter'] - 1 ) % $sensei_course_loop['columns'] || 1 == $sensei_course_loop['columns']  ){
2165
            $extra_classes[] = 'first';
2166
        }
2167
2168
        if( 0 == $sensei_course_loop['counter'] % $sensei_course_loop['columns']  ){
2169
            $extra_classes[] = 'last';
2170
        }
2171
2172
        // add the item number to the classes as well.
2173
        $extra_classes[] = 'loop-item-number-'. $sensei_course_loop['counter'];
2174
2175
        /**
2176
         * Filter the course loop class the fires in the  in get_course_loop_content_class function
2177
         * which is called from the course loop content-course.php
2178
         *
2179
         * @since 1.9.0
2180
         *
2181
         * @param array $extra_classes
2182
         * @param WP_Post $loop_current_course
2183
         */
2184
        return apply_filters( 'sensei_course_loop_content_class', $extra_classes ,get_post() );
2185
2186
    }// end get_course_loop_class
2187
2188
    /**
2189
     * Get the number of columns set for Sensei courses
2190
     *
2191
     * @since 1.9.0
2192
     * @return mixed|void
2193
     */
2194
    public static function get_loop_number_of_columns(){
2195
2196
        /**
2197
         * Filter the number of columns on the course archive page.
2198
         *
2199
         * @since 1.9.0
2200
         * @param int $number_of_columns default 1
2201
         */
2202
        return apply_filters('sensei_course_loop_number_of_columns', 1);
2203
2204
    }
2205
2206
    /**
2207
     * Output the course archive filter markup
2208
     *
2209
     * hooked into sensei_loop_course_before
2210
     *
2211
     * @since 1.9.0
2212
     * @param
2213
     */
2214
    public static function course_archive_sorting( $query ){
0 ignored issues
show
Unused Code introduced by
The parameter $query is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2215
2216
        // don't show on category pages and other pages
2217
        if( ! is_archive(  'course ') || is_tax('course-category') ){
2218
            return;
2219
        }
2220
2221
        /**
2222
         * Filter the sensei archive course order by values
2223
         *
2224
         * @since 1.9.0
2225
         * @param array $options {
2226
         *  @type string $option_value
2227
         *  @type string $option_string
2228
         * }
2229
         */
2230
        $course_order_by_options = apply_filters( 'sensei_archive_course_order_by_options', array(
2231
            "newness"     => __( "Sort by newest first", "woothemes-sensei"),
2232
            "title"       => __( "Sort by title A-Z", "woothemes-sensei" ),
2233
        ));
2234
2235
        // setup the currently selected item
2236
        $selected = 'newness';
2237
        if( isset( $_GET['orderby'] ) ){
2238
2239
            $selected =  $_GET[ 'orderby' ];
2240
2241
        }
2242
2243
        ?>
2244
2245
        <form class="sensei-ordering" name="sensei-course-order" action="<?php echo WooThemes_Sensei_Utils::get_current_url(); ?>" method="POST">
2246
            <select name="course-orderby" class="orderby">
2247
                <?php
2248
                foreach( $course_order_by_options as $value => $text ){
2249
2250
                    echo '<option value="'. $value . ' "' . selected( $selected, $value, false ) . '>'. $text. '</option>';
2251
2252
                }
2253
                ?>
2254
            </select>
2255
        </form>
2256
2257
    <?php
2258
    }// end course archive filters
2259
2260
    /**
2261
     * Output the course archive filter markup
2262
     *
2263
     * hooked into sensei_loop_course_before
2264
     *
2265
     * @since 1.9.0
2266
     * @param
2267
     */
2268
    public static function course_archive_filters( $query ){
0 ignored issues
show
Unused Code introduced by
The parameter $query is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2269
2270
        // don't show on category pages
2271
        if( is_tax('course-category') ){
2272
            return;
2273
        }
2274
2275
        /**
2276
         * filter the course archive filter buttons
2277
         *
2278
         * @since 1.9.0
2279
         * @param array $filters{
2280
         *   @type array ( $id, $url , $title )
2281
         * }
2282
         *
2283
         */
2284
        $filters = apply_filters( 'sensei_archive_course_filter_by_options', array(
2285
            array( 'id' => 'all', 'url' => self::get_courses_page_url(), 'title'=> __( 'All', 'woothemes-sensei' ) ),
2286
            array( 'id' => 'featured', 'url' => add_query_arg( array( 'course_filter'=>'featured'), self::get_courses_page_url()  ), 'title'=> __( 'Featured', 'woothemes-sensei' ) ),
2287
        ));
2288
2289
2290
        ?>
2291
        <ul class="sensei-course-filters clearfix" >
2292
            <?php
2293
2294
            //determine the current active url
2295
            $current_url = WooThemes_Sensei_Utils::get_current_url();
2296
2297
            foreach( $filters as $filter ) {
2298
2299
                $active_class =  $current_url == $filter['url'] ? ' class="active" ' : '';
2300
2301
                echo '<li><a '. $active_class .' id="'. $filter['id'] .'" href="'. esc_url( $filter['url'] ).'" >'. $filter['title']  .'</a></li>';
2302
2303
            }
2304
            ?>
2305
2306
        </ul>
2307
2308
        <?php
2309
2310
    }
2311
2312
    /**
2313
     * if the featured link is clicked on the course archive page
2314
     * filter the courses returned to only show those featured
2315
     *
2316
     * Hooked into pre_get_posts
2317
     *
2318
     * @since 1.9.0
2319
     * @param WP_Query $query
2320
     * @return WP_Query $query
2321
     */
2322
    public static function course_archive_featured_filter( $query ){
2323
2324
        if( isset ( $_GET[ 'course_filter' ] ) && 'featured'== $_GET['course_filter'] && $query->is_main_query()  ){
2325
            //setup meta query for featured courses
2326
            $query->set( 'meta_value', 'featured'  );
2327
            $query->set( 'meta_key', '_course_featured'  );
2328
            $query->set( 'meta_compare', '='  );
2329
        }
2330
2331
        return $query;
2332
    }
2333
2334
    /**
2335
     * if the course order drop down is changed
2336
     *
2337
     * Hooked into pre_get_posts
2338
     *
2339
     * @since 1.9.0
2340
     * @param WP_Query $query
2341
     * @return WP_Query $query
2342
     */
2343
    public static function course_archive_order_by_title( $query ){
2344
2345
        if( isset ( $_POST[ 'course-orderby' ] ) && 'title '== $_POST['course-orderby']
2346
            && 'course'== $query->get('post_type') && $query->is_main_query()  ){
2347
            // setup the order by title for this query
2348
            $query->set( 'orderby', 'title'  );
2349
            $query->set( 'order', 'ASC'  );
2350
        }
2351
2352
        return $query;
2353
    }
2354
2355
2356
    /**
2357
     * Get the link to the courses page. This will be the course post type archive
2358
     * page link or the page the user set in their settings
2359
     *
2360
     * @since 1.9.0
2361
     * @return string $course_page_url
2362
     */
2363
    public static function get_courses_page_url(){
2364
2365
        $course_page_id = intval( Sensei()->settings->settings[ 'course_page' ] );
2366
        $course_page_url = empty( $course_page_id ) ? get_post_type_archive_link('course') : get_permalink( $course_page_id );
2367
2368
        return $course_page_url;
2369
2370
    }// get_course_url
2371
2372
    /**
2373
     * Output the headers on the course archive page
2374
     *
2375
     * Hooked into the sensei_archive_title
2376
     *
2377
     * @since 1.9.0
2378
     * @param string $query_type
2379
     * @param string $before_html
2380
     * @param string $after_html
2381
     * @return void
2382
     */
2383
    public static function archive_header( $query_type ='' , $before_html='', $after_html =''  ){
2384
2385
        if( ! is_post_type_archive('course') ){
2386
            return;
2387
        }
2388
2389
        // deprecated since 1.9.0
2390
        sensei_do_deprecated_action('sensei_archive_title','1.9.0','sensei_archive_before_course_loop');
2391
2392
        $html = '';
2393
2394
        if( empty( $before_html ) ){
2395
2396
            $before_html = '<header class="archive-header"><h1>';
2397
2398
        }
2399
2400
        if( empty( $after_html ) ){
2401
2402
            $after_html = '</h1></header>';
2403
2404
        }
2405
2406
        if ( is_tax( 'course-category' ) ) {
2407
2408
            global $wp_query;
2409
2410
            $taxonomy_obj = $wp_query->get_queried_object();
2411
            $taxonomy_short_name = $taxonomy_obj->taxonomy;
2412
            $taxonomy_raw_obj = get_taxonomy( $taxonomy_short_name );
2413
            $title = sprintf( __( '%1$s Archives: %2$s', 'woothemes-sensei' ), $taxonomy_raw_obj->labels->name, $taxonomy_obj->name );
2414
            echo apply_filters( 'course_category_archive_title', $before_html . $title . $after_html );
2415
            return;
2416
2417
        } // End If Statement
2418
2419
        switch ( $query_type ) {
2420
            case 'newcourses':
2421
                $html .= $before_html . __( 'New Courses', 'woothemes-sensei' ) . $after_html;
2422
                break;
2423
            case 'featuredcourses':
2424
                $html .= $before_html .  __( 'Featured Courses', 'woothemes-sensei' ) . $after_html;
2425
                break;
2426
            case 'freecourses':
2427
                $html .= $before_html .  __( 'Free Courses', 'woothemes-sensei' ) . $after_html;
2428
                break;
2429
            case 'paidcourses':
2430
                $html .= $before_html .  __( 'Paid Courses', 'woothemes-sensei' ) . $after_html;
2431
                break;
2432
            default:
2433
                $html .= $before_html . __( 'Courses', 'woothemes-sensei' ) . $after_html;
2434
                break;
2435
        } // End Switch Statement
2436
2437
        echo apply_filters( 'course_archive_title', $html );
2438
2439
    }//course_archive_header
2440
2441
2442
    /**
2443
     * Filter the single course content
2444
     * taking into account if the user has access.
2445
     *
2446
     * @1.9.0
2447
     *
2448
     * @param string $content
2449
     * @return string $content or $excerpt
2450
     */
2451
    public static function single_course_content( $content ){
2452
2453
        if( ! is_singular('course') ){
2454
2455
            return $content;
2456
2457
        }
2458
2459
        // Content Access Permissions
2460
        $access_permission = false;
2461
2462
        if ( ! Sensei()->settings->get('access_permission')  || sensei_all_access() ) {
2463
2464
            $access_permission = true;
2465
2466
        } // End If Statement
2467
2468
        // Check if the user is taking the course
2469
        $is_user_taking_course = WooThemes_Sensei_Utils::user_started_course( get_the_ID(), get_current_user_id() );
2470
2471
        if(WooThemes_Sensei_Utils::sensei_is_woocommerce_activated()) {
2472
2473
            $wc_post_id = get_post_meta( get_the_ID(), '_course_woocommerce_product', true );
2474
            $product = Sensei()->sensei_get_woocommerce_product_object( $wc_post_id );
2475
2476
            $has_product_attached = isset ( $product ) && is_object ( $product );
2477
2478
        } else {
2479
2480
            $has_product_attached = false;
2481
2482
        }
2483
2484
        if ( ( is_user_logged_in() && $is_user_taking_course )
0 ignored issues
show
Bug Best Practice introduced by
The expression $is_user_taking_course of type false|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
2485
            || ( $access_permission && !$has_product_attached)
2486
            || 'full' == Sensei()->settings->get( 'course_single_content_display' ) ) {
2487
2488
            return $content;
2489
2490
        } else {
2491
2492
            return '<p class="course-excerpt">' . get_post(  get_the_ID() )->post_excerpt . '</p>';
2493
2494
        }
2495
2496
    }// end single_course_content
2497
2498
    /**
2499
     * Output the the single course lessons title with markup.
2500
     *
2501
     * @since 1.9.0
2502
     */
2503
    public static function the_course_lessons_title(){
2504
        global $post;
2505
        $none_module_lessons = Sensei()->modules->get_none_module_lessons( $post->ID  );
2506
        $course_lessons = Sensei()->course->course_lessons( $post->ID );
2507
2508
        // title should be Other Lessons if there are lessons belonging to models.
2509
        $title = __('Other Lessons', 'woothemes-sensei');
2510
        if( count( $course_lessons ) == count( $none_module_lessons )  ){
2511
2512
            $title = __('Lessons', 'woothemes-sensei');
2513
2514
        }
2515
2516
        /**
2517
         * hook document in class-woothemes-sensei-message.php
2518
         */
2519
        $title = apply_filters( 'sensei_single_title', $title, $post->post_type );
2520
2521
        ob_start(); // start capturing the following output.
2522
2523
        ?>
2524
2525
            <header>
2526
                <h2> <?php echo $title; ?> </h2>
2527
            </header>
2528
2529
        <?php
2530
2531
        /**
2532
         * Filter the title and markup that appears above the lessons on a single course
2533
         * page.
2534
         *
2535
         * @since 1.9.0
2536
         * @param string $lessons_title_html
2537
         */
2538
        echo apply_filters('the_course_lessons_title', ob_get_clean() ); // output and filter the captured output and stop capturing.
2539
2540
    }// end the_course_lessons_title
2541
2542
    /**
2543
     * This function loads the global wp_query object with with lessons
2544
     * of the current course. It is designed to be used on the single-course template
2545
     * and expects the global post to be a singular course.
2546
     *
2547
     * This function excludes lessons belonging to modules as they are
2548
     * queried separately.
2549
     *
2550
     * @since 1.9.0
2551
     * @global $wp_query
2552
     */
2553
    public static function load_single_course_lessons_query(){
2554
2555
        global $post, $wp_query;
2556
2557
        $course_id = $post->ID;
2558
2559
        if( 'course' != get_post_type( $course_id ) ){
2560
            return;
2561
        }
2562
2563
        $course_lesson_query_args = array(
2564
            'post_type'         => 'lesson',
2565
            'posts_per_page'    => 500,
2566
            'orderby'           => 'date',
2567
            'order'             => 'ASC',
2568
            'meta_query'        => array(
2569
                array(
2570
                    'key' => '_lesson_course',
2571
                    'value' => intval( $course_id ),
2572
                ),
2573
            ),
2574
            'post_status'       => 'public',
2575
            'suppress_filters'  => 0,
2576
        );
2577
2578
        // Exclude lessons belonging to modules as they are queried along with the modules.
2579
        $modules = Sensei()->modules->get_course_modules( $course_id );
2580
        if( !is_wp_error( $modules ) && ! empty( $modules ) && is_array( $modules ) ){
2581
2582
            $terms_ids = array();
2583
            foreach( $modules as $term ){
2584
2585
                $terms_ids[] = $term->term_id;
2586
2587
            }
2588
2589
            $course_lesson_query_args[ 'tax_query'] = array(
2590
                array(
2591
                    'taxonomy' => 'module',
2592
                    'field'    => 'id',
2593
                    'terms'    => $terms_ids,
2594
                    'operator' => 'NOT IN',
2595
                ),
2596
            );
2597
        }
2598
2599
        $wp_query = new WP_Query( $course_lesson_query_args );
2600
2601
    }// load_single_course_lessons
2602
2603
    /**
2604
     * Flush the rewrite rules for a course post type
2605
     *
2606
     * @since 1.9.0
2607
     *
2608
     * @param $post_id
2609
     */
2610 View Code Duplication
    public static function flush_rewrite_rules( $post_id ){
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...
2611
2612
        if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE){
2613
2614
            return;
2615
2616
        }
2617
2618
2619
        if( 'course' == get_post_type( $post_id )  ){
2620
2621
            Sensei()->initiate_rewrite_rules_flush();
2622
2623
        }
2624
2625
    }
2626
2627
    /**
2628
     * Optionally return the full content on the single course pages
2629
     * depending on the users course_single_content_display setting
2630
     *
2631
     * @since 1.9.0
2632
     * @param $excerpt
2633
     * @return string
2634
     */
2635
    public static function full_content_excerpt_override( $excerpt ){
2636
2637
        if (   is_singular('course')  &&
2638
                'full' == Sensei()->settings->get( 'course_single_content_display' ) ){
2639
2640
            return get_the_content();
2641
2642
        } else {
2643
2644
            return $excerpt;
2645
2646
        }
2647
2648
    }
2649
2650
    /**
2651
     * Output the course actions like start taking course, register, add to cart etc.
2652
     *
2653
     * @since 1.9.0
2654
     */
2655
    public static function the_course_enrolment_actions(){
2656
        ?>
2657
        <section class="course-meta course-enrolment">
2658
        <?php
2659
        global  $post, $current_user;
2660
        $is_user_taking_course = WooThemes_Sensei_Utils::user_started_course( $post->ID, $current_user->ID );
2661
        if ( is_user_logged_in() && ! $is_user_taking_course ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $is_user_taking_course of type false|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
2662
2663
            // Get the product ID
2664
            $wc_post_id = absint( get_post_meta( $post->ID, '_course_woocommerce_product', true ) );
2665
2666
            // Check for woocommerce
2667
            if ( WooThemes_Sensei_Utils::sensei_is_woocommerce_activated() && ( 0 < intval( $wc_post_id ) ) ) {
2668
                sensei_wc_add_to_cart($post->ID);
0 ignored issues
show
Deprecated Code introduced by
The function sensei_wc_add_to_cart() has been deprecated with message: since Sensei_WC::the_add_to_cart_button_html( $course_id );

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
2669
            } else {
2670
                sensei_start_course_form($post->ID);
2671
            } // End If Statement
2672
2673
        } elseif ( is_user_logged_in() ) {
2674
2675
            // Check if course is completed
2676
            $user_course_status = WooThemes_Sensei_Utils::user_course_status( $post->ID, $current_user->ID );
2677
            $completed_course = WooThemes_Sensei_Utils::user_completed_course( $user_course_status );
0 ignored issues
show
Documentation introduced by
$user_course_status is of type object, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
2678
            // Success message
2679
            if ( $completed_course ) { ?>
2680
                <div class="status completed"><?php  _e( 'Completed', 'woothemes-sensei' ); ?></div>
2681
                <?php
2682
                $has_quizzes = Sensei()->course->course_quizzes( $post->ID, true );
2683
                if( has_filter( 'sensei_results_links' ) || $has_quizzes ) { ?>
2684
                    <p class="sensei-results-links">
2685
                        <?php
2686
                        $results_link = '';
2687 View Code Duplication
                        if( $has_quizzes ) {
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...
2688
                            $results_link = '<a class="view-results" href="' . Sensei()->course_results->get_permalink( $post->ID ) . '">' .  __( 'View results', 'woothemes-sensei' ) . '</a>';
2689
                        }
2690
                        $results_link = apply_filters( 'sensei_results_links', $results_link );
2691
                        echo $results_link;
2692
                        ?></p>
2693
                <?php } ?>
2694
            <?php } else { ?>
2695
                <div class="status in-progress"><?php echo __( 'In Progress', 'woothemes-sensei' ); ?></div>
2696
            <?php }
2697
2698
        } else {
2699
            // Get the product ID
2700
            $wc_post_id = absint( get_post_meta( $post->ID, '_course_woocommerce_product', true ) );
2701
            // Check for woocommerce
2702
            if ( WooThemes_Sensei_Utils::sensei_is_woocommerce_activated() && ( 0 < intval( $wc_post_id ) ) ) {
2703
2704
                sensei_wc_add_to_cart($post->ID);
0 ignored issues
show
Deprecated Code introduced by
The function sensei_wc_add_to_cart() has been deprecated with message: since Sensei_WC::the_add_to_cart_button_html( $course_id );

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
2705
2706
            } else {
2707
2708
                if( get_option( 'users_can_register') ) {
2709
2710
2711
                    $my_courses_page_id = '';
2712
2713
                    /**
2714
                     * Filter to force Sensei to output the default WordPress user
2715
                     * registration link.
2716
                     *
2717
                     * @since 1.9.0
2718
                     * @param bool $wp_register_link default false
2719
                     */
2720
2721
                    $wp_register_link = apply_filters('sensei_use_wp_register_link', false);
2722
2723
                    $settings = Sensei()->settings->get_settings();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $settings is correct as Sensei()->settings->get_settings() (which targets Sensei_Settings_API::get_settings()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
2724 View Code Duplication
                    if( isset( $settings[ 'my_course_page' ] )
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...
2725
                        && 0 < intval( $settings[ 'my_course_page' ] ) ){
2726
2727
                        $my_courses_page_id = $settings[ 'my_course_page' ];
2728
2729
                    }
2730
2731
                    // If a My Courses page was set in Settings, and 'sensei_use_wp_register_link'
2732
                    // is false, link to My Courses. If not, link to default WordPress registration page.
2733
                    if( !empty( $my_courses_page_id ) && $my_courses_page_id && !$wp_register_link){
2734
2735
                        $my_courses_url = get_permalink( $my_courses_page_id  );
2736
                        $register_link = '<a href="'.$my_courses_url. '">' . __('Register', 'woothemes-sensei') .'</a>';
2737
                        echo '<div class="status register">' . $register_link . '</div>' ;
2738
2739
                    } else{
2740
2741
                        wp_register( '<div class="status register">', '</div>' );
2742
2743
                    }
2744
2745
                } // end if user can register
2746
2747
            } // End If Statement
2748
2749
        } // End If Statement ?>
2750
2751
        </section><?php
2752
2753
    }// end the_course_enrolment_actions
2754
2755
    /**
2756
     * Output the course video inside the loop.
2757
     *
2758
     * @since 1.9.0
2759
     */
2760
    public static function the_course_video(){
2761
2762
        global $post;
2763
        // Get the meta info
2764
        $course_video_embed = get_post_meta( $post->ID, '_course_video_embed', true );
2765
2766
        if ( 'http' == substr( $course_video_embed, 0, 4) ) {
2767
2768
            $course_video_embed = wp_oembed_get( esc_url( $course_video_embed ) );
2769
2770
        } // End If Statement
2771
2772
        if ( '' != $course_video_embed ) { ?>
2773
2774
            <div class="course-video">
2775
                <?php echo html_entity_decode($course_video_embed); ?>
2776
            </div>
2777
2778
        <?php } // End If Statement
2779
    }
2780
2781
    /**
2782
     * Output the title for the single lesson page
2783
     *
2784
     * @global $post
2785
     * @since 1.9.0
2786
     */
2787
    public static function the_title(){
2788
2789
        global $post;
2790
2791
        ?>
2792
        <header>
2793
2794
            <h1>
2795
2796
                <?php
2797
                /**
2798
                 * Filter documented in class-sensei-messages.php the_title
2799
                 */
2800
                echo apply_filters( 'sensei_single_title', get_the_title( $post ), $post->post_type );
2801
                ?>
2802
2803
            </h1>
2804
2805
        </header>
2806
2807
        <?php
2808
2809
    }//the_title
2810
2811
    /**
2812
     * Show the title on the course category pages
2813
     *
2814
     * @since 1.9.0
2815
     */
2816
    public static function course_category_title(){
2817
2818
        if( ! is_tax( 'course-category' ) ){
2819
            return;
2820
        }
2821
2822
        $category_slug = get_query_var('course-category');
2823
        $term  = get_term_by('slug',$category_slug,'course-category');
2824
2825
        if( ! empty($term) ){
2826
2827
            $title = $term->name;
2828
2829
        }else{
2830
2831
            $title = 'Course Category';
2832
2833
        }
2834
2835
        $html = '<h2 class="sensei-category-title">';
2836
        $html .= __('Category') . ' ' . $title;
2837
        $html .= '</h2>';
2838
2839
        echo apply_filters( 'course_category_title', $html , $term->term_id );
2840
2841
    }// course_category_title
2842
2843
    /**
2844
     * Alter the course query to respect the order set for courses and apply
2845
     * this on the course-category pages.
2846
     *
2847
     * @since 1.9.0
2848
     *
2849
     * @param WP_Query $query
2850
     * @return WP_Query
2851
     */
2852
    public static function alter_course_category_order( $query ){
2853
2854
        if( ! is_tax( 'course-category' ) || ! $query->is_main_query() ){
2855
            return $query;
2856
        }
2857
2858
        $order = get_option( 'sensei_course_order', '' );
2859
        if( !empty( $order )  ){
2860
            $query->set('orderby', 'menu_order' );
2861
            $query->set('order', 'ASC' );
2862
        }
2863
2864
        return $query;
2865
2866
    }
2867
2868
    /**
2869
     * The very basic course query arguments
2870
     * so we don't have to repeat this througout
2871
     * the code base.
2872
     *
2873
     * Usage:
2874
     * $args = Sensei_Course::get_default_query_args();
2875
     * $args['custom_arg'] ='custom value';
2876
     * $courses = get_posts( $args )
2877
     *
2878
     * @since 1.9.0
2879
     *
2880
     * @return array
2881
     */
2882
    public static function get_default_query_args(){
2883
        return array(
2884
            'post_type' 		=> 'course',
2885
            'posts_per_page' 		=> 1000,
2886
            'orderby'         	=> 'date',
2887
            'order'           	=> 'DESC',
2888
            'suppress_filters' 	=> 0
2889
        );
2890
    }
2891
2892
    /**
2893
     * Check if the prerequisite course is completed
2894
     * Courses with no pre-requisite should always return true
2895
     *
2896
     * @since 1.9.0
2897
     * @param $course_id
2898
     * @return bool
2899
     */
2900
    public static function is_prerequisite_complete( $course_id ){
2901
2902
        $course_prerequisite_id = get_post_meta( $course_id, '_course_prerequisite', true );
2903
2904
        // if it has a pre requisite course check it
2905
        if( ! empty(  $course_prerequisite_id ) ){
2906
2907
            return Sensei_Utils::user_completed_course( $course_prerequisite_id, get_current_user_id() );
2908
2909
        }
2910
2911
        return true;
2912
2913
    }// end is_prerequisite_complete
2914
2915
2916
}// End Class
2917
2918
/**
2919
 * Class WooThemes_Sensei_Course
2920
 * for backward compatibility
2921
 * @since 1.9.0
2922
 */
2923
class WooThemes_Sensei_Course extends Sensei_Course{}
2924