Completed
Push — master ( 201c1b...d51ce1 )
by Dwain
04:57
created

Sensei_Frontend   D

Complexity

Total Complexity 272

Size/Duplication

Total Lines 1778
Duplicated Lines 6.07 %

Coupling/Cohesion

Components 3
Dependencies 11
Metric Value
wmc 272
lcom 3
cbo 11
dl 108
loc 1778
rs 4

64 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 73 1
A init() 0 3 1
A __get() 0 12 4
B enqueue_scripts() 0 30 6
A enqueue_styles() 0 22 3
A sensei_get_template_part() 0 6 1
A sensei_get_template() 0 6 1
A sensei_locate_template() 0 6 1
A sensei_output_content_wrapper() 19 19 2
A sensei_output_content_wrapper_end() 20 20 2
B load_content_pagination() 28 57 8
A sensei_output_comments() 0 5 1
D sensei_setup_nav_menu_item() 0 85 16
C sensei_wp_nav_menu_objects() 17 26 11
B sensei_search_results_classes() 0 8 5
A the_single_title() 0 5 1
A sensei_course_image() 0 14 2
A sensei_lesson_image() 0 11 2
B sensei_course_archive_pagination() 0 17 8
A sensei_course_archive_header() 0 6 1
A sensei_lesson_archive_header() 0 4 1
A sensei_message_archive_header() 0 4 1
A sensei_course_archive_course_title() 0 10 3
A sensei_lesson_archive_lesson_title() 0 5 1
C sensei_breadcrumb() 14 38 11
A sensei_lesson_course_signup_link() 0 5 1
B lesson_tags_display() 0 20 8
A lesson_tag_archive_filter() 0 11 3
A lesson_tag_archive_header() 0 6 2
A lesson_tag_archive_description() 0 6 2
B sensei_complete_lesson() 0 30 5
B sensei_complete_course() 0 57 7
A sensei_get_user_quiz_answers() 0 15 3
A sensei_has_user_completed_lesson() 0 4 1
A sensei_frontend_messages() 0 3 1
A sensei_lesson_video() 0 12 4
B sensei_complete_lesson_button() 0 32 5
B sensei_reset_lesson_button() 0 30 4
A sensei_lesson_quiz_meta() 0 5 1
B sensei_course_archive_meta() 7 27 5
A sensei_single_main_content() 0 3 1
A sensei_lesson_archive_main_content() 0 3 1
A sensei_message_archive_main_content() 0 3 1
A sensei_no_permissions_main_content() 0 3 1
B sensei_course_category_main_content() 0 35 3
B sensei_login_form() 0 65 5
B sensei_lesson_meta() 3 17 5
A sensei_lesson_preview_title_text() 0 13 3
B sensei_lesson_preview_title() 0 21 9
B sensei_course_start() 0 26 5
A sensei_course_meta() 0 4 1
A sensei_course_meta_video() 0 4 1
A sensei_woocommerce_in_cart_message() 0 14 4
A sensei_lesson_comment_count() 0 3 1
A sensei_search_results_excerpt() 0 9 3
C remove_active_course() 0 46 9
D activate_purchased_courses() 0 98 15
C activate_purchased_single_course() 0 81 13
A hide_sensei_activity() 0 8 3
B sensei_login_fail_redirect() 0 20 6
D sensei_handle_login_request() 0 92 13
D sensei_process_registration() 0 84 18
A login_message_process() 0 20 3
A sensei_show_admin_bar() 0 9 2

How to fix   Duplicated Code    Complexity   

Duplicated Code

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

Common duplication problems, and corresponding solutions are:

Complex Class

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

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

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

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

1
<?php
2
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
3
4
/**
5
 * Sensei Frontend Class
6
 *
7
 * All functionality pertaining to the frontend of Sensei.
8
 *
9
 * @package WordPress
10
 * @subpackage Sensei
11
 * @category Frontend
12
 * @author WooThemes
13
 * @since 1.0.0
14
 */
15
class Sensei_Frontend {
16
17
	public $token;
18
	public $messages;
19
	public $data;
20
21
	/**
22
	 * Constructor.
23
	 * @since  1.0.0
24
	 */
25
	public function __construct () {
26
27
		// Template output actions
28
		add_action( 'sensei_before_main_content', array( $this, 'sensei_output_content_wrapper' ), 10 );
29
		add_action( 'sensei_after_main_content', array( $this, 'sensei_output_content_wrapper_end' ), 10 );
30
		add_action( 'sensei_lesson_archive_lesson_title', array( $this, 'sensei_lesson_archive_lesson_title' ), 10 );
31
32
		// 1.2.1
33
		add_action( 'sensei_complete_lesson', array( $this, 'sensei_complete_lesson' ) );
34
		add_action( 'init', array( $this, 'sensei_complete_course' ), 5 );
35
		add_action( 'sensei_frontend_messages', array( $this, 'sensei_frontend_messages' ) );
36
		add_action( 'sensei_lesson_video', array( $this, 'sensei_lesson_video' ), 10, 1 );
37
		add_action( 'sensei_complete_lesson_button', array( $this, 'sensei_complete_lesson_button' ) );
38
		add_action( 'sensei_reset_lesson_button', array( $this, 'sensei_reset_lesson_button' ) );
39
40
		add_action( 'sensei_course_archive_meta', array( $this, 'sensei_course_archive_meta' ) );
41
42
		add_action( 'sensei_lesson_tag_main_content', array( $this, 'sensei_lesson_archive_main_content' ), 10 );
43
		add_action( 'sensei_no_permissions_main_content', array( $this, 'sensei_no_permissions_main_content' ), 10 );
44
45
		add_action( 'sensei_lesson_meta', array( $this, 'sensei_lesson_meta' ), 10 );
46
		add_action( 'sensei_single_course_content_inside_before', array( $this, 'sensei_course_start' ), 10 );
47
48
		// add_filter( 'get_comments_number', array( $this, 'sensei_lesson_comment_count' ), 1 );
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% 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...
49
		add_filter( 'the_title', array( $this, 'sensei_lesson_preview_title' ), 10, 2 );
50
51
		//1.6.2
52
		add_filter( 'wp_login_failed', array( $this, 'sensei_login_fail_redirect' ), 10 );
53
		add_filter( 'init', array( $this, 'sensei_handle_login_request' ), 10 );
54
		//1.6.3
55
		add_action( 'init', array( $this, 'sensei_process_registration' ), 2 );
56
		//1.7.0
57
		add_action( 'sensei_pagination', array( $this, 'sensei_breadcrumb' ), 80, 1 );
58
59
		// Fix pagination for course archive pages when filtering by course type
60
		add_filter( 'pre_get_posts', array( $this, 'sensei_course_archive_pagination' ) );
61
62
		// Scripts and Styles
63
		add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_styles' ) );
64
		add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
65
66
		// Custom Menu Item filters
67
		add_filter( 'wp_setup_nav_menu_item', array( $this, 'sensei_setup_nav_menu_item' ) );
68
		add_filter( 'wp_nav_menu_objects', array( $this, 'sensei_wp_nav_menu_objects' ) );
69
		// Search Results filters
70
		add_filter( 'post_class', array( $this, 'sensei_search_results_classes' ), 10 );
71
		// Only show course & lesson excerpts in search results
72
		add_filter( 'the_content', array( $this, 'sensei_search_results_excerpt' ) );
73
74
        //Use WooCommerce filter to show admin bar to Teachers.
75
        add_action( 'init', array( $this, 'sensei_show_admin_bar') );
76
77
        // Remove course from active courses if an order is cancelled or refunded
78
		add_action( 'woocommerce_order_status_processing_to_cancelled', array( $this, 'remove_active_course' ), 10, 1 );
79
		add_action( 'woocommerce_order_status_completed_to_cancelled', array( $this, 'remove_active_course' ), 10, 1 );
80
		add_action( 'woocommerce_order_status_on-hold_to_cancelled', array( $this, 'remove_active_course' ), 10, 1 );
81
		add_action( 'woocommerce_order_status_processing_to_refunded', array( $this, 'remove_active_course' ), 10, 1 );
82
		add_action( 'woocommerce_order_status_completed_to_refunded', array( $this, 'remove_active_course' ), 10, 1 );
83
		add_action( 'woocommerce_order_status_on-hold_to_refunded', array( $this, 'remove_active_course' ), 10, 1 );
84
85
		// Make sure correct courses are marked as active for users
86
		add_action( 'sensei_before_my_courses', array( $this, 'activate_purchased_courses' ), 10, 1 );
87
		add_action( 'sensei_single_course_content_inside_before', array( $this, 'activate_purchased_single_course' ), 10 );
88
89
		// Lesson tags
90
		add_action( 'sensei_lesson_meta_extra', array( $this, 'lesson_tags_display' ), 10, 1 );
91
		add_action( 'pre_get_posts', array( $this, 'lesson_tag_archive_filter' ), 10, 1 );
92
		add_filter( 'sensei_lessons_archive_text', array( $this, 'lesson_tag_archive_header' ) );
93
		add_action( 'sensei_loop_lesson_inside_before', array( $this, 'lesson_tag_archive_description' ), 11 );
94
95
		// Hide Sensei activity comments from lesson and course pages
96
		add_filter( 'wp_list_comments_args', array( $this, 'hide_sensei_activity' ) );
97
	} // End __construct()
98
99
	/**
100
	 * Initialise the code.
101
	 * @since  1.0.0
102
	 * @return void
103
	 */
104
	public function init () {
105
106
	} // End init()
107
108
	/**
109
	 * Graceful fallback for course and lesson variables on Frontend object
110
	 *
111
	 * @param string $key Key to get.
112
	 * @since  1.7.3
113
	 * @return array|mixed
114
	 */
115
	public function __get( $key ) {
116
117
118
		if ( 'lesson' == $key || 'course' == $key ) {
119
			if ( WP_DEBUG ) {
120
				trigger_error( sprintf( 'Sensei()->frontend->%1$s has been <strong>deprecated</strong> since version %2$s! Please use Sensei()->%1$s to access the instance.', $key, '1.7.3' ) );
121
			}
122
			return Sensei()->$key;
123
		}
124
125
		return null;
126
	}
127
128
	/**
129
	 * Enqueue frontend JavaScripts.
130
	 * @since  1.0.0
131
	 * @return void
132
	 */
133
	public function enqueue_scripts () {
134
135
		$disable_js = false;
136
		if ( isset( Sensei()->settings->settings[ 'js_disable' ] ) ) {
137
			$disable_js = Sensei()->settings->settings[ 'js_disable' ];
138
		} // End If Statement
139
		if ( ! $disable_js ) {
140
141
			$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
142
143
			// My Courses tabs script
144
			wp_register_script( $this->token . '-user-dashboard', esc_url( Sensei()->plugin_url . 'assets/js/user-dashboard' . $suffix . '.js' ), array( 'jquery-ui-tabs' ), Sensei()->version, true );
145
			wp_enqueue_script( $this->token . '-user-dashboard' );
146
147
148
            // Course Archive javascript
149
            if( is_post_type_archive( 'course' ) ){
150
151
                wp_register_script( 'sensei-course-archive-js', esc_url( Sensei()->plugin_url . 'assets/js/frontend/course-archive' . $suffix . '.js' ), array( 'jquery' ), '1', true );
152
                wp_enqueue_script( 'sensei-course-archive-js' );
153
154
            }
155
156
157
			// Allow additional scripts to be loaded
158
			do_action( 'sensei_additional_scripts' );
159
160
		} // End If Statement
161
162
	} // End enqueue_scripts()
163
164
	/**
165
	 * Enqueue frontend CSS files.
166
	 * @since  1.0.0
167
	 * @return void
168
	 */
169
	public function enqueue_styles () {
170
171
172
		$disable_styles = false;
173
		if ( isset( Sensei()->settings->settings[ 'styles_disable' ] ) ) {
174
			$disable_styles = Sensei()->settings->settings[ 'styles_disable' ];
175
		} // End If Statement
176
177
		// Add filter for theme overrides
178
		$disable_styles = apply_filters( 'sensei_disable_styles', $disable_styles );
179
180
		if ( ! $disable_styles ) {
181
182
			wp_register_style( Sensei()->token . '-frontend', Sensei()->plugin_url . 'assets/css/frontend/sensei.css', '', Sensei()->version, 'screen' );
183
			wp_enqueue_style( Sensei()->token . '-frontend' );
184
185
			// Allow additional stylesheets to be loaded
186
			do_action( 'sensei_additional_styles' );
187
188
		} // End If Statement
189
190
	} // End enqueue_styles()
191
192
193
	/**
194
	 * sensei_get_template_part function.
195
	 *
196
     * @deprecated sine 1.9.0
197
	 * @access public
198
	 * @param mixed $slug
199
	 * @param string $name (default: '')
200
	 * @return void
201
	 */
202
	function sensei_get_template_part( $slug, $name = '' ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
203
204
        _deprecated_function( 'class-woothemes-sensei-frontend.php', '1.9.0', 'Sensei_Templates::get_part' );
205
        Sensei_Templates::get_part( $slug, $name );
206
207
	} // End sensei_get_template_part()
208
209
	/**
210
	 * sensei_get_template function.
211
	 *
212
     * @deprecated since 1.9.0
213
	 * @access public
214
	 * @param mixed $template_name
215
	 * @param array $args (default: array())
216
	 * @param string $template_path (default: '')
217
	 * @param string $default_path (default: '')
218
	 * @return void
219
	 */
220
	function sensei_get_template( $template_name, $args = array(), $template_path = '', $default_path = '' ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
221
222
        _deprecated_function( 'sensei_get_template', '1.9.0', 'Sensei_Templates::get_template' );
223
        Sensei_Templates::get_template($template_name, $args, $template_path, $default_path  );
224
225
	} // End sensei_get_template()
226
227
228
	/**
229
	 * sensei_locate_template function.
230
	 *
231
	 * @access public
232
	 * @param mixed $template_name
233
	 * @param string $template_path (default: '')
234
	 * @param string $default_path (default: '')
235
	 * @return void
236
	 */
237
	function sensei_locate_template( $template_name, $template_path = '', $default_path = '' ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
238
239
        _deprecated_function( 'sensei_locate_template', '1.9.0', 'Sensei_Templates::locate_template' );
240
        Sensei_Templates::locate_template( $template_name, $template_path, $default_path );
241
242
	} // End sensei_locate_template()
243
244
245
	/**
246
	 * sensei_output_content_wrapper function.
247
     *
248
	 * @access public
249
	 * @return void
250
	 */
251 View Code Duplication
	function sensei_output_content_wrapper() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
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...
252
253
	    // backwards compatibility check for old location under the wrappers directory of the active theme
254
        $backwards_compatible_wrapper_location =   array(
255
            Sensei()->template_url . 'wrappers/wrapper-start.php',
256
            'wrappers/wrapper-start.php'
257
        );
258
259
        $template = locate_template( $backwards_compatible_wrapper_location );
260
        if( !empty( $template ) ){
261
262
            Sensei_Templates::get_template( 'wrappers/wrapper-start.php' );
263
            return;
264
265
        }
266
267
		Sensei_Templates::get_template( 'globals/wrapper-start.php' );
268
269
	} // End sensei_output_content_wrapper()
270
271
272
	/**
273
	 * sensei_output_content_wrapper_end function.
274
     *
275
	 * @access public
276
	 * @return void
277
	 */
278 View Code Duplication
	function sensei_output_content_wrapper_end() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
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...
279
280
	    // backwards compatibility check for old location under the wrappers directory of the active theme
281
        $backwards_compatible_wrapper_location =   array(
282
            Sensei()->template_url . 'wrappers/wrapper-end.php',
283
            'wrappers/wrapper-end.php'
284
        );
285
286
        $backwards_compatible_template = locate_template( $backwards_compatible_wrapper_location );
287
        if( !empty( $backwards_compatible_template ) ){
288
289
            Sensei_Templates::get_template( 'wrappers/wrapper-end.php' );
290
            return;
291
292
        }
293
294
295
		Sensei_Templates::get_template( 'globals/wrapper-end.php' );
296
297
	} // End sensei_output_content_wrapper_end()
298
299
300
	/**
301
	 * sensei_output_content_pagination function.
302
	 *
303
	 * @access public
304
	 * @return void
305
	 */
306
	public static function load_content_pagination() {
307
308
        if( is_singular('course') ) {
309
310
            // backwards compatibility check for old location under the wrappers directory of the active theme
311
            $template = locate_template( array( Sensei()->template_url . 'wrappers/pagination-posts.php' ) );
312
            if( !empty( $template ) ){
313
314
                Sensei_Templates::get_template( 'wrappers/pagination-posts.php' );
315
                return;
316
317
            }
318
319
			Sensei_Templates::get_template( 'globals/pagination-posts.php' );
320
321 View Code Duplication
		} elseif( is_singular('lesson') ) {
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...
322
323
		    // backwards compatibility check for old location under the wrappers directory of the active theme
324
		    $template = locate_template( array( Sensei()->template_url . 'wrappers/pagination-lesson.php' ) );
325
            if( !empty( $template ) ){
326
327
                Sensei_Templates::get_template( 'wrappers/pagination-lesson.php' );
328
                return;
329
330
            }
331
332
			Sensei_Templates::get_template( 'globals/pagination-lesson.php' );
333
334
		} elseif( is_singular('quiz') ) {
335
336
		    // backwards compatibility check for old location under the wrappers directory of the active theme
337
		    $template = locate_template( array( Sensei()->template_url . 'wrappers/pagination-quiz.php' ) );
338
            if( !empty( $template ) ){
339
340
                Sensei_Templates::get_template( 'wrappers/pagination-quiz.php' );
341
                return;
342
343
            }
344
345
			Sensei_Templates::get_template( 'globals/pagination-quiz.php' );
346
347 View Code Duplication
		} else {
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...
348
349
            // backwards compatibility check for old location under the wrappers directory of the active theme
350
            $template = locate_template( array( Sensei()->template_url . 'wrappers/pagination.php' ) );
351
            if( !empty( $template ) ){
352
353
                Sensei_Templates::get_template( 'wrappers/pagination.php' );
354
                return;
355
356
            }
357
358
			Sensei_Templates::get_template( 'globals/pagination.php' );
359
360
		} // End If Statement
361
362
	} // End sensei_output_content_pagination()
363
364
	/**
365
	 * outputs comments for the specified pages
366
	 * @deprecated
367
	 * @return void
368
	 */
369
	function sensei_output_comments() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
370
371
		Sensei_Lesson::output_comments();
372
373
	} // End sensei_output_comments()
374
375
	/**
376
	 * sensei_setup_nav_menu_item function.
377
	 *
378
	 * Generate the urls for Sensei custom menu items.
379
	 *
380
	 * @access public
381
	 * @param object $item
382
	 * @return object $item
383
	 */
384
	public function sensei_setup_nav_menu_item( $item ) {
385
		global $pagenow, $wp_rewrite;
386
387
		if( 'nav-menus.php' != $pagenow && !defined('DOING_AJAX') && isset( $item->url ) && 'custom' == $item->type ) {
388
389
			// Set up Sensei menu links
390
			$course_page_id = intval( Sensei()->settings->settings[ 'course_page' ] );
0 ignored issues
show
Unused Code introduced by
$course_page_id is not used, you could remove the assignment.

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

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

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

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

Loading history...
391
			$my_account_page_id = intval( Sensei()->settings->settings[ 'my_course_page' ] );
392
393
			$course_page_url = Sensei_Course::get_courses_page_url();
394
			$lesson_archive_url = get_post_type_archive_link( 'lesson' );
395
			$my_courses_url = get_permalink( $my_account_page_id );
396
			$my_messages_url = get_post_type_archive_link( 'sensei_message' );
397
398
			switch ( $item->url ) {
399
				case '#senseicourses':
400
					$item->url = $course_page_url;
401
					break;
402
403
				case '#senseilessons':
404
					$item->url = $lesson_archive_url;
405
					break;
406
407
				case '#senseimycourses':
408
					$item->url = $my_courses_url;
409
					break;
410
411
				case '#senseimymessages':
412
					$item->url = $my_messages_url;
413
                    // if no archive link exist for sensei_message
414
                    // set it back to the place holder
415
                    if( ! $item->url ){
416
417
                        $item->url = '#senseimymessages';
418
419
                    }
420
					break;
421
422
				case '#senseilearnerprofile':
423
					$item->url = esc_url( Sensei()->learner_profiles->get_permalink() );
424
					break;
425
426
				case '#senseiloginlogout':
427
						$logout_url = wp_logout_url( home_url() );
428
						// Login link links to the My Courses page, to avoid the WP dashboard.
429
						$login_url = $my_courses_url;
430
431
						$item->url = ( is_user_logged_in() ? $logout_url : $login_url );
432
433
						// determine the menu title login or logout
434
						if ( is_user_logged_in() ) {
435
							$menu_title =  __( 'Logout'  ,'woothemes-sensei');
436
						} else {
437
							$menu_title =  __( 'Login'  ,'woothemes-sensei');
438
						}
439
440
						/**
441
						 * Action Filter: login/logout menu title
442
						 *
443
						 * With this filter you can alter the login / login menu item title string
444
						 *
445
						 * @param $menu_title
446
						 */
447
						$item->title = apply_filters( 'sensei_login_logout_menu_title', $menu_title );
448
449
					break;
450
451
				default:
452
					break;
453
			}
454
455
			$_root_relative_current = untrailingslashit( $_SERVER['REQUEST_URI'] );
456
			$current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_root_relative_current );
457
			$item_url = untrailingslashit( $item->url );
458
			$_indexless_current = untrailingslashit( preg_replace( '/' . preg_quote( $wp_rewrite->index, '/' ) . '$/', '', $current_url ) );
459
			// Highlight current menu item
460
			if ( $item_url && in_array( $item_url, array( $current_url, $_indexless_current, $_root_relative_current ) ) ) {
461
				$item->classes[] = 'current-menu-item current_page_item';
462
			}
463
464
		} // endif nav
465
466
		return $item;
467
468
	} // End sensei_setup_nav_menu_item()
469
470
	/**
471
	 * sensei_wp_nav_menu_objects function.
472
	 *
473
	 * Remove Sensei custom menu items depending on settings and logged in status.
474
	 *
475
	 * @access public
476
	 * @param object $sorted_menu_items
477
	 * @return object $sorted_menu_items
478
	 */
479
	public function sensei_wp_nav_menu_objects( $sorted_menu_items ) {
480
481
		foreach( $sorted_menu_items as $k=>$item ) {
482
483
			// Remove the My Messages link for logged out users or if Private Messages are disabled
484 View Code Duplication
			if( ! get_post_type_archive_link( 'sensei_message' )
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...
485
                && '#senseimymessages' == $item->url ) {
486
487
				if ( !is_user_logged_in() || ( isset( Sensei()->settings->settings['messages_disable'] ) && Sensei()->settings->settings['messages_disable'] ) ) {
488
489
					unset( $sorted_menu_items[$k] );
490
491
				}
492
			}
493
			// Remove the My Profile link for logged out users.
494 View Code Duplication
			if( Sensei()->learner_profiles->get_permalink() == $item->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...
495
496
				if ( !is_user_logged_in() || ! ( isset( Sensei()->settings->settings[ 'learner_profile_enable' ] ) && Sensei()->settings->settings[ 'learner_profile_enable' ] ) ) {
497
498
					unset( $sorted_menu_items[$k] );
499
500
				}
501
			}
502
		}
503
		return $sorted_menu_items;
504
	} // End sensei_wp_nav_menu_objects
505
506
	// add category nicenames in body and post class
507
	function sensei_search_results_classes($classes) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
508
	    global $post;
509
	    // Handle Search Classes for Courses, Lessons, and WC Products
510
	    if ( isset( $post->post_type ) && ( ( 'course' == $post->post_type ) || ( 'lesson' == $post->post_type ) || ( 'product' == $post->post_type ) ) ) {
511
	    	$classes[] = 'post';
512
		} // End If Statement
513
	    return $classes;
514
	} // End sensei_search_results_classes()
515
516
    /**
517
     * sensei_single_title output for single page title
518
     * @since  1.1.0
519
     * @return void
520
     * @deprecate
521
     */
522
    function the_single_title() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
523
524
        _deprecated_function(' WooThemes_Sensei_Frontend::the_single_title', '1.9.0');
525
526
    } // End sensei_single_title()
527
528
	/**
529
	 * sensei_course_image output for course image Please use Sensei()->course->course_image instead.
530
     *
531
     * @deprecated since 1.9.0
532
     * @param $course_id
533
     * @param string $width
534
     * @param string $height
535
     * @param bool|false $return
536
     * @return string|void
537
	 */
538
	function sensei_course_image( $course_id, $width = '100', $height = '100', $return = false ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
539
540
        trigger_error( 'Sensei Deprecated function: sensei_course_image since 1.9.0 . Please use Sensei()->course->course_image instead.');
541
542
    	if ( ! $return ) {
543
544
			echo Sensei()->course->course_image( $course_id, $width, $height );
545
            return '';
546
547
		} // End If Statement
548
549
		return Sensei()->course->course_image( $course_id, $width, $height );
550
551
	} // End sensei_course_image()
552
553
	/**
554
	 * sensei_lesson_image output for lesson image
555
	 * @since  1.2.0
556
     * @deprecated since 1.9.0
557
     * @param $lesson_id
558
     * @param string $width
559
     * @param string $height
560
     * @param bool|false $return
561
     * @param bool|false $widget
562
     * @return string
563
	 */
564
	function sensei_lesson_image( $lesson_id, $width = '100', $height = '100', $return = false, $widget = false ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
565
566
        if( ! $return ){
567
568
            echo Sensei()->lesson->lesson_image( $lesson_id, $width, $height, $widget );
569
            return '';
570
        }
571
572
        return Sensei()->lesson->lesson_image( $lesson_id, $width, $height, $widget );
573
574
	} // End sensei_lesson_image()
575
576
    /**
577
     * @since 1.0.0
578
     * @param WP_Query $query
579
     */
580
    function sensei_course_archive_pagination( $query ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
581
582
		if( ! is_admin() && $query->is_main_query() && isset( $_GET['action'] ) && in_array( $_GET['action'], array( 'newcourses', 'featuredcourses', 'freecourses', 'paidcourses' ) ) ) {
583
584
			$amount = 0;
585
			if ( isset( Sensei()->settings->settings[ 'course_archive_amount' ] ) && ( 0 < absint( Sensei()->settings->settings[ 'course_archive_amount' ] ) ) ) {
586
				$amount = absint( Sensei()->settings->settings[ 'course_archive_amount' ] );
587
			}
588
589
			if( $amount ) {
590
				$query->set( 'posts_per_page', $amount );
591
			}
592
593
			$query->set( 'orderby', 'menu_order date' );
594
595
		}
596
	}
597
598
	/**
599
	 * sensei_course_archive_header function.
600
	 *
601
	 * @access public
602
	 * @since  1.2.0
603
     * @deprecated since 1.9.0 use WooThemes_Sensei_Course::archive_header
604
	 * @return void
605
	 */
606
	function sensei_course_archive_header(  ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
607
608
        trigger_error('This function sensei_course_archive_header has been depricated. Please use: WooThemes_Sensei_Course::course_archive_header ');
609
        WooThemes_Sensei_Course::archive_header( '', '<header class="archive-header"><h1>', '</h1></header>' );
610
611
	} // sensei_course_archive_header()
612
613
	/**
614
	 * sensei_lesson_archive_header function.
615
	 *
616
     * @deprecated since 1.9.0
617
	 * @access public
618
	 * @since  1.2.1
619
	 * @return void
620
	 */
621
	public function sensei_lesson_archive_header( ) {
622
        _deprecated_function( 'WooThemes_Sensei_Frontend::sensei_lesson_archive_header', '1.9.0', 'WooThemes_Sensei_Lesson::the_archive_header' );
623
        Sensei()->lesson->the_archive_header();
624
	} // sensei_course_archive_header()
625
626
    /**
627
     * @deprecated since 1.9.0
628
     */
629
	public function sensei_message_archive_header( ){
630
        _deprecated_function('Sensei_Frontend::sensei_message_archive_header','Please use: Sense');
631
        Sensei_Messages::the_archive_header();
632
	} // sensei_message_archive_header()
633
634
	/**
635
	 * sensei_course_archive_course_title output for course archive page individual course title
636
	 * @since  1.2.0
637
     * @param WP_Post $post_item
638
	 * @return void
639
	 */
640
	function sensei_course_archive_course_title( $post_item ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
641
		if ( isset( $post_item->ID ) && ( 0 < $post_item->ID ) ) {
642
			$post_id = absint( $post_item->ID );
643
    		$post_title = $post_item->post_title;
644
		} else {
645
			$post_id = get_the_ID();
646
    		$post_title = get_the_title();
647
		} // End If Statement
648
		?><header><h2><a href="<?php echo get_permalink( $post_id ); ?>" title="<?php echo esc_attr( $post_title ); ?>"><?php echo $post_title; ?></a></h2></header><?php
649
	} // End sensei_course_archive_course_title()
650
651
	/**
652
	 * sensei_lesson_archive_lesson_title output for course archive page individual course title
653
	 * @since  1.2.1
654
	 * @return void
655
	 */
656
	public function sensei_lesson_archive_lesson_title() {
657
		$post_id = get_the_ID();
658
    	$post_title = get_the_title();
659
		?><header><h2><a href="<?php echo get_permalink( $post_id ); ?>" title="<?php echo esc_attr( $post_title ); ?>"><?php echo $post_title; ?></a></h2></header><?php
660
	} // End sensei_lesson_archive_lesson_title()
661
662
	/**
663
	 * sensei_breadcrumb outputs Sensei breadcrumb trail on lesson & quiz pages
664
	 * @since  1.7.0
665
	 * @param  integer $id course, lesson or quiz id
666
	 * @return void
667
	 */
668
	public function sensei_breadcrumb( $id = 0 ) {
669
670
		// Only output on lesson, quiz and taxonomy (module) pages
671
		if( ! ( is_tax( 'module' ) || is_singular( 'lesson' ) || is_singular( 'quiz' ) ) ) return;
672
673
		if( empty( $id )  ){
674
675
            $id = get_the_ID();
676
677
        }
678
679
		$sensei_breadcrumb_prefix = __( 'Back to: ', 'woothemes-sensei' );
680
		$separator = apply_filters( 'sensei_breadcrumb_separator', '&gt;' );
681
682
		$html = '<section class="sensei-breadcrumb">' . $sensei_breadcrumb_prefix;
683
		// Lesson
684 View Code Duplication
		if ( is_singular( 'lesson' ) && 0 < intval( $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...
685
			$course_id = intval( get_post_meta( $id, '_lesson_course', true ) );
686
			if( ! $course_id ) {
687
				return;
688
			}
689
			$html .= '<a href="' . esc_url( get_permalink( $course_id ) ) . '" title="' . __( 'Back to the course', 'woothemes-sensei' ) . '">' . get_the_title( $course_id ) . '</a>';
690
    	} // End If Statement
691
    	// Quiz
692 View Code Duplication
		if ( is_singular( 'quiz' ) && 0 < intval( $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...
693
			$lesson_id = intval( get_post_meta( $id, '_quiz_lesson', true ) );
694
			if( ! $lesson_id ) {
695
				return;
696
			}
697
			 $html .= '<a href="' . esc_url( get_permalink( $lesson_id ) ) . '" title="' .  __( 'Back to the lesson', 'woothemes-sensei' ) . '">' . get_the_title( $lesson_id ) . '</a>';
698
    	} // End If Statement
699
700
    	// Allow other plugins to filter html
701
    	$html = apply_filters ( 'sensei_breadcrumb_output', $html, $separator );
702
    	$html .= '</section>';
703
704
    	echo $html;
705
	} // End sensei_breadcrumb()
706
707
708
    /**
709
     * @deprecated since 1.9.0 use WooThemes_Sensei_Lesson::course_signup_link instead
710
     */
711
	public function sensei_lesson_course_signup_link( ) {
712
713
        _deprecated_function('sensei_lesson_course_signup_link', '1.9.0', 'WooThemes_Sensei_Lesson::course_signup_link' );
714
        WooThemes_Sensei_Lesson::course_signup_link();
715
	}
716
717
	public function lesson_tags_display( $lesson_id = 0 ) {
718
		if( $lesson_id ) {
719
			$tags = wp_get_post_terms( $lesson_id, 'lesson-tag' );
720
			if( $tags && count( $tags ) > 0 ) {
721
				$tag_list = '';
722
				foreach( $tags as $tag ) {
723
					$tag_link = get_term_link( $tag, 'lesson-tag' );
724
					if( ! is_wp_error( $tag_link ) ) {
725
						if( $tag_list ) { $tag_list .= ', '; }
726
						$tag_list .= '<a href="' . $tag_link . '">' . $tag->name . '</a>';
727
					}
728
				}
729
				if( $tag_list ) {
730
					?><section class="lesson-tags">
731
		    			<?php printf( __( 'Lesson tags: %1$s', 'woothemes-sensei' ), $tag_list ); ?>
732
		    		</section><?php
733
		    	}
734
	    	}
735
		}
736
	}
737
738
    /**
739
     * @param WP_Query $query
740
     */
741
	public function lesson_tag_archive_filter( $query ) {
742
    	if( is_tax( 'lesson-tag' ) && $query->is_main_query() ) {
743
    		// Limit to lessons only
744
    		$query->set( 'post_type', 'lesson' );
745
746
    		// Set order of lessons
747
    		$query->set( 'orderby', 'menu_order' );
748
    		$query->set( 'order', 'ASC' );
749
750
    	}
751
    }
752
753
    public function lesson_tag_archive_header( $title ) {
754
		if( is_tax( 'lesson-tag' ) ) {
755
			$title = sprintf( __( 'Lesson tag: %1$s', 'woothemes-sensei' ), apply_filters( 'sensei_lesson_tag_archive_title', get_queried_object()->name ) );
756
		}
757
		return $title;
758
	}
759
760
	public function lesson_tag_archive_description() {
761
		if( is_tax( 'lesson-tag' ) ) {
762
			$tag = get_queried_object();
763
			echo '<p class="archive-description lesson-description">' . apply_filters( 'sensei_lesson_tag_archive_description', nl2br( $tag->description ), $tag->term_id ) . '</p>';
764
		}
765
	}
766
767
	public function sensei_complete_lesson() {
768
		global $post,  $current_user;
769
		// Handle Quiz Completion
770
		if ( isset( $_POST['quiz_action'] ) && wp_verify_nonce( $_POST[ 'woothemes_sensei_complete_lesson_noonce' ], 'woothemes_sensei_complete_lesson_noonce' ) ) {
771
772
			$sanitized_submit = esc_html( $_POST['quiz_action'] );
773
774
			switch ($sanitized_submit) {
775
                case 'lesson-complete':
776
777
					Sensei_Utils::sensei_start_lesson( $post->ID, $current_user->ID, $complete = true );
778
779
					break;
780
781
                case 'lesson-reset':
782
783
					Sensei_Utils::sensei_remove_user_from_lesson( $post->ID, $current_user->ID );
784
785
					$this->messages = '<div class="sensei-message note">' .  __( 'Lesson Reset Successfully.', 'woothemes-sensei' ) . '</div>';
786
					break;
787
788
				default:
789
					// Nothing
790
					break;
791
792
			} // End Switch Statement
793
794
		} // End If Statement
795
796
	} // End sensei_complete_lesson()
797
798
	public function sensei_complete_course() {
799
		global $post,  $current_user, $wp_query;
800
		if ( isset( $_POST['course_complete'] ) && wp_verify_nonce( $_POST[ 'woothemes_sensei_complete_course_noonce' ], 'woothemes_sensei_complete_course_noonce' ) ) {
801
802
			$sanitized_submit = esc_html( $_POST['course_complete'] );
803
			$sanitized_course_id = absint( esc_html( $_POST['course_complete_id'] ) );
804
			// Handle submit data
805
			switch ($sanitized_submit) {
806
				case __( 'Mark as Complete', 'woothemes-sensei' ):
807
808
					// Add user to course
809
					$course_metadata = array(
810
						'start' => current_time('mysql'),
811
						'percent' => 0, // No completed lessons yet
812
						'complete' => 0,
813
					);
814
					$activity_logged = Sensei_Utils::update_course_status( $current_user->ID, $sanitized_course_id, 'in-progress', $course_metadata );
815
816
					if ( $activity_logged ) {
817
						// Get all course lessons
818
						$course_lesson_ids = Sensei()->course->course_lessons( $sanitized_course_id, 'any', 'ids' );
819
						// Mark all quiz user meta lessons as complete
820
						foreach ( $course_lesson_ids as $lesson_item_id ){
821
							// Mark lesson as complete
822
							$activity_logged = Sensei_Utils::sensei_start_lesson( $lesson_item_id, $current_user->ID, $complete = true );
0 ignored issues
show
Unused Code introduced by
$activity_logged is not used, you could remove the assignment.

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

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

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

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

Loading history...
823
						} // End For Loop
824
825
						// Update with final stats
826
						$course_metadata = array(
827
							'percent' => 100,
828
							'complete' => count($course_lesson_ids),
829
						);
830
						$activity_logged = Sensei_Utils::update_course_status( $current_user->ID, $sanitized_course_id, 'complete', $course_metadata );
0 ignored issues
show
Unused Code introduced by
$activity_logged is not used, you could remove the assignment.

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

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

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

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

Loading history...
831
832
						do_action( 'sensei_user_course_end', $current_user->ID, $sanitized_course_id );
833
834
						// Success message
835
						$this->messages = '<header class="archive-header"><div class="sensei-message tick">' . sprintf( __( '%1$s marked as complete.', 'woothemes-sensei' ), get_the_title( $sanitized_course_id ) ) . '</div></header>';
836
					} // End If Statement
837
838
					break;
839
840
				case __( 'Delete Course', 'woothemes-sensei' ):
841
842
					Sensei_Utils::sensei_remove_user_from_course( $sanitized_course_id, $current_user->ID );
843
844
					// Success message
845
					$this->messages = '<header class="archive-header"><div class="sensei-message tick">' . sprintf( __( '%1$s deleted.', 'woothemes-sensei' ), get_the_title( $sanitized_course_id ) ) . '</div></header>';
846
					break;
847
848
				default:
849
					// Nothing
850
					break;
851
			} // End Switch Statement
852
853
		} // End If Statement
854
	} // End sensei_complete_course()
855
856
	/**
857
	 * @deprecated use WooThemes_Sensei_Quiz::get_user_answers
858
	 * @param int $lesson_id
859
	 * @return array
860
	 */
861
	public function sensei_get_user_quiz_answers( $lesson_id = 0 ) {
862
		global $current_user;
863
864
		$user_answers = array();
865
866
		if ( 0 < intval( $lesson_id ) ) {
867
			$lesson_quiz_questions = Sensei()->lesson->lesson_quiz_questions( $lesson_id );
868
			foreach( $lesson_quiz_questions as $question ) {
869
				$answer = maybe_unserialize( base64_decode( Sensei_Utils::sensei_get_activity_value( array( 'post_id' => $question->ID, 'user_id' => $current_user->ID, 'type' => 'sensei_user_answer', 'field' => 'comment_content' ) ) ) );
870
				$user_answers[ $question->ID ] = $answer;
871
			}
872
		}
873
874
		return $user_answers;
875
	} // End sensei_get_user_quiz_answers()
876
877
	public function sensei_has_user_completed_lesson( $post_id = 0, $user_id = 0 ) {
878
		_deprecated_function( __FUNCTION__, '1.7', "WooThemes_Sensei_Utils::user_completed_lesson()" );
879
		return Sensei_Utils::user_completed_lesson( $post_id, $user_id );
880
	} // End sensei_has_user_completed_lesson()
881
882
/**
883
*
884
 */
885
	public function sensei_frontend_messages() {
886
		Sensei()->notices->print_notices();
0 ignored issues
show
Bug introduced by
The property notices does not seem to exist. Did you mean notice?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
887
	} // End sensei_frontend_messages()
888
889
	public function sensei_lesson_video( $post_id = 0 ) {
890
		if ( 0 < intval( $post_id ) ) {
891
			$lesson_video_embed = get_post_meta( $post_id, '_lesson_video_embed', true );
892
			if ( 'http' == substr( $lesson_video_embed, 0, 4) ) {
893
        		// V2 - make width and height a setting for video embed
894
        		$lesson_video_embed = wp_oembed_get( esc_url( $lesson_video_embed )/*, array( 'width' => 100 , 'height' => 100)*/ );
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...
895
        	} // End If Statement
896
        	if ( '' != $lesson_video_embed ) {
897
        	?><div class="video"><?php echo html_entity_decode($lesson_video_embed); ?></div><?php
898
        	} // End If Statement
899
        } // End If Statement
900
	} // End sensei_lesson_video()
901
902
	public function sensei_complete_lesson_button() {
903
		global  $post;
904
905
		$quiz_id = 0;
0 ignored issues
show
Unused Code introduced by
$quiz_id is not used, you could remove the assignment.

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

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

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

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

Loading history...
906
907
		// Lesson quizzes
908
		$quiz_id = Sensei()->lesson->lesson_quizzes( $post->ID );
909
		$pass_required = true;
910
		if( $quiz_id ) {
911
			// Get quiz pass setting
912
	    	$pass_required = get_post_meta( $quiz_id, '_pass_required', true );
913
	    }
914
		if( ! $quiz_id || ( $quiz_id && ! $pass_required ) ) {
915
			?>
916
			<form class="lesson_button_form" method="POST" action="<?php echo esc_url( get_permalink() ); ?>">
917
	            <input type="hidden"
918
                       name="woothemes_sensei_complete_lesson_noonce"
919
                       id="woothemes_sensei_complete_lesson_noonce"
920
                       value="<?php echo esc_attr( wp_create_nonce( 'woothemes_sensei_complete_lesson_noonce' ) ); ?>"
921
                />
922
923
	            <input type="hidden" name="quiz_action" value="lesson-complete" />
924
925
                <input type="submit"
926
                       name="quiz_complete"
927
                       class="quiz-submit complete"
928
                       value="<?php _e( 'Complete Lesson', 'woothemes-sensei' ); ?>"/>
929
930
	        </form>
931
			<?php
932
		} // End If Statement
933
	} // End sensei_complete_lesson_button()
934
935
	public function sensei_reset_lesson_button() {
936
		global  $post;
937
938
		$quiz_id = 0;
0 ignored issues
show
Unused Code introduced by
$quiz_id is not used, you could remove the assignment.

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

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

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

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

Loading history...
939
940
		// Lesson quizzes
941
		$quiz_id = Sensei()->lesson->lesson_quizzes( $post->ID );
942
		$reset_allowed = true;
943
		if( $quiz_id ) {
944
			// Get quiz pass setting
945
			$reset_allowed = get_post_meta( $quiz_id, '_enable_quiz_reset', true );
946
		}
947
		if ( ! $quiz_id || !empty($reset_allowed) ) {
948
		?>
949
		<form method="POST" action="<?php echo esc_url( get_permalink() ); ?>">
950
951
            <input
952
            type="hidden"
953
            name="<?php echo esc_attr( 'woothemes_sensei_complete_lesson_noonce' ); ?>"
954
            id="<?php echo esc_attr( 'woothemes_sensei_complete_lesson_noonce' ); ?>"
955
            value="<?php echo esc_attr( wp_create_nonce( 'woothemes_sensei_complete_lesson_noonce' ) ); ?>" />
956
957
            <input type="hidden" name="quiz_action" value="lesson-reset" />
958
959
            <input type="submit" name="quiz_complete" class="quiz-submit reset" value="<?php _e( 'Reset Lesson', 'woothemes-sensei' ); ?>"/>
960
961
        </form>
962
		<?php
963
		} // End If Statement
964
	} // End sensei_reset_lesson_button()
965
966
    /**
967
     * @deprecated since 1.9.0
968
     */
969
    public function sensei_lesson_quiz_meta( ) {
970
971
        Sensei_Lesson::footer_quiz_call_to_action();
972
973
	} // End sensei_lesson_quiz_meta()
974
975
	public function sensei_course_archive_meta() {
976
		global  $post;
977
		// Meta data
978
		$post_id = get_the_ID();
979
		$post_title = get_the_title();
0 ignored issues
show
Unused Code introduced by
$post_title is not used, you could remove the assignment.

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

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

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

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

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

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

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

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

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

Loading history...
981
		$author_id = get_the_author_meta('ID');
0 ignored issues
show
Unused Code introduced by
$author_id is not used, you could remove the assignment.

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

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

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

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

Loading history...
982
		$category_output = get_the_term_list( $post_id, 'course-category', '', ', ', '' );
983
		$free_lesson_count = intval( Sensei()->course->course_lesson_preview_count( $post_id ) );
984
		?><section class="entry">
985
        	<p class="sensei-course-meta">
986 View Code Duplication
           	<?php 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...
987
		   	<span class="course-author"><?php _e( 'by ', 'woothemes-sensei' ); ?><?php the_author_link(); ?></span>
988
		   	<?php } // End If Statement ?>
989
		   	<span class="course-lesson-count"><?php echo Sensei()->course->course_lesson_count( $post_id ) . '&nbsp;' . __( 'Lessons', 'woothemes-sensei' ); ?></span>
990
		   	<?php if ( '' != $category_output ) { ?>
991
		   	<span class="course-category"><?php echo sprintf( __( 'in %s', 'woothemes-sensei' ), $category_output ); ?></span>
992
		   	<?php } // End If Statement ?>
993
		   	<?php sensei_simple_course_price( $post_id ); ?>
994
        	</p>
995
        	<p class="course-excerpt"><?php the_excerpt(); ?></p>
996 View Code Duplication
        	<?php if ( 0 < $free_lesson_count ) {
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...
997
                $free_lessons = sprintf( __( 'You can access %d of this course\'s lessons for free', 'woothemes-sensei' ), $free_lesson_count ); ?>
998
                <p class="sensei-free-lessons"><a href="<?php echo get_permalink( $post_id ); ?>"><?php _e( 'Preview this course', 'woothemes-sensei' ) ?></a> - <?php echo $free_lessons; ?></p>
999
            <?php } ?>
1000
		</section><?php
1001
	} // End sensei_course_archive_meta()
1002
1003
    /**
1004
     * @deprecated since 1.9.0
1005
     */
1006
	public function sensei_single_main_content() {
1007
	    _deprecated_function('Woothemes_Sensei_Frontend::sensei_single_main_content', '1.9.0');
1008
	} // End sensei_single_main_content()
1009
1010
    /**
1011
    * @deprecated since 1.9.0
1012
    */
1013
	public function sensei_lesson_archive_main_content() {
1014
        _deprecated_function('Sensei_Frontend::sensei_lesson_archive_main_content', '1.9.0', 'Please include loop-lesson.php directly');
1015
	} // End sensei_lesson_archive_main_content()
1016
1017
    /**
1018
    * @deprecated since 1.9.0
1019
    */
1020
	public function sensei_message_archive_main_content() {
1021
		_deprecated_function( 'Sensei_Frontend::sensei_message_archive_main_content', 'This method is no longer needed' );
1022
	} // End sensei_lesson_archive_main_content()
1023
1024
    /**
1025
    * @deprecated since 1.9.0
1026
    */
1027
	public function sensei_no_permissions_main_content() {
1028
        _deprecated_function( 'Sensei_Frontend::sensei_no_permissions_main_content', 'This method is no longer needed' );
1029
	} // End sensei_no_permissions_main_content()
1030
1031
	public function sensei_course_category_main_content() {
1032
		global $post;
1033
		if ( have_posts() ) { ?>
1034
1035
			<section id="main-course" class="course-container">
1036
1037
                <?php do_action( 'sensei_course_archive_header' ); ?>
1038
1039
                <?php while ( have_posts() ) { the_post(); ?>
1040
1041
                    <article class="<?php echo join( ' ', get_post_class( array( 'course', 'post' ), get_the_ID() ) ); ?>">
1042
1043
	    			    <?php do_action( 'sensei_course_image', get_the_ID() ); ?>
1044
1045
	    			    <?php do_action( 'sensei_course_archive_course_title', $post ); ?>
1046
1047
	    			    <?php do_action( 'sensei_course_archive_meta' ); ?>
1048
1049
	    		    </article>
1050
1051
                <?php } // End While Loop ?>
1052
1053
	    	</section>
1054
1055
		<?php } else { ?>
1056
1057
			<p>
1058
1059
                <?php _e( 'No courses found that match your selection.', 'woothemes-sensei' ); ?>
1060
1061
            </p>
1062
1063
		<?php } // End If Statement
1064
1065
	} // End sensei_course_category_main_content()
1066
1067
	public function sensei_login_form() {
1068
		?>
1069
		<div id="my-courses">
1070
			<?php Sensei()->notices->print_notices(); ?>
0 ignored issues
show
Bug introduced by
The property notices does not seem to exist. Did you mean notice?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1071
			<div class="col2-set" id="customer_login">
1072
1073
				<div class="col-1">
1074
					<?php
1075
					// output the actual form markup
1076
                    Sensei_Templates::get_template( 'user/login-form.php');
1077
					?>
1078
				</div>
1079
1080
			<?php
1081
			if ( get_option('users_can_register') ) {
1082
1083
				// get current url
1084
				$action_url = get_permalink();
1085
1086
				?>
1087
1088
				<div class="col-2">
1089
					<h2><?php _e( 'Register', 'woothemes-sensei' ); ?></h2>
1090
1091
					<form method="post" class="register"  action="<?php echo esc_url( $action_url ); ?>" >
1092
1093
						<?php do_action( 'sensei_register_form_start' ); ?>
1094
1095
						<p class="form-row form-row-wide">
1096
							<label for="sensei_reg_username"><?php _e( 'Username', 'woothemes-sensei' ); ?> <span class="required">*</span></label>
1097
							<input type="text" class="input-text" name="sensei_reg_username" id="sensei_reg_username" value="<?php if ( ! empty( $_POST['sensei_reg_username'] ) ) esc_attr_e( $_POST['sensei_reg_username'] ); ?>" />
1098
						</p>
1099
1100
						<p class="form-row form-row-wide">
1101
							<label for="sensei_reg_email"><?php _e( 'Email address', 'woothemes-sensei' ); ?> <span class="required">*</span></label>
1102
							<input type="email" class="input-text" name="sensei_reg_email" id="sensei_reg_email" value="<?php if ( ! empty( $_POST['sensei_reg_email'] ) ) esc_attr_e( $_POST['sensei_reg_email'] ); ?>" />
1103
						</p>
1104
1105
						<p class="form-row form-row-wide">
1106
							<label for="sensei_reg_password"><?php _e( 'Password', 'woothemes-sensei' ); ?> <span class="required">*</span></label>
1107
							<input type="password" class="input-text" name="sensei_reg_password" id="sensei_reg_password" value="<?php if ( ! empty( $_POST['sensei_reg_password'] ) ) esc_attr_e( $_POST['sensei_reg_password'] ); ?>" />
1108
						</p>
1109
1110
						<!-- Spam Trap -->
1111
						<div style="left:-999em; position:absolute;"><label for="trap"><?php _e( 'Anti-spam', 'woothemes-sensei' ); ?></label><input type="text" name="email_2" id="trap" tabindex="-1" /></div>
1112
1113
						<?php do_action( 'sensei_register_form_fields' ); ?>
1114
						<?php do_action( 'register_form' ); ?>
1115
1116
						<p class="form-row">
1117
							<input type="submit" class="button" name="register" value="<?php _e( 'Register', 'woothemes-sensei' ); ?>" />
1118
						</p>
1119
1120
						<?php do_action( 'sensei_register_form_end' ); ?>
1121
1122
					</form>
1123
				</div>
1124
				<?php
1125
			}
1126
			?>
1127
			</div>
1128
		</div>
1129
1130
		<?php
1131
	} // End sensei_login_form()
1132
1133
	public function sensei_lesson_meta( $post_id = 0 ) {
1134
		global $post;
1135
		if ( 0 < intval( $post_id ) ) {
1136
		$lesson_course_id = absint( get_post_meta( $post_id, '_lesson_course', true ) );
1137
		?><section class="entry">
1138
            <p class="sensei-course-meta">
1139 View Code Duplication
			    <?php if ( isset( Sensei()->settings->settings[ 'lesson_author' ] ) && ( Sensei()->settings->settings[ 'lesson_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...
1140
			    <span class="course-author"><?php _e( 'by ', 'woothemes-sensei' ); ?><?php the_author_link(); ?></span>
1141
			    <?php } ?>
1142
                <?php if ( 0 < intval( $lesson_course_id ) ) { ?>
1143
                <span class="lesson-course"><?php echo '&nbsp;' . sprintf( __( 'Part of: %s', 'woothemes-sensei' ), '<a href="' . esc_url( get_permalink( $lesson_course_id ) ) . '" title="' . __( 'View course', 'woothemes-sensei' ) . '"><em>' . get_the_title( $lesson_course_id ) . '</em></a>' ); ?></span>
1144
                <?php } ?>
1145
            </p>
1146
            <p class="lesson-excerpt"><?php the_excerpt( ); ?></p>
1147
		</section><?php
1148
		} // End If Statement
1149
	} // sensei_lesson_meta()
1150
1151
	public function sensei_lesson_preview_title_text( $course_id ) {
1152
1153
		$preview_text = __( ' (Preview)', 'woothemes-sensei' );
1154
1155
		//if this is a paid course
1156
		if ( Sensei_WC::is_woocommerce_active() ) {
1157
    	    $wc_post_id = get_post_meta( $course_id, '_course_woocommerce_product', true );
1158
    	    if ( 0 < $wc_post_id ) {
1159
    	    	$preview_text = __( ' (Free Preview)', 'woothemes-sensei' );
1160
    	    } // End If Statement
1161
    	}
1162
    	return $preview_text;
1163
	}
1164
1165
	public function sensei_lesson_preview_title( $title = '', $id = 0 ) {
1166
		global $post, $current_user;
1167
1168
		// Limit to lessons and check if lesson ID matches filtered post ID
1169
		// @see https://github.com/woothemes/sensei/issues/574
1170
		if( isset( $post->ID ) && $id == $post->ID && 'lesson' == get_post_type( $post ) ) {
1171
1172
			// Limit to main query only
1173
			if( is_main_query() ) {
1174
1175
				// Get the course ID
1176
				$course_id = get_post_meta( $post->ID, '_lesson_course', true );
1177
1178
				// Check if the user is taking the course
1179
				if( is_singular( 'lesson' ) && Sensei_Utils::is_preview_lesson( $post->ID ) && ! Sensei_Utils::user_started_course( $course_id, $current_user->ID ) && $post->ID == $id ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression \Sensei_Utils::user_star..._id, $current_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...
1180
					$title .= ' ' . $this->sensei_lesson_preview_title_text( $course_id );
1181
				}
1182
			}
1183
		}
1184
		return $title;
1185
	} // sensei_lesson_preview_title
1186
1187
	public function sensei_course_start() {
1188
		global $post, $current_user;
1189
1190
		// Check if the user is taking the course
1191
		$is_user_taking_course = Sensei_Utils::user_started_course( $post->ID, $current_user->ID );
1192
		// Handle user starting the course
1193
		if ( isset( $_POST['course_start'] )
1194
		    && wp_verify_nonce( $_POST[ 'woothemes_sensei_start_course_noonce' ], 'woothemes_sensei_start_course_noonce' )
1195
		    && !$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...
1196
1197
			// Start the course
1198
			$activity_logged = Sensei_Utils::user_start_course( $current_user->ID, $post->ID );
1199
			$this->data = new stdClass();
1200
			$this->data->is_user_taking_course = false;
1201
			if ( $activity_logged ) {
1202
				$this->data->is_user_taking_course = true;
1203
1204
				// Refresh page to avoid re-posting
1205
				?>
1206
1207
			    <script type="text/javascript"> window.location = '<?php echo get_permalink( $post->ID ); ?>'; </script>
1208
1209
			    <?php
1210
			} // End If Statement
1211
		} // End If Statement
1212
	} // End sensei_course_start()
1213
1214
    /**
1215
     * @deprecated since 1.9.0
1216
     */
1217
	public function sensei_course_meta() {
1218
        _deprecated_function( 'Sensei_Frontend::sensei_course_meta', '1.9.0' , 'Sensei_Course::the_course_meta()' );
1219
        Sensei()->course->the_course_meta( get_post() );
1220
	} // End sensei_course_meta()
1221
1222
    /**
1223
     * @deprecated since 1.9.0
1224
     */
1225
	public function sensei_course_meta_video() {
1226
        _deprecated_function( 'Sensei_Frontend::sensei_course_meta_video', '1.9.0' , 'Sensei_Course::the_course_video()' );
1227
        Sensei_Course::the_course_video();
1228
	} // End sensei_course_meta_video()
1229
1230
    /**
1231
     * This function shows the WooCommerce cart notice if the user has
1232
     * added the current course to cart. It does not show if the user is already taking
1233
     * the course.
1234
     *
1235
     * @since 1.0.2
1236
     * @return void;
0 ignored issues
show
Documentation introduced by
The doc-type void; could not be parsed: Expected "|" or "end of type", but got ";" at position 4. (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...
1237
     */
1238
    public function sensei_woocommerce_in_cart_message() {
1239
		global $post, $woocommerce;
1240
1241
		$wc_post_id = absint( get_post_meta( $post->ID, '_course_woocommerce_product', true ) );
1242
        $user_course_status_id = Sensei_Utils::user_started_course($post->ID , get_current_user_id() );
1243
		if ( 0 < intval( $wc_post_id ) && ! $user_course_status_id ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $user_course_status_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...
1244
1245
			if ( Sensei_WC::is_product_in_cart( $wc_post_id ) ) {
1246
				echo '<div class="sensei-message info">' . sprintf(  __('You have already added this Course to your cart. Please %1$s to access the course.', 'woothemes-sensei') . '</div>', '<a class="cart-complete" href="' . $woocommerce->cart->get_checkout_url() . '" title="' . __('complete the purchase', 'woothemes-sensei') . '">' . __('complete the purchase', 'woothemes-sensei') . '</a>' );
1247
			} // End If Statement
1248
1249
		} // End If Statement
1250
1251
	} // End sensei_woocommerce_in_cart_message()
1252
1253
	// Deprecated
1254
	public function sensei_lesson_comment_count( $count ) {
1255
		return $count;
1256
	} // End sensei_lesson_comment_count()
1257
1258
	/**
1259
	 * Only show excerpts for lessons and courses in search results
1260
	 * @param  string $content Original content
1261
	 * @return string          Modified content
1262
	 */
1263
	public function sensei_search_results_excerpt( $content ) {
1264
		global $post;
1265
1266
		if( is_search() && in_array( $post->post_type, array( 'course', 'lesson' ) ) ) {
1267
			$content = '<p class="course-excerpt">' . the_excerpt( ) . '</p>';
1268
		}
1269
1270
		return $content;
1271
	} // End sensei_search_results_excerpt()
1272
1273
	/**
1274
	 * Remove active course when an order is refunded or cancelled
1275
	 * @param  integer $order_id ID of order
1276
	 * @return void
1277
	 */
1278
	public function remove_active_course( $order_id ) {
1279
		$order = new WC_Order( $order_id );
1280
1281
		foreach ( $order->get_items() as $item ) {
1282
			if ( isset( $item['variation_id'] ) && ( 0 < $item['variation_id'] ) ) {
1283
				// If item has variation_id then its a variation of the product
1284
				$item_id = $item['variation_id'];
1285
			} else {
1286
				// Than its real product set it's id to item_id
1287
				$item_id = $item['product_id'];
1288
			} 
1289
1290
            if ( $item_id > 0 ) {
1291
1292
				$user_id = get_post_meta( $order_id, '_customer_user', true );
1293
1294
				if( $user_id ) {
1295
1296
					// Get all courses for product
1297
					$args = array(
1298
						'posts_per_page' => -1,
1299
						'post_type' => 'course',
1300
						'meta_query' => array(
1301
							array(
1302
								'key' => '_course_woocommerce_product',
1303
								'value' => $item_id
1304
							)
1305
						),
1306
						'orderby' => 'menu_order date',
1307
						'order' => 'ASC',
1308
						'fields' => 'ids',
1309
					);
1310
					$course_ids = get_posts( $args );
1311
1312
					if( $course_ids && count( $course_ids ) > 0 ) {
1313
						foreach( $course_ids as $course_id ) {
1314
1315
							// Remove all course user meta
1316
							Sensei_Utils::sensei_remove_user_from_course( $course_id, $user_id );
1317
1318
						} // End For Loop
1319
					} // End If Statement
1320
				} // End If Statement
1321
			} // End If Statement
1322
		} // End For Loop
1323
	} // End remove_active_course()
1324
1325
1326
	/**
1327
	 * Activate all purchased courses for user
1328
	 * @since  1.4.8
1329
	 * @param  integer $user_id User ID
1330
	 * @return void
1331
	 */
1332
	public function activate_purchased_courses( $user_id = 0 ) {
1333
1334
		if( $user_id ) {
1335
1336
			if( Sensei_WC::is_woocommerce_active() ) {
1337
1338
				// Get all user's orders
1339
				$order_args = array(
1340
					'post_type' => 'shop_order',
1341
					'post_status' =>  array( 'wc-processing', 'wc-completed' ),
1342
					'posts_per_page' => -1,
1343
					'meta_query' => array(
1344
						array(
1345
							'key' => '_customer_user',
1346
							'value' => $user_id
1347
						)
1348
					),
1349
				);
1350
1351
				$orders = get_posts( $order_args );
1352
1353
				$product_ids = array();
1354
				$order_ids = array();
1355
1356
				foreach( $orders as $post_id ) {
1357
1358
					// Only process each order once
1359
					$processed = get_post_meta( $post_id, 'sensei_products_processed', true );
1360
1361
					if( $processed && $processed == 'processed' ) {
1362
						continue;
1363
					}
1364
1365
					// Get course product IDs from order
1366
					$order = new WC_Order( $post_id );
1367
1368
					$items = $order->get_items();
1369
					foreach( $items as $item ) {
1370
                                            if (isset($item['variation_id']) && $item['variation_id'] > 0) {
1371
                                                $item_id = $item['variation_id'];
1372
                                                $product_type = 'variation';
0 ignored issues
show
Unused Code introduced by
$product_type is not used, you could remove the assignment.

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

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

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

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

Loading history...
1373
                                            } else {
1374
                                                $item_id = $item['product_id'];
1375
                                            }
1376
1377
                                            $product_ids[] = $item_id;
1378
                                            }
1379
1380
					$order_ids[] = $post_id;
1381
				}
1382
1383
				if( count( $product_ids ) > 0 ) {
1384
1385
					// Get all courses from user's orders
1386
					$course_args = array(
1387
						'post_type' => 'course',
1388
						'posts_per_page' => -1,
1389
						'meta_query' => array(
1390
							array(
1391
								'key' => '_course_woocommerce_product',
1392
								'value' => $product_ids,
1393
								'compare' => 'IN'
1394
							)
1395
						),
1396
						'orderby' => 'menu_order date',
1397
						'order' => 'ASC',
1398
						'fields' => 'ids',
1399
					);
1400
					$course_ids = get_posts( $course_args );
1401
1402
					foreach( $course_ids as $course_id ) {
1403
1404
						$user_course_status = Sensei_Utils::user_course_status( intval($course_id), $user_id );
1405
1406
						// Ignore course if already completed
1407
						if( Sensei_Utils::user_completed_course( $user_course_status ) ) {
1408
							continue;
1409
						}
1410
1411
						// Ignore course if already started
1412
						if( $user_course_status ) {
1413
							continue;
1414
						}
1415
1416
						// Mark course as started by user
1417
						Sensei_Utils::user_start_course( $user_id, $course_id );
1418
					}
1419
				}
1420
1421
				if( count( $order_ids ) > 0 ) {
1422
					foreach( $order_ids as $order_id ) {
1423
						// Mark order as processed
1424
						update_post_meta( $order_id, 'sensei_products_processed', 'processed' );
1425
					}
1426
				}
1427
			}
1428
		}
1429
	} // End activate_purchased_courses()
1430
1431
	/**
1432
	 * Activate single course if already purchases
1433
	 * @return void
1434
	 */
1435
	public function activate_purchased_single_course() {
1436
		global $post, $current_user;
1437
1438
		if( Sensei_WC::is_woocommerce_active() ) {
1439
1440
			if( ! is_user_logged_in() ) return;
1441
			if( ! isset( $post->ID ) ) return;
1442
1443
			$user_id = $current_user->ID;
1444
			$course_id = $post->ID;
1445
			$course_product_id = (int) get_post_meta( $course_id, '_course_woocommerce_product', true );
1446
			if( ! $course_product_id ) {
1447
				return;
1448
			}
1449
1450
			$user_course_status = Sensei_Utils::user_course_status( intval($course_id), $user_id );
1451
1452
			// Ignore course if already completed
1453
			if( Sensei_Utils::user_completed_course( $user_course_status ) ) {
1454
1455
				return;
1456
			}
1457
1458
			// Ignore course if already started
1459
			if( $user_course_status ) {
1460
				return;
1461
			}
1462
1463
			// Get all user's orders
1464
			$order_args = array(
1465
				'post_type' => 'shop_order',
1466
				'posts_per_page' => -1,
1467
				'post_status' => array( 'wc-processing', 'wc-completed' ),
1468
				'meta_query' => array(
1469
					array(
1470
						'key' => '_customer_user',
1471
						'value' => $user_id
1472
					)
1473
				),
1474
				'fields' => 'ids',
1475
			);
1476
			$orders = get_posts( $order_args );
1477
1478
			foreach( $orders as $order_post_id ) {
1479
1480
				// Get course product IDs from order
1481
				$order = new WC_Order( $order_post_id );
1482
1483
				$items = $order->get_items();
1484
				foreach( $items as $item ) {
1485
                    $product = wc_get_product( $item['product_id'] );
1486
1487
                    // handle product bundles
1488
                    if( $product->is_type('bundle') ){
1489
1490
                        $bundled_product = new WC_Product_Bundle( $product->id );
1491
                        $bundled_items = $bundled_product->get_bundled_items();
1492
1493
                        foreach( $bundled_items as $bundled_item ){
1494
1495
                            if( $bundled_item->product_id == $course_product_id ) {
1496
                                Sensei_Utils::user_start_course( $user_id, $course_id );
1497
                                return;
1498
                            }
1499
1500
                        }
1501
1502
                    } else {
1503
1504
                    // handle regular products
1505
                        if( $item['product_id'] == $course_product_id ) {
1506
                            Sensei_Utils::user_start_course( $user_id, $course_id );
1507
                            return;
1508
                        }
1509
1510
                    }
1511
				}
1512
			}
1513
1514
		}
1515
	} // End activate_purchased_single_course()
1516
1517
	/**
1518
	 * Hide Sensei activity comments from frontend (requires WordPress 4.0+)
1519
	 * @param  array  $args Default arguments
1520
	 * @return array        Modified arguments
1521
	 */
1522
	public function hide_sensei_activity( $args = array() ) {
1523
1524
		if( is_singular( 'lesson' ) || is_singular( 'course' ) ) {
1525
			$args['type'] = 'comment';
1526
		}
1527
1528
		return $args;
1529
	} // End hide_sensei_activity()
1530
1531
	/**
1532
	 * Redirect failed login attempts to the front end login page
1533
	 * in the case where the login fields are not left empty
1534
	 *
1535
	 * @return void redirect
1536
	 */
1537
	function sensei_login_fail_redirect( ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
1538
1539
		//if not posted from the sensei login form let
1540
		// WordPress or any other party handle the failed request
1541
	    if( ! isset( $_REQUEST['form'] ) || 'sensei-login' != $_REQUEST['form']  ){
1542
1543
	    	return ;
1544
1545
	    }
1546
1547
    	// Get the reffering page, where did the post submission come from?
1548
    	$referrer = add_query_arg('login', false, $_SERVER['HTTP_REFERER']);
1549
1550
   		 // if there's a valid referrer, and it's not the default log-in screen
1551
	    if(!empty($referrer) && !strstr($referrer,'wp-login') && !strstr($referrer,'wp-admin')){
1552
	        // let's append some information (login=failed) to the URL for the theme to use
1553
	        wp_redirect( esc_url_raw( add_query_arg('login', 'failed',  $referrer) ) );
1554
	    	exit;
1555
    	}
1556
	}// End sensei_login_fail_redirect_to_front_end_login
1557
1558
	/**
1559
	 * Handle the login reques from all sensei intiated login forms.
1560
	 *
1561
	 * @return void redirect
1562
	 */
1563
	function sensei_handle_login_request( ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

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

Loading history...
1564
1565
1566
		// Check that it is a sensei login request and if it has a valid nonce
1567
	    if(  isset( $_REQUEST['form'] ) && 'sensei-login' == $_REQUEST['form'] ) {
1568
1569
	    	// Validate the login request nonce
1570
		    if( !wp_verify_nonce( $_REQUEST['_wpnonce'], 'sensei-login' ) ){
1571
		    	return;
1572
		    }
1573
1574
1575
		    //get the page where the sensei log form is located
1576
		    $referrer = $_REQUEST['_wp_http_referer'];
1577
		    //$redirect = $_REQUEST['_sensei_redirect'];
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% 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...
1578
1579
		    if ( ( isset( $_REQUEST['log'] ) && !empty( $_REQUEST['log'] ) )
1580
		    	 && ( isset( $_REQUEST['pwd'] ) && !empty( $_REQUEST['pwd'] ) ) ){
1581
1582
		    	// when the user has entered a password or username do the sensei login
1583
		    	$creds = array();
1584
1585
		    	// check if the requests login is an email address
1586
		    	if( is_email(  trim( $_REQUEST['log'] ) )  ){
1587
		    		// query wordpress for the users details
1588
		    		$user =	get_user_by( 'email', sanitize_email( $_REQUEST['log'] )  );
1589
1590
		    		// validate the user object
1591
		    		if( !$user ){
1592
1593
		    			// the email doesnt exist
1594
                        wp_redirect( esc_url_raw( add_query_arg('login', 'failed', $referrer) ) );
1595
		        		exit;
1596
1597
		    		}
1598
1599
		    		//assigne the username to the creds array for further processing
1600
		    		$creds['user_login'] =  $user->user_login ;
1601
1602
		    	}else{
1603
1604
		    		// process this as a default username login
1605
		    		$creds['user_login'] = sanitize_text_field( $_REQUEST['log'] ) ;
1606
1607
		    	}
1608
1609
				// get setup the rest of the creds array
1610
				$creds['user_password'] = sanitize_text_field( $_REQUEST['pwd'] );
1611
				$creds['remember'] = isset( $_REQUEST['rememberme'] ) ? true : false ;
1612
1613
				//attempt logging in with the given details
1614
				$user = wp_signon( $creds, false );
1615
1616
				if ( is_wp_error($user) ){ // on login failure
1617
                    wp_redirect( esc_url_raw( add_query_arg('login', 'failed', $referrer) ) );
1618
                    exit;
1619
				}else{ // on login success
1620
1621
					/**
1622
					* change the redirect url programatically
1623
					*
1624
					* @since 1.6.1
1625
					*
1626
					* @param string $referrer the page where the current url wheresensei login form was posted from
1627
					*/
1628
1629
					$success_redirect_url = apply_filters('sesei_login_success_redirect_url', remove_query_arg( 'login', $referrer ) );
1630
1631
					wp_redirect( esc_url_raw( $success_redirect_url ) );
1632
		        	exit;
1633
1634
				}	// end is_wp_error($user)
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% 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...
1635
1636
		    }else{ // if username or password is empty
1637
1638
                wp_redirect( esc_url_raw( add_query_arg('login', 'emptyfields', $referrer) ) );
1639
		        exit;
1640
1641
		    } // end if username $_REQUEST['log']  and password $_REQUEST['pwd'] is empty
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...
1642
1643
	    }elseif( ( isset( $_GET['login'] ) ) ) {
1644
	    	// else if this request is a redircect from a previously faile login request
1645
	    	$this->login_message_process();
1646
1647
			//exit the handle login request function
1648
			return;
1649
	    }
1650
1651
	    // if none of the above
1652
	    return;
1653
1654
	} // End  sensei_login_fail_redirect_to_front_end_login
1655
1656
	/**
1657
	 * handle sensei specific registration requests
1658
	 *
1659
	 * @return void redirect
1660
	 *
1661
	 */
1662
	public function sensei_process_registration(){
1663
		global 	 $current_user;
1664
		// check the for the sensei specific registration requests
1665
		if( !isset( $_POST['sensei_reg_username'] ) && ! isset( $_POST['sensei_reg_email'] ) && !isset( $_POST['sensei_reg_password'] )){
1666
			// exit functionas this is not a sensei registration request
1667
			return ;
1668
		}
1669
		// check for spam throw cheating huh
1670
		if( isset( $_POST['email_2'] ) &&  '' !== $_POST['email_2']   ){
1671
			$message = 'Error:  The spam field should be empty';
1672
			Sensei()->notices->add_notice( $message, 'alert');
0 ignored issues
show
Bug introduced by
The property notices does not seem to exist. Did you mean notice?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1673
			return;
1674
		}
1675
1676
		// retreive form variables
1677
		$new_user_name		= sanitize_user( $_POST['sensei_reg_username'] );
1678
		$new_user_email		= $_POST['sensei_reg_email'];
1679
		$new_user_password	= $_POST['sensei_reg_password'];
1680
1681
		// Check the username
1682
		$username_error_notice = '';
1683
		if ( $new_user_name == '' ) {
1684
			$username_error_notice =  __( '<strong>ERROR</strong>: Please enter a username.' );
1685
		} elseif ( ! validate_username( $new_user_name ) ) {
1686
			$username_error_notice =  __( '<strong>ERROR</strong>: This username is invalid because it uses illegal characters. Please enter a valid username.' );
1687
		} elseif ( username_exists( $new_user_name ) ) {
1688
			$username_error_notice =  __( '<strong>ERROR</strong>: This username is already registered. Please choose another one.' );
1689
		}
1690
1691
		// exit on username error
1692
		if( '' !== $username_error_notice ){
1693
			Sensei()->notices->add_notice( $username_error_notice , 'alert');
0 ignored issues
show
Bug introduced by
The property notices does not seem to exist. Did you mean notice?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1694
			return;
1695
		}
1696
1697
		// Check the e-mail address
1698
		$email_error_notice = '';
1699
		if ( $new_user_email == '' ) {
1700
			$email_error_notice = __( '<strong>ERROR</strong>: Please type your e-mail address.' );
1701
		} elseif ( ! is_email( $new_user_email ) ) {
1702
			$email_error_notice = __( '<strong>ERROR</strong>: The email address isn&#8217;t correct.' );
1703
		} elseif ( email_exists( $new_user_email ) ) {
1704
			$email_error_notice = __( '<strong>ERROR</strong>: This email is already registered, please choose another one.' );
1705
		}
1706
1707
		// exit on email address error
1708
		if( '' !== $email_error_notice ){
1709
			Sensei()->notices->add_notice( $email_error_notice , 'alert');
0 ignored issues
show
Bug introduced by
The property notices does not seem to exist. Did you mean notice?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1710
			return;
1711
		}
1712
1713
		//check user password
1714
1715
		// exit on email address error
1716
		if( empty( $new_user_password ) ){
1717
			Sensei()->notices->add_notice(  __( '<strong>ERROR</strong>: The password field may not be empty, please enter a secure password.' )  , 'alert');
0 ignored issues
show
Bug introduced by
The property notices does not seem to exist. Did you mean notice?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1718
			return;
1719
		}
1720
1721
		// register user
1722
		$user_id = wp_create_user( $new_user_name, $new_user_password, $new_user_email );
1723
		if ( ! $user_id || is_wp_error( $user_id ) ) {
1724
			Sensei()->notices->add_notice( sprintf( __( '<strong>ERROR</strong>: Couldn\'t register you&hellip; please contact the <a href="mailto:%s">webmaster</a> !' ), get_option( 'admin_email' ) ), 'alert');
0 ignored issues
show
Bug introduced by
The property notices does not seem to exist. Did you mean notice?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1725
		}
1726
1727
		// notify the user
1728
		wp_new_user_notification( $user_id, $new_user_password );
1729
1730
		// set global current user aka log the user in
1731
		$current_user = get_user_by( 'id', $user_id );
1732
		wp_set_auth_cookie( $user_id, true );
1733
1734
		// Redirect
1735
		global $wp;
1736
		if ( wp_get_referer() ) {
1737
			$redirect = esc_url( wp_get_referer() );
1738
		} else {
1739
			$redirect = esc_url( home_url( $wp->request ) );
1740
		}
1741
1742
		wp_redirect( apply_filters( 'sensei_registration_redirect', $redirect ) );
1743
		exit;
1744
1745
	} // end  sensei_process_registration)()
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% 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...
1746
1747
	/**
1748
	 * login_message_process(). handle the login message displayed on faile login
1749
	 *
1750
	 * @return void redirect
1751
	 * @since 1.7.0
1752
	 */
1753
	public function login_message_process(){
1754
1755
1756
		    // setup the message variables
1757
			$message = '';
1758
1759
			//only output message if the url contains login=failed and login=emptyfields
1760
1761
			if( $_GET['login'] == 'failed' ){
1762
1763
				$message = __('Incorrect login details', 'woothemes-sensei' );
1764
1765
			}elseif( $_GET['login'] == 'emptyfields'  ){
1766
1767
				$message= __('Please enter your username and password', 'woothemes-sensei' );
1768
			}
1769
1770
			Sensei()->notices->add_notice( $message, 'alert');
0 ignored issues
show
Bug introduced by
The property notices does not seem to exist. Did you mean notice?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1771
1772
	}// end login_message_process
1773
1774
1775
    /**
1776
     * sensei_show_admin_bar(). Use WooCommerce filter
1777
     * to show admin bar to Teachers as well.
1778
     *
1779
     * @return void redirect
1780
     *
1781
     */
1782
    public function sensei_show_admin_bar () {
1783
1784
        if (current_user_can('edit_courses')) {
1785
1786
            add_filter( 'woocommerce_disable_admin_bar', '__return_false', 10, 1);
1787
1788
        }
1789
1790
    }
1791
1792
} // End Class
1793
1794
/**
1795
 * Class WooThemes_Sensei_Frontend
1796
 * for backward compatibility
1797
 * @since 1.9.0
1798
 */
1799
class WooThemes_Sensei_Frontend extends Sensei_Frontend{}
1800