Issues (896)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

includes/template-functions.php (6 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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

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

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

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

Loading history...
2
if ( ! defined( 'ABSPATH' ) ){ exit; } // Exit if accessed directly
3
4
	/***************************************************************************************************
5
	 * 	Output tags.
6
	 ***************************************************************************************************/
7
8
    /**
9
     * sensei_course_archive_next_link function.
10
     *
11
     * @access public
12
     * @param string $type (default: 'newcourses')
13
     * @return void
14
     */
15
    function sensei_course_archive_next_link( $type = 'newcourses' ) {
16
17
        _deprecated_function('sensei_course_archive_next_link', '1.9.0','This is no longer used or required in Sensei.');
18
19
    } // End sensei_course_archive_next_link()
20
21
	 /**
22
	  * course_single_lessons function.
23
	  *
24
	  * @access public
25
	  * @return void
26
	  */
27 View Code Duplication
	 function course_single_lessons() {
0 ignored issues
show
This function 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...
28
29
         // load backwards compatible template name if it exists in the users theme
30
         $located_template= locate_template( Sensei()->template_url . 'single-course/course-lessons.php' );
31
         if( $located_template ){
32
33
             Sensei_Templates::get_template( 'single-course/course-lessons.php' );
34
             return;
35
36
        }
37
38
		Sensei_Templates::get_template( 'single-course/lessons.php' );
39
40
	 } // End course_single_lessons()
41
42
43
	 /**
44
	  * lesson_single_meta function.
45
	  *
46
	  * @access public
47
	  * @return void
48
	  */
49
	 function lesson_single_meta() {
50
51
         _deprecated_function('lesson_single_meta','1.9;0', 'WooThemes_Sensei_Lesson::the_lesson_meta' );
52
         sensei_the_single_lesson_meta();
53
54
	 } // End lesson_single_meta()
55
56
57
	 /**
58
	  * quiz_questions function.
59
	  *
60
	  * @access public
61
	  * @param bool $return (default: false)
62
	  * @return void
63
      * @deprecated since 1.9.0
64
	  */
65
	 function quiz_questions( $return = false ) {
0 ignored issues
show
The parameter $return is not used and could be removed.

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

Loading history...
66
67
	 	Sensei_Templates::get_template( 'single-quiz/quiz-questions.php' );
68
69
	 } // End quiz_questions()
70
71
	 /**
72
	  * quiz_question_type function.
73
	  *
74
	  * @access public
75
	  * @since  1.3.0
76
	  * @return void
77
      * @deprecated
78
	  */
79
	 function quiz_question_type( $question_type = 'multiple-choice' ) {
80
81
         Sensei_Templates::get_template( 'single-quiz/question_type-' . $question_type . '.php' );
82
83
	 } // End lesson_single_meta()
84
85
	 /***************************************************************************************************
86
	 * Helper functions.
87
	 ***************************************************************************************************/
88
89
	/**
90
	 * sensei_check_prerequisite_course function.
91
	 *
92
     * @deprecated since 1.9.0 use Sensei_Course::is_prerequisite_complete( $course_id );
93
	 * @access public
94
	 * @param mixed $course_id
95
	 * @return bool
96
	 */
97
	function sensei_check_prerequisite_course( $course_id ) {
98
99
        return Sensei_Course::is_prerequisite_complete( $course_id );
100
101
	} // End sensei_check_prerequisite_course()
102
103
104
	/**
105
	 * sensei_start_course_form function.
106
	 *
107
	 * @access public
108
	 * @param mixed $course_id
109
	 * @return void
110
	 */
111
	function sensei_start_course_form( $course_id ) {
112
113
		$prerequisite_complete = sensei_check_prerequisite_course( $course_id );
0 ignored issues
show
Deprecated Code introduced by
The function sensei_check_prerequisite_course() has been deprecated with message: since 1.9.0 use Sensei_Course::is_prerequisite_complete( $course_id );

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

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

Loading history...
114
115 View Code Duplication
		if ( $prerequisite_complete ) {
0 ignored issues
show
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...
116
		?><form method="POST" action="<?php echo esc_url( get_permalink() ); ?>">
117
118
    			<input type="hidden" name="<?php echo esc_attr( 'woothemes_sensei_start_course_noonce' ); ?>" id="<?php echo esc_attr( 'woothemes_sensei_start_course_noonce' ); ?>" value="<?php echo esc_attr( wp_create_nonce( 'woothemes_sensei_start_course_noonce' ) ); ?>" />
119
120
    			<span><input name="course_start" type="submit" class="course-start" value="<?php _e( 'Start taking this Course', 'woothemes-sensei' ); ?>"/></span>
121
122
    		</form><?php
123
    	} // End If Statement
124
	} // End sensei_start_course_form()
125
126
127
	/**
128
	 * sensei_wc_add_to_cart function.
129
	 *
130
     * @deprecated since Sensei_WC::the_add_to_cart_button_html( $course_id );
131
	 * @access public
132
	 * @param mixed $course_id
133
	 * @return void
134
	 */
135
	function sensei_wc_add_to_cart( $course_id ) {
136
137
		Sensei_WC::the_add_to_cart_button_html( $course_id );
138
139
	} // End sensei_wc_add_to_cart()
140
141
142
	/**
143
	 * sensei_check_if_product_is_in_cart function.
144
	 *
145
	 * @deprecated since 1.9.0
146
	 * @param int $wc_post_id (default: 0)
0 ignored issues
show
There is no parameter named $wc_post_id. Was it maybe removed?

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

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

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

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

Loading history...
147
	 * @return bool
148
	 */
149
	function sensei_check_if_product_is_in_cart( $wc_product_id = 0 ) {
150
        return Sensei_WC::is_product_in_cart( $wc_product_id );
151
	} // End sensei_check_if_product_is_in_cart()
152
153
	/**
154
	 * sensei_simple_course_price function.
155
	 *
156
	 * @access public
157
	 * @param mixed $post_id
158
	 * @return void
159
	 */
160
	function sensei_simple_course_price( $post_id ) {
161
162
		//WooCommerce Pricing
163
        if ( Sensei_WC::is_woocommerce_active() ) {
164
    	    $wc_post_id = get_post_meta( $post_id, '_course_woocommerce_product', true );
165
    	    if ( 0 < $wc_post_id ) {
166
    	    	// Get the product
167
    	    	$product = Sensei()->sensei_get_woocommerce_product_object( $wc_post_id );
168
169
    	    	if ( isset( $product ) && !empty( $product )  &&  $product->is_purchasable() && $product->is_in_stock() && !sensei_check_if_product_is_in_cart( $wc_post_id ) ) { ?>
170
    	    		<span class="course-price"><?php echo $product->get_price_html(); ?></span>
171
    	    	<?php } // End If Statement
172
    	    } // End If Statement
173
    	} // End If Statement
174
	} // End sensei_simple_course_price()
175
176
	/**
177
	 * sensei_recent_comments_widget_filter function.
178
	 *
179
	 * @access public
180
	 * @param array $widget_args (default: array())
181
	 * @return array
182
	 */
183
	function sensei_recent_comments_widget_filter( $widget_args = array() ) {
184
		if ( ! isset( $widget_args['post_type'] ) ) $widget_args['post_type'] = array( 'post', 'page' );
185
		return $widget_args;
186
	} // End sensei_recent_comments_widget_filter()
187
	add_filter( 'widget_comments_args', 'sensei_recent_comments_widget_filter', 10, 1 );
188
189
	/**
190
	 * sensei_course_archive_filter function.
191
	 *
192
	 * @access public
193
	 * @param WP_Query $query ( default: array ( ) )
194
	 * @return void
195
	 */
196
	function sensei_course_archive_filter( $query ) {
197
198
199
		if ( ! $query->is_main_query() )
200
        	return;
201
202
		// Apply Filter only if on frontend and when course archive is running
203
		$course_page_id = intval( Sensei()->settings->settings[ 'course_page' ] );
204
205
		if ( ! is_admin() && 0 < $course_page_id && 0 < intval( $query->get( 'page_id' ) ) && $query->get( 'page_id' ) == $course_page_id ) {
206
			// Check for pagination settings
207 View Code Duplication
   			if ( isset( Sensei()->settings->settings[ 'course_archive_amount' ] ) && ( 0 < absint( Sensei()->settings->settings[ 'course_archive_amount' ] ) ) ) {
208
    			$amount = absint( Sensei()->settings->settings[ 'course_archive_amount' ] );
209
    		} else {
210
    			$amount = $query->get( 'posts_per_page' );
211
    		} // End If Statement
212
    		$query->set( 'posts_per_page', $amount );
213
		} // End If Statement
214
	} // End sensei_course_archive_filter()
215
	add_filter( 'pre_get_posts', 'sensei_course_archive_filter', 10, 1 );
216
217
	/**
218
	 * sensei_complete_lesson_button description
219
	 * since 1.0.3
220
	 * @return html
221
	 */
222
	function sensei_complete_lesson_button() {
223
		do_action( 'sensei_complete_lesson_button' );
224
	} // End sensei_complete_lesson_button()
225
226
	/**
227
	 * sensei_reset_lesson_button description
228
	 * since 1.0.3
229
	 * @return html
230
	 */
231
	function sensei_reset_lesson_button() {
232
		do_action( 'sensei_reset_lesson_button' );
233
	} // End sensei_reset_lesson_button()
234
235
	/**
236
	 * sensei_get_prev_next_lessons Returns the next and previous Lessons in the Course
237
	 * since 1.0.9
238
	 * @param  integer $lesson_id
239
	 * @return array $return_values
240
	 */
241
	function sensei_get_prev_next_lessons( $lesson_id = 0 ) {
242
243
		$return_values = array();
244
		$return_values['prev_lesson'] = 0;
245
		$return_values['next_lesson'] = 0;
246
		if ( 0 < $lesson_id ) {
247
			// Get the List of Lessons in the Course
248
			$lesson_course_id = get_post_meta( $lesson_id, '_lesson_course', true );
249
			$all_lessons = array();
250
251
            $modules = Sensei()->modules->get_course_modules( intval( $lesson_course_id ) );
252
253
            if( !empty( $modules )  ){
254
                foreach( (array) $modules as $module ) {
255
256
                    $args = array(
257
                        'post_type' => 'lesson',
258
                        'post_status' => 'publish',
259
                        'posts_per_page' => -1,
260
                        'meta_query' => array(
261
                            array(
262
                                'key' => '_lesson_course',
263
                                'value' => intval( $lesson_course_id ),
264
                                'compare' => '='
265
                            )
266
                        ),
267
                        'tax_query' => array(
268
                            array(
269
                                'taxonomy' => Sensei()->modules->taxonomy,
270
                                'field' => 'id',
271
                                'terms' => intval( $module->term_id )
272
                            )
273
                        ),
274
                        'meta_key' => '_order_module_' . $module->term_id,
275
                        'orderby' => 'meta_value_num date',
276
                        'order' => 'ASC',
277
                        'suppress_filters' => 0
278
                    );
279
280
                    $lessons = get_posts( $args );
281
                    if ( 0 < count( $lessons ) ) {
282
                        foreach ($lessons as $lesson_item){
283
                            $all_lessons[] = $lesson_item->ID;
284
                        } // End For Loop
285
                    } // End If Statement
286
287
                }//end for each
288
289
            }// end if empty modules
290
291
            $args = array(
292
                'post_type' => 'lesson',
293
                'posts_per_page' => -1,
294
                'suppress_filters' => 0,
295
                'meta_key' => '_order_' . $lesson_course_id,
296
                'orderby' => 'meta_value_num date',
297
                'order' => 'ASC',
298
                'meta_query' => array(
299
                    array(
300
                        'key' => '_lesson_course',
301
                        'value' => intval( $lesson_course_id ),
302
                    ),
303
                ),
304
                'post__not_in' => $all_lessons,
305
            );
306
307
            $other_lessons = get_posts( $args );
308
            if ( 0 < count( $other_lessons ) ) {
309
				foreach ($other_lessons as $lesson_item){
310
					$all_lessons[] = $lesson_item->ID;
311
				} // End For Loop
312
			} // End If Statement
313
314
            if ( 0 < count( $all_lessons ) ) {
315
				$found_index = false;
316
				foreach ( $all_lessons as $lesson ){
317
					if ( $found_index && $return_values['next_lesson'] == 0 ) {
318
						$return_values['next_lesson'] = $lesson;
319
					} // End If Statement
320
					if ( $lesson == $lesson_id ) {
321
						// Is the current post
322
						$found_index = true;
323
					} // End If Statement
324
					if ( !$found_index ) {
325
						$return_values['prev_lesson'] = $lesson;
326
					} // End If Statement
327
				} // End For Loop
328
			} // End If Statement
329
330
		} // End If Statement
331
		return $return_values;
332
	} // End sensei_get_prev_next_lessons()
333
334
  /**
335
   * sensei_get_excerpt Returns the excerpt for the $post
336
   *
337
   * Unhooks wp_trim_excerpt() so to disable excerpt auto-gen.
338
   *
339
   * @deprecated since  1.9.0
340
   * @param  int|WP_Post $post_id Optional. Defaults to current post
341
   * @return string $excerpt
342
   */
343
  function sensei_get_excerpt( $post_id = '' ) {
344
345
      global $post;
346
      _deprecated_function('sensei_get_excerpt', 'use the wordpress excerpt functionality.');
347
      return get_the_excerpt();
348
349
  }
350
351
	function sensei_has_user_started_course( $post_id = 0, $user_id = 0 ) {
352
		_deprecated_function( __FUNCTION__, '1.7', "WooThemes_Sensei_Utils::user_started_course()" );
353
		return Sensei_Utils::user_started_course( $post_id, $user_id );
354
	} // End sensei_has_user_started_course()
355
356
	function sensei_has_user_completed_lesson( $post_id = 0, $user_id = 0 ) {
357
		_deprecated_function( __FUNCTION__, '1.7', "WooThemes_Sensei_Utils::user_completed_lesson()" );
358
		return Sensei_Utils::user_completed_lesson( $post_id, $user_id );
359
	} // End sensei_has_user_completed_lesson()
360
361
/**
362
 * Determine if a user has completed the pre-requisite lesson.
363
 *
364
 * @uses
365
 *
366
 * @param int $current_lesson_id
367
 * @param int $user_id
368
 * @return bool
369
*/
370
function sensei_has_user_completed_prerequisite_lesson( $current_lesson_id, $user_id ) {
371
372
    return WooThemes_Sensei_Lesson::is_pre_requisite_complete( $current_lesson_id, $user_id );
373
374
} // End sensei_has_user_completed_prerequisite_lesson()
375
376
/*******************************
377
 *
378
 * Module specific template tags
379
 *
380
 ******************************/
381
382
/**
383
 * This function checks if the current course has modules.
384
 *
385
 * This must only be used within the loop.
386
 *
387
 * I checks the current global post (course) if it has modules.
388
 *
389
 * @since 1.9.0
390
 *
391
 * @param string $course_post_id options
392
 * @return bool
393
 *
394
 */
395
function sensei_have_modules( $course_post_id = '' ){
396
397
	global $post, $wp_query, $sensei_modules_loop;
398
399
	// set the current course to be the global post again
400
	wp_reset_query();
401
	$post = $wp_query->post;
402
403
	if( empty( $course_post_id ) ){
404
405
		$course_id = $post->ID;
406
407
	}
408
409
	// doesn't apply to none course post types
410
	if( ! sensei_is_a_course( $course_id )  ){
411
		return false;
412
	}
413
414
	// check the current item compared to the total number of modules
415
	if( $sensei_modules_loop[ 'current' ] + 1 > $sensei_modules_loop[ 'total' ]  ){
416
417
		return false;
418
419
	}else{
420
421
		return true;
422
423
	}
424
425
} //sensei_have_modules
426
427
428
/**
429
 * Setup the next module int the module loop
430
 *
431
 * @since 1.9.0
432
 */
433
function sensei_setup_module(){
434
435
	global  $sensei_modules_loop, $wp_query;
436
437
	// increment the index
438
	$sensei_modules_loop[ 'current' ]++;
439
	$index = $sensei_modules_loop[ 'current' ];
440
	if( isset( $sensei_modules_loop['modules'][ $index ] ) ) {
441
442
		$sensei_modules_loop['current_module'] = $sensei_modules_loop['modules'][$index];
443
		// setup the query for the module lessons
444
		$course_id = $sensei_modules_loop['course_id'];
445
		$module_term_id = $sensei_modules_loop['current_module']->term_id;
446
		$modules_query = Sensei()->modules->get_lessons_query( $course_id , $module_term_id );
447
448
		// setup the global wp-query only if the lessons
449
		if( $modules_query->have_posts() ){
450
451
			$wp_query = $modules_query;
452
453
		}else{
454
455
			wp_reset_query();
456
457
		}
458
459
	} else {
460
461
		wp_reset_query();
462
463
	}
464
465
}// end sensei_the_module
466
467
/**
468
 * Check if the current module in the modules loop has any lessons.
469
 * This relies on the global $wp_query. Which will be setup for each module
470
 * by sensei_the_module(). This function must only be used withing the module lessons loop.
471
 *
472
 * If the loop has not been initiated this function will check if the first
473
 * module has lessons.
474
 *
475
 * @return bool
476
 */
477
function sensei_module_has_lessons(){
478
479
	global $wp_query, $sensei_modules_loop;
480
481
	if( 'lesson' == $wp_query->get('post_type') ){
482
483
		return have_posts();
484
485
	}else{
486
487
        // if the loop has not been initiated check the first module has lessons
488
        if( -1 == $sensei_modules_loop[ 'current' ]  ){
489
490
            $index = 0;
491
492
            if( isset( $sensei_modules_loop['modules'][ $index ] ) ) {
493
                // setup the query for the module lessons
494
                $course_id = $sensei_modules_loop['course_id'];
495
496
                $module_term_id = $sensei_modules_loop['modules'][ $index ] ->term_id;
497
                $modules_query = Sensei()->modules->get_lessons_query( $course_id , $module_term_id );
498
499
                // setup the global wp-query only if the lessons
500
                if( $modules_query->have_posts() ){
501
502
                    return true;
503
504
                }
505
            }
506
        }
507
        // default to false if the first module doesn't have posts
508
		return false;
509
510
	}
511
512
}
513
514
/**
515
 * This function return the Module title to be used as an html element attribute value.
516
 *
517
 * Should only be used within the Sensei modules loop.
518
 *
519
 * @since 1.9.0
520
 *
521
 * @uses sensei_the_module_title
522
 * @return string
523
 */
524
function sensei_the_module_title_attribute(){
525
526
	esc_attr_e( sensei_get_the_module_title() );
527
528
}
529
530
/**
531
 * Returns a permalink to the module currently loaded within the Single Course module loop.
532
 *
533
 * This function should only be used with the Sensei modules loop.
534
 *
535
 * @return string
536
 */
537
function sensei_the_module_permalink(){
538
539
	global $sensei_modules_loop;
540
	$course_id = $sensei_modules_loop['course_id'];
541
	$module_url = add_query_arg('course_id', $course_id, get_term_link( $sensei_modules_loop['current_module'], 'module' ) );
542
	$module_term_id = $sensei_modules_loop['current_module']->term_id;
543
544
	/**
545
	 * Filter the module permalink url. This fires within the sensei_the_module_permalink function.
546
	 *
547
	 * @since 1.9.0
548
	 *
549
	 * @param string $module_url
550
	 * @param int $module_term_id
551
	 * @param string $course_id
552
	 */
553
	 echo esc_url_raw( apply_filters( 'sensei_the_module_permalink', $module_url, $module_term_id  ,$course_id ) );
554
555
}// end sensei_the_module_permalink
556
557
/**
558
 * Returns the current module name. This must be used
559
 * within the Sensei module loop.
560
 *
561
 * @since 1.9.0
562
 *
563
 * @return string
564
 */
565
function sensei_get_the_module_title(){
566
567
	global $sensei_modules_loop;
568
569
	$module_title = $sensei_modules_loop['current_module']->name;
570
	$module_term_id = $sensei_modules_loop['current_module']->term_id;
571
	$course_id = $sensei_modules_loop['course_id'];
572
573
	/**
574
	 * Filter the module title.
575
	 *
576
	 * This fires within the sensei_the_module_title function.
577
	 *
578
	 * @since 1.9.0
579
	 *
580
	 * @param $module_title
581
	 * @param $module_term_id
582
	 * @param $course_id
583
	 */
584
	return apply_filters( 'sensei_the_module_title',  $module_title , $module_term_id, $course_id );
585
586
}
587
588
/**
589
 * Ouputs the current module name. This must be used
590
 * within the Sensei module loop.
591
 *
592
 * @since 1.9.0
593
 * @uses sensei_get_the_module_title
594
 * @return string
595
 */
596
function sensei_the_module_title(){
597
598
	echo sensei_get_the_module_title();
599
600
}
601
602
/**
603
 * Give the current user's lesson progress status
604
 * Used in the module loop on the courses page
605
 *
606
 * @since 1.9.0
607
 * @return string
608
 */
609
function sensei_get_the_module_status(){
610
611
	if( ! is_user_logged_in() ){
612
		return '';
613
	}
614
615
    global $sensei_modules_loop;
616
    $module_title = $sensei_modules_loop['current_module']->name;
617
    $module_term_id = $sensei_modules_loop['current_module']->term_id;
618
    $course_id = $sensei_modules_loop['course_id'];
619
    $module_progress = Sensei()->modules->get_user_module_progress( $module_term_id, $course_id, get_current_user_id() );
620
621
    $module_status =  '';
622
    if ( $module_progress && $module_progress > 0) {
623
624
        $module_status = __('Completed', 'woothemes-sensei');
625
626
        if ($module_progress < 100) {
627
628
            $module_status = __('In progress', 'woothemes-sensei');
629
630
        }
631
632
    }
633
634
	if ( empty( $module_status ) ){
635
		return '';
636
	}
637
638
	$status_class = strtolower( str_replace( ' ', '-', $module_status  ) );
639
    $module_status_html = '<p class="status module-status ' . $status_class . '">'
640
                            . $module_status
641
                            . '</p>';
642
643
    /**
644
     * Filter the module status.
645
     *
646
     * This fires within the sensei_get_the_module_status function.
647
     *
648
     * @since 1.9.0
649
     *
650
     * @param $module_status_html
651
     * @param $module_term_id
652
     * @param $course_id
653
     */
654
    return apply_filters( 'sensei_the_module_status_html',  $module_status_html , $module_term_id, $course_id );
655
656
}
657
658
/**
659
 * Print out the current module status
660
 * @since 1.9.0
661
 */
662
function sensei_the_module_status(){
663
664
    echo sensei_get_the_module_status();
665
666
}
667
668
/************************
669
 *
670
 * Single Quiz Functions
671
 *
672
 ***********************/
673
674
/**
675
 * This function can only be run inside the the quiz question lessons loop.
676
 *
677
 * It will check if the current lessons loop has questions
678
 *
679
 * @since 1.9.0
680
 *
681
 * @return bool
682
 */
683
function sensei_quiz_has_questions(){
684
685
    global $sensei_question_loop;
686
687
    if( !isset( $sensei_question_loop['total'] ) ){
688
        return false;
689
    }
690
691
    if( $sensei_question_loop['current'] + 1 < $sensei_question_loop['total']  ){
692
693
        return true;
694
695
    }else{
696
697
        return false;
698
699
    }
700
701
}// end sensei_quiz_has_questions
702
703
/**
704
 * This funciton must only be run inside the quiz question loop.
705
 *
706
 * It will setup the next question in the loop into the current spot within the loop for further
707
 * execution.
708
 *
709
 * @since 1.9.0
710
711
 */
712
function sensei_setup_the_question(){
713
714
    global $sensei_question_loop;
715
716
    $sensei_question_loop['current']++;
717
    $index = $sensei_question_loop['current'];
718
    $sensei_question_loop['current_question'] =  $sensei_question_loop['questions'][ $index ] ;
719
720
721
}// end sensei_setup_the_question
722
723
/**
724
 * This function must only be run inside the quiz question loop.
725
 *
726
 * This function gets the type and loads the template that will handle it.
727
 *
728
 */
729
function sensei_the_question_content(){
730
731
    global $sensei_question_loop;
732
733
    $question_type = Sensei()->question->get_question_type( $sensei_question_loop['current_question']->ID );
734
735
    // load the template that displays the question information.
736
    WooThemes_Sensei_Question::load_question_template( $question_type );
737
738
}// end sensei_the_question_content
739
740
/**
741
 * Outputs the question class. This must only be run withing the single quiz question loop.
742
 *
743
 * @since 1.9.0
744
 */
745
function sensei_the_question_class(){
746
747
    global $sensei_question_loop;
748
749
    $question_type = Sensei()->question->get_question_type( $sensei_question_loop['current_question']->ID );
750
751
    /**
752
     * filter the sensei question class within
753
     * the quiz question loop.
754
     *
755
     * @since 1.9.0
756
     */
757
     $classes = apply_filters( 'sensei_question_classes', array( $question_type ) );
758
759
    $html_classes = '';
760
    foreach( $classes as $class ){
761
762
        $html_classes .= $class . ' ';
763
764
    }// end foreach
765
766
    esc_attr_e( trim( $html_classes ) );
767
768
}
769
770
/**
771
 * Output the ID of the current question within the quiz question loop.
772
 *
773
 * @since 1.9.0
774
 */
775
function sensei_get_the_question_id( ){
776
777
    global $sensei_question_loop;
778
    if( isset( $sensei_question_loop['current_question']->ID ) ){
779
780
        return $sensei_question_loop['current_question']->ID;
781
782
    }
783
784
}// end sensei_the_question_id
785
786
/************************
787
 *
788
 * Single Lesson Functions
789
 *
790
 ***********************/
791
792
/**
793
 * Template function to determine if the current user can
794
 * access the current lesson content being viewed.
795
 *
796
 * This function checks in the folowing order
797
 * - if the current user has all access based on their permissions
798
 * - If the access permission setting is enabled for this site, if not the user has accces
799
 * - if the lesson has a pre-requisite and if the user has completed that
800
 * - If it is a preview the user has access as well
801
 *
802
 * @since 1.9.0
803
 *
804
 * @param string $lesson_id
805
 * @return bool
806
 */
807
function sensei_can_user_view_lesson( $lesson_id = '', $user_id = ''  ){
808
809
    if( empty( $lesson_id ) ){
810
811
        $lesson_id = get_the_ID();
812
813
    }
814
815
	if ( 'quiz'== get_post_type( get_the_ID() ) ){
816
817
		$lesson_id = Sensei()->quiz->get_lesson_id( get_the_ID() );
818
819
	}
820
821
    if( empty( $user_id ) ){
822
823
        $user_id = get_current_user_id();
824
825
    }
826
827
    // Check for prerequisite lesson completions
828
    $pre_requisite_complete = WooThemes_Sensei_Lesson::is_prerequisite_complete( $lesson_id, $user_id );
829
    $lesson_course_id = get_post_meta( $lesson_id, '_lesson_course', true );
830
    $user_taking_course = Sensei_Utils::user_started_course( $lesson_course_id, $user_id );
831
832
    $is_preview = false;
833
    if( Sensei_Utils::is_preview_lesson( $lesson_id ) ) {
834
835
        $is_preview = true;
836
        $pre_requisite_complete = true;
837
838
    };
839
840
841
    $user_can_access_lesson =  false;
842
843
    if( is_user_logged_in() && $user_taking_course ){
844
845
        $user_can_access_lesson =  true;
846
847
    }
848
849
850
    $access_permission = false;
851
852
    if ( ! Sensei()->settings->get('access_permission')  || sensei_all_access() ) {
853
854
        $access_permission = true;
855
856
    }
857
858
    $can_user_view_lesson = $access_permission || ( $user_can_access_lesson && $pre_requisite_complete ) || $is_preview;
859
860
    /**
861
     * Filter the can user view lesson function
862
     *
863
     * @since 1.9.0
864
     *
865
     * @hooked Sensei_WC::alter_can_user_view_lesson
866
     *
867
     * @param bool $can_user_view_lesson
868
     * @param string $lesson_id
869
     * @param string $user_id
870
     */
871
    return apply_filters( 'sensei_can_user_view_lesson', $can_user_view_lesson, $lesson_id, $user_id );
872
873
} // end sensei_can_current_user_view_lesson
874
875
/**
876
 * Ouput the single lesson meta
877
 *
878
 * The function should only be called on the single lesson
879
 *
880
 */
881
function sensei_the_single_lesson_meta(){
882
883
    // if the lesson meta is included within theme load that instead of the function content
884
    $template = Sensei_Templates::locate_template( 'single-lesson/lesson-meta.php' );
885
    if( ! empty( $template ) ){
886
887
        Sensei_Templates::get_template( 'single-lesson/lesson-meta.php' );
888
        return;
889
890
    }
891
892
    // Get the meta info
893
    $lesson_course_id = absint( get_post_meta( get_the_ID(), '_lesson_course', true ) );
894
    $is_preview = Sensei_Utils::is_preview_lesson( get_the_ID() );
895
896
    // Complete Lesson Logic
897
    do_action( 'sensei_complete_lesson' );
898
    // Check that the course has been started
899
    if ( Sensei()->access_settings()
900
        || Sensei_Utils::user_started_course( $lesson_course_id, get_current_user_id())
901
        || $is_preview ) {
902
        ?>
903
        <section class="lesson-meta">
904
            <?php
905
            if( apply_filters( 'sensei_video_position', 'top', get_the_ID() ) == 'bottom' ) {
906
907
                do_action( 'sensei_lesson_video', get_the_ID() );
908
909
            }
910
            ?>
911
            <?php do_action( 'sensei_frontend_messages' ); ?>
912
913
            <?php if ( ! $is_preview
914
                || Sensei_Utils::user_started_course( $lesson_course_id, get_current_user_id()) ) {
915
916
                sensei_do_deprecated_action( 'sensei_lesson_quiz_meta','1.9.0', 'sensei_single_lesson_content_inside_before' ,array( get_the_ID(), get_current_user_id() )  );
917
918
            } ?>
919
        </section>
920
921
        <?php do_action( 'sensei_lesson_back_link', $lesson_course_id ); ?>
922
923
    <?php }
924
925
    do_action( 'sensei_lesson_meta_extra', get_the_ID() );
926
927
} // end the_single_lesson_meta
928
929
/**
930
 * This function runs the most common header hooks and ensures
931
 * templates are setup correctly.
932
 *
933
 * This function also runs the get_header for the general WP header setup.
934
 *
935
 * @uses get_header
936
 *
937
 * @since 1.9.0
938
 */
939
function get_sensei_header(){
940
941
    if ( ! defined( 'ABSPATH' ) ) exit;
942
943
    get_header();
944
945
    /**
946
     * sensei_before_main_content hook
947
     *
948
     * @hooked sensei_output_content_wrapper - 10 (outputs opening divs for the content)
949
     */
950
    do_action( 'sensei_before_main_content' );
951
952
}// end get_sensei_header
953
954
/**
955
 * This function runs the most common footer hooks and ensures
956
 * templates are setup correctly.
957
 *
958
 * This function also runs the get_header for the general WP header setup.
959
 *
960
 * @uses get_footer
961
 *
962
 * @since 1.9.0
963
 */
964
function get_sensei_footer(){
965
966
    /**
967
     * sensei_pagination hook
968
     *
969
     * @hooked sensei_pagination - 10 (outputs pagination)
970
     */
971
    do_action( 'sensei_pagination' );
972
973
    /**
974
     * sensei_after_main_content hook
975
     *
976
     * @hooked sensei_output_content_wrapper_end - 10 (outputs closing divs for the content)
977
     */
978
    do_action( 'sensei_after_main_content' );
979
980
    /**
981
     * sensei_sidebar hook
982
     *
983
     * @hooked sensei_get_sidebar - 10
984
     */
985
    do_action( 'sensei_sidebar' );
986
987
    get_footer();
988
989
}// end get_sensei_header
990
991
/**
992
 * Output the permissions message
993
 * title.
994
 *
995
 * @since 1.9.0
996
 */
997
function the_no_permissions_title(){
998
999
    /**
1000
     * Filter the no permissions title just before it is echo'd on the
1001
     * no-permissions.php file.
1002
     *
1003
     * @since 1.9.0
1004
     * @param $no_permissions_title
1005
     */
1006
    echo apply_filters( 'sensei_the_no_permissions_title', Sensei()->permissions_message['title'] );
1007
1008
}
1009
1010
/**
1011
 * Output the permissions message.
1012
 *
1013
 * @since 1.9.0
1014
 */
1015
function the_no_permissions_message( $post_id ){
1016
1017
    /**
1018
     * Filter the no permissions message just before it is echo'd on the
1019
     * no-permissions.php file.
1020
     *
1021
     * @since 1.9.0
1022
     * @param $no_permissions_message
1023
     */
1024
    echo apply_filters( 'sensei_the_no_permissions_message', Sensei()->permissions_message['message'] , $post_id );
1025
}
1026
1027
/**
1028
 * Output the sensei excerpt
1029
 *
1030
 * @since 1.9.0
1031
 */
1032
function sensei_the_excerpt( $post_id ){
1033
1034
    global $post;
1035
    the_excerpt( $post );
1036
1037
}
1038
1039
/**
1040
 * Get current url on the frontend
1041
 *
1042
 * @since 1.9.0
1043
 *
1044
 * @global WP $wp
1045
 * @return string $current_page_url
1046
 */
1047
 function sensei_get_current_page_url(){
1048
1049
     global $wp;
1050
     $current_page_url =  home_url( $wp->request );
1051
     return $current_page_url;
1052
1053
 }
1054
1055
/**
1056
 * Outputs the content for the my courses page
1057
 *
1058
 *
1059
 * @since 1.9.0
1060
 */
1061
function sensei_the_my_courses_content(){
1062
1063
    echo Sensei()->course->load_user_courses_content( wp_get_current_user() );
1064
1065
} // sensei_the_my_courses_content
1066
1067
/**
1068
 * This is a wrapper function for Sensei_Templates::get_template
1069
 * It helps simplify templates for designers by removing the class::function call.
1070
 *
1071
 * @param string $template_name the name of the template.
1072
 *              If it is in a sub directory please suply the directory name as well e.g. globals/wrapper-end.php
1073
 *
1074
 * @since 1.9.0
1075
 */
1076
function sensei_load_template( $template_name ){
1077
1078
    Sensei_Templates::get_template( $template_name );
1079
1080
}
1081
1082
/**
1083
 * This is a wrapper function for Sensei_Templates::get_part
1084
 * It helps simplify templates for designers by removing the class::function call.
1085
 *
1086
 * @param string $slug the first part to the template file name
1087
 * @param string $name the name of the template.
1088
 * @since 1.9.0
1089
 */
1090
function sensei_load_template_part( $slug, $name ){
1091
1092
    Sensei_Templates::get_part( $slug, $name );
1093
1094
}
1095
1096
/**
1097
 * Returns the the lesson excerpt.
1098
 *
1099
 * This function will not wrap the the excerpt with <p> tags.
1100
 * For the p tags call Sensei_Lesson::lesson_excerpt( $lesson)
1101
 *
1102
 * This function will only work for the lesson post type. All other post types will
1103
 * be ignored.
1104
 *
1105
 * @since 1.9.0
1106
 * @access public
1107
 * @param string $lesson_id
1108
 */
1109
function sensei_the_lesson_excerpt( $lesson_id = '' ) {
1110
1111
    if( empty( $lesson_id )){
1112
1113
        $lesson_id = get_the_ID();
1114
1115
    }
1116
1117
    if( 'lesson' != get_post_type( $lesson_id ) ){
1118
        return;
1119
    }
1120
1121
    echo Sensei_Lesson::lesson_excerpt( get_post( $lesson_id ), false );
1122
1123
}// End lesson_excerpt()
1124
1125
/**
1126
 * The the course result lessons template
1127
 *
1128
 * @since 1.9.0
1129
 */
1130 View Code Duplication
function sensei_the_course_results_lessons(){
1131
    // load backwards compatible template name if it exists in the users theme
1132
    $located_template= locate_template( Sensei()->template_url . 'course-results/course-lessons.php' );
1133
    if( $located_template ){
1134
1135
        Sensei_Templates::get_template( 'course-results/course-lessons.php' );
1136
        return;
1137
1138
    }
1139
1140
    Sensei_Templates::get_template( 'course-results/lessons.php' );
1141
}
1142
1143
/**
1144
 * Echo the number of columns (also number of items per row) on the
1145
 * the course archive.
1146
 *
1147
 * @uses Sensei_Course::get_loop_number_of_columns
1148
 * @since 1.9.0
1149
 */
1150
function sensei_courses_per_row(){
1151
1152
    echo Sensei_Course::get_loop_number_of_columns();
1153
1154
}
1155
1156
/**
1157
 * Wrapper function for Sensei_Templates::get_template( $template_name, $args, $path )
1158
 *
1159
 * @since 1.9.0
1160
 * @param $template_name
1161
 * @param $args
1162
 * @param $path
1163
 */
1164
function sensei_get_template( $template_name, $args, $path ){
1165
1166
    Sensei_Templates::get_template( $template_name, $args, $path );
1167
1168
}
1169
1170
/**
1171
 * Returns the lesson status class
1172
 *
1173
 * must be used in the loop.
1174
 * @since 1.9.0
1175
 *
1176
 * @return string $status_class
1177
 */
1178
function get_the_lesson_status_class(){
1179
1180
    $status_class = '';
1181
    $lesson_completed = Sensei_Utils::user_completed_lesson( get_the_ID(), get_current_user_id() );
1182
1183
    if ( $lesson_completed ) {
1184
        $status_class = 'completed';
1185
    }
1186
1187
    return  $status_class;
1188
1189
}// end get_the_lesson_status_class
1190
/**
1191
 * Outputs the lesson status class
1192
 *
1193
 * must be used in the lesson loop
1194
 *
1195
 * @since 1.9.0
1196
 */
1197
function sensei_the_lesson_status_class(){
1198
1199
    echo get_the_lesson_status_class();
1200
}
1201