Completed
Push — master ( ab9b7f...ec0479 )
by Dwain
04:39
created

Sensei_Lesson::footer_quiz_call_to_action()   C

Complexity

Conditions 12
Paths 144

Size

Total Lines 60
Code Lines 30

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 60
rs 5.7643
cc 12
eloc 30
nc 144
nop 2

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
3
4
/**
5
 * Sensei Lessons Class
6
 *
7
 * All functionality pertaining to the lessons post type in Sensei.
8
 *
9
 * @package WordPress
10
 * @subpackage Sensei
11
 * @category Core
12
 * @author WooThemes
13
 * @since 1.0.0
14
 */
15
class Sensei_Lesson {
16
	public $token;
17
	public $meta_fields;
18
19
	/**
20
	 * Constructor.
21
	 * @since  1.0.0
22
	 */
23
	public function __construct () {
24
		// Setup meta fields for this post type
25
		$this->meta_fields = array( 'lesson_prerequisite', 'lesson_course', 'lesson_preview', 'lesson_length', 'lesson_complexity', 'lesson_video_embed' );
26
27
        $this->question_order = '';
0 ignored issues
show
Bug introduced by
The property question_order does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
28
29
		// Admin actions
30
		if ( is_admin() ) {
31
32
			// Metabox functions
33
			add_action( 'admin_menu', array( $this, 'meta_box_setup' ), 20 );
34
			add_action( 'save_post', array( $this, 'meta_box_save' ) );
35
			add_action( 'save_post', array( $this, 'quiz_update' ) );
36
37
			// Custom Write Panel Columns
38
			add_filter( 'manage_edit-lesson_columns', array( $this, 'add_column_headings' ), 10, 1 );
39
			add_action( 'manage_posts_custom_column', array( $this, 'add_column_data' ), 10, 2 );
40
41
			// Add/Update question
42
			add_action( 'wp_ajax_lesson_update_question', array( $this, 'lesson_update_question' ) );
43
			add_action( 'wp_ajax_nopriv_lesson_update_question', array( $this, 'lesson_update_question' ) );
44
45
			// Add course
46
			add_action( 'wp_ajax_lesson_add_course', array( $this, 'lesson_add_course' ) );
47
			add_action( 'wp_ajax_nopriv_lesson_add_course', array( $this, 'lesson_add_course' ) );
48
49
			// Update grade type
50
			add_action( 'wp_ajax_lesson_update_grade_type', array( $this, 'lesson_update_grade_type' ) );
51
			add_action( 'wp_ajax_nopriv_lesson_update_grade_type', array( $this, 'lesson_update_grade_type' ) );
52
53
			// Update question order
54
			add_action( 'wp_ajax_lesson_update_question_order', array( $this, 'lesson_update_question_order' ) );
55
			add_action( 'wp_ajax_nopriv_lesson_update_question_order', array( $this, 'lesson_update_question_order' ) );
56
57
			//Update question order
58
			add_action( 'wp_ajax_lesson_update_question_order_random', array( $this, 'lesson_update_question_order_random' ) );
59
			add_action( 'wp_ajax_nopriv_lesson_update_question_order_random', array( $this, 'lesson_update_question_order_random' ) );
60
61
			// Get answer ID
62
			add_action( 'wp_ajax_question_get_answer_id', array( $this, 'question_get_answer_id' ) );
63
			add_action( 'wp_ajax_nopriv_question_get_answer_id', array( $this, 'question_get_answer_id' ) );
64
65
			// Add multiple questions
66
			add_action( 'wp_ajax_lesson_add_multiple_questions', array( $this, 'lesson_add_multiple_questions' ) );
67
			add_action( 'wp_ajax_nopriv_lesson_add_multiple_questions', array( $this, 'lesson_add_multiple_questions' ) );
68
69
			// Remove multiple questions
70
			add_action( 'wp_ajax_lesson_remove_multiple_questions', array( $this, 'lesson_remove_multiple_questions' ) );
71
			add_action( 'wp_ajax_nopriv_lesson_remove_multiple_questions', array( $this, 'lesson_remove_multiple_questions' ) );
72
73
			// Get question category limit
74
			add_action( 'wp_ajax_get_question_category_limit', array( $this, 'get_question_category_limit' ) );
75
			add_action( 'wp_ajax_nopriv_get_question_category_limit', array( $this, 'get_question_category_limit' ) );
76
77
			// Add existing questions
78
			add_action( 'wp_ajax_lesson_add_existing_questions', array( $this, 'lesson_add_existing_questions' ) );
79
			add_action( 'wp_ajax_nopriv_lesson_add_existing_questions', array( $this, 'lesson_add_existing_questions' ) );
80
81
			// Filter existing questions
82
			add_action( 'wp_ajax_filter_existing_questions', array( $this, 'quiz_panel_filter_existing_questions' ) );
83
			add_action( 'wp_ajax_nopriv_filter_existing_questions', array( $this, 'quiz_panel_filter_existing_questions' ) );
84
85
            // output bulk edit fields
86
            add_action( 'bulk_edit_custom_box', array( $this, 'all_lessons_edit_fields' ), 10, 2 );
87
            add_action( 'quick_edit_custom_box', array( $this, 'all_lessons_edit_fields' ), 10, 2 );
88
89
            // load quick edit default values
90
            add_action('manage_lesson_posts_custom_column', array( $this, 'set_quick_edit_admin_defaults'), 11, 2);
91
92
            // save bulk edit fields
93
            add_action( 'wp_ajax_save_bulk_edit_book', array( $this, 'save_all_lessons_edit_fields' ) );
94
95
            // flush rewrite rules when saving a lesson
96
            add_action('save_post', array( __CLASS__, 'flush_rewrite_rules' ) );
97
98
		} else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
99
			// Frontend actions
100
		} // End If Statement
101
	} // End __construct()
102
103
	/**
104
	 * meta_box_setup function.
105
	 *
106
	 * @access public
107
	 * @return void
108
	 */
109
	public function meta_box_setup () {
110
111
		// Add Meta Box for Prerequisite Lesson
112
		add_meta_box( 'lesson-prerequisite', __( 'Lesson Prerequisite', 'woothemes-sensei' ), array( $this, 'lesson_prerequisite_meta_box_content' ), $this->token, 'side', 'default' );
113
114
		// Add Meta Box for Lesson Course
115
		add_meta_box( 'lesson-course', __( 'Lesson Course', 'woothemes-sensei' ), array( $this, 'lesson_course_meta_box_content' ), $this->token, 'side', 'default' );
116
117
		// Add Meta Box for Lesson Preview
118
		add_meta_box( 'lesson-preview', __( 'Lesson Preview', 'woothemes-sensei' ), array( $this, 'lesson_preview_meta_box_content' ), $this->token, 'side', 'default' );
119
120
		// Add Meta Box for Lesson Information
121
		add_meta_box( 'lesson-info', __( 'Lesson Information', 'woothemes-sensei' ), array( $this, 'lesson_info_meta_box_content' ), $this->token, 'normal', 'default' );
122
123
		// Add Meta Box for Quiz Settings
124
		add_meta_box( 'lesson-quiz-settings', __( 'Quiz Settings', 'woothemes-sensei' ), array( $this, 'lesson_quiz_settings_meta_box_content' ), $this->token, 'normal', 'default' );
125
126
		// Add Meta Box for Lesson Quiz Questions
127
		add_meta_box( 'lesson-quiz', __( 'Quiz Questions', 'woothemes-sensei' ), array( $this, 'lesson_quiz_meta_box_content' ), $this->token, 'normal', 'default' );
128
129
		// Remove "Custom Settings" meta box.
130
		remove_meta_box( 'woothemes-settings', $this->token, 'normal' );
131
132
		// Add JS scripts
133
		add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
134
135
		// Add CSS
136
		add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_styles' ) );
137
138
	} // End meta_box_setup()
139
140
141
	/**
142
	 * lesson_info_meta_box_content function.
143
	 *
144
	 * @access public
145
	 * @return void
146
	 */
147
	public function lesson_info_meta_box_content () {
148
		global $post;
149
150
		$lesson_length = get_post_meta( $post->ID, '_lesson_length', true );
151
		$lesson_complexity = get_post_meta( $post->ID, '_lesson_complexity', true );
152
		$complexity_array = $this->lesson_complexities();
153
		$lesson_video_embed = get_post_meta( $post->ID, '_lesson_video_embed', true );
154
155
		$html = '';
156
		// Lesson Length
157
		$html .= '<p><label for="lesson_length">' . __( 'Lesson Length in minutes', 'woothemes-sensei' ) . ': </label>';
158
		$html .= '<input type="number" id="lesson-length" name="lesson_length" class="small-text" value="' . esc_attr( $lesson_length ) . '" /></p>' . "\n";
159
		// Lesson Complexity
160
		$html .= '<p><label for="lesson_complexity">' . __( 'Lesson Complexity', 'woothemes-sensei' ) . ': </label>';
161
		$html .= '<select id="lesson-complexity-options" name="lesson_complexity" class="chosen_select lesson-complexity-select">';
162
			$html .= '<option value="">' . __( 'None', 'woothemes-sensei' ) . '</option>';
163
			foreach ($complexity_array as $key => $value){
164
				$html .= '<option value="' . esc_attr( $key ) . '"' . selected( $key, $lesson_complexity, false ) . '>' . esc_html( $value ) . '</option>' . "\n";
165
			} // End For Loop
166
		$html .= '</select></p>' . "\n";
167
168
		$html .= '<p><label for="lesson_video_embed">' . __( 'Video Embed Code', 'woothemes-sensei' ) . ':</label><br/>' . "\n";
169
		$html .= '<textarea rows="5" cols="50" name="lesson_video_embed" tabindex="6" id="course-video-embed">' . $lesson_video_embed . '</textarea></p>' . "\n";
170
		$html .= '<p>' .  __( 'Paste the embed code for your video (e.g. YouTube, Vimeo etc.) in the box above.', 'woothemes-sensei' ) . '</p>';
171
172
		echo $html;
173
174
	} // End lesson_info_meta_box_content()
175
176
	/**
177
	 * lesson_prerequisite_meta_box_content function.
178
	 *
179
	 * @access public
180
	 * @return void
181
	 */
182
	public function lesson_prerequisite_meta_box_content () {
183
		global $post;
184
		// Get existing post meta
185
		$select_lesson_prerequisite = get_post_meta( $post->ID, '_lesson_prerequisite', true );
186
		// Get the Lesson Posts
187
		$post_args = array(	'post_type' 		=> 'lesson',
188
							'posts_per_page' 		=> -1,
189
							'orderby'         	=> 'title',
190
    						'order'           	=> 'ASC',
191
    						'exclude' 			=> $post->ID,
192
							'suppress_filters' 	=> 0
193
							);
194
		$posts_array = get_posts( $post_args );
195
		// Build the HTML to Output
196
		$html = '';
197
		$html .= wp_nonce_field( 'sensei-save-post-meta','woo_' . $this->token . '_nonce', true, false  );
198 View Code Duplication
		if ( count( $posts_array ) > 0 ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
199
			$html .= '<select id="lesson-prerequisite-options" name="lesson_prerequisite" class="chosen_select widefat">' . "\n";
200
			$html .= '<option value="">' . __( 'None', 'woothemes-sensei' ) . '</option>';
201
				foreach ($posts_array as $post_item){
202
					$html .= '<option value="' . esc_attr( absint( $post_item->ID ) ) . '"' . selected( $post_item->ID, $select_lesson_prerequisite, false ) . '>' . esc_html( $post_item->post_title ) . '</option>' . "\n";
203
				} // End For Loop
204
			$html .= '</select>' . "\n";
205
		} else {
206
			$html .= '<p>' . esc_html( __( 'No lessons exist yet. Please add some first.', 'woothemes-sensei' ) ) . '</p>';
207
		} // End If Statement
208
		// Output the HTML
209
		echo $html;
210
	} // End lesson_prerequisite_meta_box_content()
211
212
	/**
213
	 * lesson_preview_meta_box_content function.
214
	 *
215
	 * @access public
216
	 * @return void
217
	 */
218
	public function lesson_preview_meta_box_content () {
219
		global $post;
220
		// Get existing post meta
221
		$lesson_preview = get_post_meta( $post->ID, '_lesson_preview', true );
222
		$html = '';
223
		$html .= wp_nonce_field( 'sensei-save-post-meta','woo_' . $this->token . '_nonce', true, false  );
224
225
		$checked = '';
226
		if ( isset( $lesson_preview ) && ( '' != $lesson_preview ) ) {
227
	 	    $checked = checked( 'preview', $lesson_preview, false );
228
	 	} // End If Statement
229
230
	 	$html .= '<label for="lesson_preview">';
231
	 	$html .= '<input type="checkbox" id="lesson_preview" name="lesson_preview" value="preview" ' . $checked . '>&nbsp;' . __( 'Allow this lesson to be viewed without purchase/login', 'woothemes-sensei' ) . '<br>';
232
233
		// Output the HTML
234
		echo $html;
235
	} // End lesson_preview_meta_box_content()
236
237
	/**
238
	 * meta_box_save function.
239
	 *
240
	 * @access public
241
	 * @param int $post_id
242
	 * @return void
243
	 */
244
	public function meta_box_save ( $post_id ) {
245
246
		// Verify the nonce before proceeding.
247 View Code Duplication
		if ( ( get_post_type( $post_id ) != $this->token ) || !isset(   $_POST[ 'woo_' . $this->token . '_nonce'] )  || ! wp_verify_nonce( $_POST[ 'woo_' . $this->token . '_nonce' ], 'sensei-save-post-meta' ) ) {
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...
248
			return $post_id;
249
		} // End If Statement
250
		// Get the post type object.
251
		$post_type = get_post_type_object( get_post_type( $post_id ) );
252
		// Check if the current user has permission to edit the post.
253
		if ( !current_user_can( $post_type->cap->edit_post, $post_id ) ) {
254
			return $post_id;
255
		} // End If Statement
256
		// Check if the current post type is a page
257 View Code Duplication
		if ( 'page' == $_POST[ 'post_type' ] ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
258
			if ( ! current_user_can( 'edit_page', $post_id ) ) {
259
				return $post_id;
260
			} // End If Statement
261
		} else {
262
			if ( ! current_user_can( 'edit_post', $post_id ) ) {
263
				return $post_id;
264
			} // End If Statement
265
		} // End If Statement
266
		// Save the post meta data fields
267 View Code Duplication
		if ( isset($this->meta_fields) && is_array($this->meta_fields) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
268
			foreach ( $this->meta_fields as $meta_key ) {
269
				$this->save_post_meta( $meta_key, $post_id );
270
			} // End For Loop
271
		} // End If Statement
272
	} // End meta_box_save()
273
274
275
	/**
276
     * Update the lesson quiz and all the post meta
277
	 *
278
	 * @access public
279
	 * @return void
280
	 */
281
	public function quiz_update( $post_id ) {
282
		global $post;
283
		// Verify the nonce before proceeding.
284
		if ( ( 'lesson' != get_post_type( $post_id ) )|| !isset(   $_POST[ 'woo_' . $this->token . '_nonce'] )  || ! wp_verify_nonce( $_POST[ 'woo_' . $this->token . '_nonce' ], 'sensei-save-post-meta') ) {
285
			if ( isset($post->ID) ) {
286
				return $post->ID;
287
			} else {
288
				return false;
289
			} // End If Statement
290
		} // End If Statement
291
292
		if( wp_is_post_revision( $post_id ) || wp_is_post_autosave( $post_id ) ) {
293
			return;
294
		}
295
296
		// Temporarily disable the filter
297
        remove_action( 'save_post', array( $this, 'quiz_update' ) );
298
		// Save the Quiz
299
		$quiz_id = $this->lesson_quizzes( $post_id, 'any');
300
301
		 // Sanitize and setup the post data
302
		$_POST = stripslashes_deep( $_POST );
303
		if ( isset( $_POST[ 'quiz_id' ] ) && ( 0 < absint( $_POST[ 'quiz_id' ] ) ) ) {
304
			$quiz_id = absint( $_POST[ 'quiz_id' ] );
305
		} // End If Statement
306
		$post_title = esc_html( $_POST[ 'post_title' ] );
307
		$post_status = esc_html( $_POST[ 'post_status' ] );
308
		$post_content = '';
309
310
		// Setup Query Arguments
311
		$post_type_args = array(	'post_content' => $post_content,
312
  		    						'post_status' => $post_status,
313
  		    						'post_title' => $post_title,
314
  		    						'post_type' => 'quiz',
315
                                    'post_parent' => $post_id,
316
  		    						);
317
318
		$settings = $this->get_quiz_settings();
319
320
  		// Update or Insert the Lesson Quiz
321
		if ( 0 < $quiz_id ) {
322
			// Update the Quiz
323
			$post_type_args[ 'ID' ] = $quiz_id;
324
		    wp_update_post($post_type_args);
325
326
		    // Update the post meta data
327
		    update_post_meta( $quiz_id, '_quiz_lesson', $post_id );
328
329
		    foreach( $settings as $field ) {
330
		    	if( 'random_question_order' != $field['id'] ) {
331
			    	$value = $this->get_submitted_setting_value( $field );
332
			    	if( isset( $value ) ) {
333
			    		update_post_meta( $quiz_id, '_' . $field['id'], $value );
334
			    	}
335
			    }
336
		    }
337
338
		    // Set the post terms for quiz-type
339
		    wp_set_post_terms( $quiz_id, array( 'multiple-choice' ), 'quiz-type' );
340
		} else {
341
			// Create the Quiz
342
		    $quiz_id = wp_insert_post($post_type_args);
343
344
		    // Add the post meta data WP will add it if it doesn't exist
345
            update_post_meta( $quiz_id, '_quiz_lesson', $post_id );
346
347
		    foreach( $settings as $field ) {
348
		    	if( 'random_question_order' != $field['id'] ) {
349
350
                    //ignore values not posted to avoid
351
                    // overwriting with empty or default values
352
                    // when the values are posted from bulk edit or quick edit
353
                    if( !isset( $_POST[ $field['id'] ] ) ){
354
                        continue;
355
                    }
356
357
			    	$value = $this->get_submitted_setting_value( $field );
358
			    	if( isset( $value ) ) {
359
			    		add_post_meta( $quiz_id, '_' . $field['id'], $value );
360
			    	}
361
			    }
362
		    }
363
364
		    // Set the post terms for quiz-type
365
		    wp_set_post_terms( $quiz_id, array( 'multiple-choice' ), 'quiz-type' );
366
		} // End If Statement
367
368
		// Add default lesson order meta value
369
		$course_id = get_post_meta( $post_id, '_lesson_course', true );
370
		if( $course_id ) {
371
			if( ! get_post_meta( $post_id, '_order_' . $course_id, true ) ) {
372
				update_post_meta( $post_id, '_order_' . $course_id, 0 );
373
			}
374
		}
375
		// Add reference back to the Quiz
376
		update_post_meta( $post_id, '_lesson_quiz', $quiz_id );
377
		// Mark if the Lesson Quiz has questions
378
		$quiz_questions = Sensei()->lesson->lesson_quiz_questions( $quiz_id );
379
		if( 0 < count( $quiz_questions ) ) {
380
			update_post_meta( $post_id, '_quiz_has_questions', '1' );
381
		}
382
		else {
383
			delete_post_meta( $post_id, '_quiz_has_questions' );
384
		}
385
386
		// Restore the previously disabled filter
387
        add_action( 'save_post', array( $this, 'quiz_update' ) );
388
389
	} // End post_updated()
390
391
	public function get_submitted_setting_value( $field = false ) {
392
393
		if( ! $field ) return;
394
395
		$value = false;
0 ignored issues
show
Unused Code introduced by
$value 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...
396
397
		if( 'quiz_grade_type' == $field['id'] ) {
398
			if( isset( $_POST[ $field['id'] ] ) && 'on' == $_POST[ $field['id'] ] ) {
399
				$value = 'auto';
400
			} else {
401
				$value = 'manual';
402
			}
403
			return $value;
404
		}
405
406
		if ( isset( $_POST[ $field['id'] ] ) ) {
407
			$value = $_POST[ $field['id'] ];
408
		} else {
409
			$value = $field['default'];
410
		}
411
412
		return $value;
413
	}
414
415
	/**
416
	 * save_post_meta function.
417
	 * Saves lesson meta data
418
	 * @access private
419
	 * @param string $post_key (default: '')
420
	 * @param int $post_id (default: 0)
421
	 * @return int|bool meta id or saved status
422
	 */
423
	private function save_post_meta( $post_key = '', $post_id = 0 ) {
424
		// Get the meta key.
425
		$meta_key = '_' . $post_key;
426
427
        //ignore fields are not posted
428
429
        if( !isset( $_POST[ $post_key ] ) ){
430
431
            // except for lesson preview checkbox field
432
            if( 'lesson_preview' == $post_key ){
433
434
                $_POST[ $post_key ] = '';
435
436
            } else {
437
438
                return false;
439
440
            }
441
442
        }
443
444
		// Get the posted data and sanitize it for use as an HTML class.
445 View Code Duplication
		if ( 'lesson_video_embed' == $post_key) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
446
			$new_meta_value = esc_html( $_POST[$post_key] );
447
		} else {
448
			$new_meta_value = ( isset( $_POST[$post_key] ) ? sanitize_html_class( $_POST[$post_key] ) : '' );
449
		} // End If Statement
450
451
        // update field with the new value
452
        if( -1 != $new_meta_value  ){
453
            return update_post_meta( $post_id, $meta_key, $new_meta_value );
454
        }
455
456
	} // End save_post_meta()
457
458
	/**
459
	 * lesson_course_meta_box_content function.
460
	 *
461
	 * @access public
462
	 * @return void
463
	 */
464
	public function lesson_course_meta_box_content () {
465
		global $post;
466
		// Setup Lesson Meta Data
467
		$selected_lesson_course = 0;
468
		if ( 0 < $post->ID ) {
469
			$selected_lesson_course = get_post_meta( $post->ID, '_lesson_course', true );
470
		} // End If Statement
471
		// Handle preselected course
472 View Code Duplication
		if ( isset( $_GET[ 'course_id' ] ) && ( 0 < absint( $_GET[ 'course_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...
473
			$selected_lesson_course = absint( $_GET[ 'course_id' ] );
474
		} // End If Statement
475
		// Get the Lesson Posts
476
		$post_args = array(	'post_type' 		=> 'course',
477
							'posts_per_page' 		=> -1,
478
							'orderby'         	=> 'title',
479
    						'order'           	=> 'ASC',
480
    						'post_status'      	=> 'any',
481
    						'suppress_filters' 	=> 0,
482
							);
483
		$posts_array = get_posts( $post_args );
484
		// Buid the HTML to Output
485
		$html = '';
486
		// Nonce
487
		$html .= wp_nonce_field( 'sensei-save-post-meta','woo_' . $this->token . '_nonce', true, false  );
488
489
        // Select the course for the lesson
490
        $drop_down_args = array(
491
            'name'=>'lesson_course',
492
            'id' => 'lesson-course-options'
493
        );
494
495
        $courses = WooThemes_Sensei_Course::get_all_courses();
496
        $courses_options = array();
497
        foreach( $courses as $course ){
498
            $courses_options[ $course->ID ] = get_the_title( $course ) ;
499
        }
500
        $html .= WooThemes_Sensei_Utils::generate_drop_down( $selected_lesson_course, $courses_options, $drop_down_args );
501
502
        // Course Actions Panel
503
		if ( current_user_can( 'publish_courses' )) {
504
				$html .= '<div id="lesson-course-actions">';
505
					$html .= '<p>';
506
						// Add a course action link
507
						$html .= '<a id="lesson-course-add" href="#course-add" class="lesson-add-course">+ ' . __('Add New Course', 'woothemes-sensei' ) . '</a>';
508
					$html .= '</p>';
509
				$html .= '</div>';
510
				// Add a course input fields
511
				$html .= '<div id="lesson-course-details" class="hidden">';
512
					$html .= '<p>';
513
						// Course Title input
514
						$html .= '<label>' . __( 'Course Title' , 'woothemes-sensei' ) . '</label> ';
515
	  					$html .= '<input type="text" id="course-title" name="course_title" value="" size="25" class="widefat" />';
516
	  					// Course Description input
517
	  					$html .= '<label>' . __( 'Description' , 'woothemes-sensei' ) . '</label> ';
518
	  					$html .= '<textarea rows="10" cols="40" id="course-content" name="course_content" value="" size="300" class="widefat"></textarea>';
519
	  					// Course Prerequisite
520
	  					$html .= '<label>' . __( 'Course Prerequisite' , 'woothemes-sensei' ) . '</label> ';
521
	  					$html .= '<select id="course-prerequisite-options" name="course_prerequisite" class="chosen_select widefat">' . "\n";
522
							$html .= '<option value="">' . __( 'None', 'woothemes-sensei' ) . '</option>';
523
							foreach ($posts_array as $post_item){
524
								$html .= '<option value="' . esc_attr( absint( $post_item->ID ) ) . '">' . esc_html( $post_item->post_title ) . '</option>' . "\n";
525
							} // End For Loop
526
						$html .= '</select>' . "\n";
527
						// Course Product
528
	  					if ( WooThemes_Sensei_Utils::sensei_is_woocommerce_activated() ) {
529
	  						// Get the Products
530
							$select_course_woocommerce_product = get_post_meta( $post_item->ID, '_course_woocommerce_product', true );
0 ignored issues
show
Bug introduced by
The variable $post_item seems to be defined by a foreach iteration on line 523. Are you sure the iterator is never empty, otherwise this variable is not defined?

It seems like you are relying on a variable being defined by an iteration:

foreach ($a as $b) {
}

// $b is defined here only if $a has elements, for example if $a is array()
// then $b would not be defined here. To avoid that, we recommend to set a
// default value for $b.


// Better
$b = 0; // or whatever default makes sense in your context
foreach ($a as $b) {
}

// $b is now guaranteed to be defined here.
Loading history...
Unused Code introduced by
$select_course_woocommerce_product 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...
531
532
							$product_args = array(	'post_type' 		=> array( 'product', 'product_variation' ),
533
													'posts_per_page' 		=> -1,
534
													'orderby'         	=> 'title',
535
	    											'order'           	=> 'DESC',
536
	    											'post_status'		=> array( 'publish', 'private', 'draft' ),
537
	    											'tax_query'			=> array(
538
														array(
539
															'taxonomy'	=> 'product_type',
540
															'field'		=> 'slug',
541
															'terms'		=> array( 'variable', 'grouped' ),
542
															'operator'	=> 'NOT IN'
543
														)
544
													),
545
	    											'suppress_filters' 	=> 0
546
													);
547
							$products_array = get_posts( $product_args );
548
							$html .= '<label>' . __( 'WooCommerce Product' , 'woothemes-sensei' ) . '</label> ';
549
	  						$html .= '<select id="course-woocommerce-product-options" name="course_woocommerce_product" class="chosen_select widefat">' . "\n";
550
								$html .= '<option value="-">' . __( 'None', 'woothemes-sensei' ) . '</option>';
551
								$prev_parent_id = 0;
552
								foreach ($products_array as $products_item){
553
554
									if ( 'product_variation' == $products_item->post_type ) {
555
										$product_object = get_product( $products_item->ID );
556
										$parent_id = wp_get_post_parent_id( $products_item->ID );
557
										$product_name = ucwords( woocommerce_get_formatted_variation( $product_object->variation_data, true ) );
0 ignored issues
show
Unused Code introduced by
$product_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...
558
									} else {
559
										$parent_id = false;
560
										$prev_parent_id = 0;
561
										$product_name = $products_item->post_title;
0 ignored issues
show
Unused Code introduced by
$product_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...
562
									}
563
564
									// Show variations in groups
565 View Code Duplication
									if( $parent_id && $parent_id != $prev_parent_id ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
566
										if( 0 != $prev_parent_id ) {
567
											$html .= '</optgroup>';
568
										}
569
										$html .= '<optgroup label="' . get_the_title( $parent_id ) . '">';
570
										$prev_parent_id = $parent_id;
571
									} elseif( ! $parent_id && 0 == $prev_parent_id ) {
572
										$html .= '</optgroup>';
573
									}
574
575
									$html .= '<option value="' . esc_attr( absint( $products_item->ID ) ) . '">' . esc_html( $products_item->post_title ) . '</option>' . "\n";
576
								} // End For Loop
577
							$html .= '</select>' . "\n";
578
						} else {
579
							// Default
580
							$html .= '<input type="hidden" name="course_woocommerce_product" id="course-woocommerce-product-options" value="-" />';
581
						}
582
						// Course Category
583
	  					$html .= '<label>' . __( 'Course Category' , 'woothemes-sensei' ) . '</label> ';
584
	  					$cat_args = array( 'echo' => false, 'hierarchical' => true, 'show_option_none' => __( 'None', 'woothemes-sensei' ), 'taxonomy' => 'course-category', 'orderby' => 'name', 'id' => 'course-category-options', 'name' => 'course_category', 'class' => 'widefat' );
585
						$html .= wp_dropdown_categories(apply_filters('widget_course_categories_dropdown_args', $cat_args)) . "\n";
586
	  					// Save the course action button
587
	  					$html .= '<a title="' . esc_attr( __( 'Save Course', 'woothemes-sensei' ) ) . '" href="#add-course-metadata" class="lesson_course_save button button-highlighted">' . esc_html( __( 'Add Course', 'woothemes-sensei' ) ) . '</a>';
588
						$html .= '&nbsp;&nbsp;&nbsp;';
589
						// Cancel action link
590
						$html .= '<a href="#course-add-cancel" class="lesson_course_cancel">' . __( 'Cancel', 'woothemes-sensei' ) . '</a>';
591
					$html .= '</p>';
592
				$html .= '</div>';
593
			} // End If Statement
594
595
		// Output the HTML
596
		echo $html;
597
	} // End lesson_course_meta_box_content()
598
599
	public function quiz_panel( $quiz_id = 0 ) {
600
601
		$html = wp_nonce_field( 'sensei-save-post-meta','woo_' . $this->token . '_nonce', true, false  );
602
		$html .= '<div id="add-quiz-main">';
603 View Code Duplication
			if ( 0 == $quiz_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...
604
				$html .= '<p>';
605
					// Default message and Add a Quiz button
606
					$html .= esc_html( __( 'Once you have saved your lesson you will be able to add questions.', 'woothemes-sensei' ) );
607
				$html .= '</p>';
608
			}
609
610
			// Quiz Panel CSS Class
611
			$quiz_class = '';
612
			if ( 0 == $quiz_id ) {
613
				$quiz_class = ' class="hidden"';
614
			} // End If Statement
615
			// Build the HTML to Output
616
			$message_class = '';
0 ignored issues
show
Unused Code introduced by
$message_class 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...
617
618
			// Setup Questions Query
619
			$questions = array();
620
			if ( 0 < $quiz_id ) {
621
				$questions = $this->lesson_quiz_questions( $quiz_id );
622
			} // End If Statement
623
624
			$question_count = 0;
625 View Code Duplication
			foreach( $questions as $question ) {
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...
626
627
				if( $question->post_type == 'multiple_question' ) {
628
					$question_number = get_post_meta( $question->ID, 'number', true );
629
					$question_count += $question_number;
630
				} else {
631
					++$question_count;
632
				}
633
634
			}
635
636
			// Inner DIV
637
			$html .= '<div id="add-quiz-metadata"' . $quiz_class . '>';
638
639
				// Quiz ID
640
				$html .= '<input type="hidden" name="quiz_id" id="quiz_id" value="' . esc_attr( $quiz_id ) . '" />';
641
642
				// Default Message
643 View Code Duplication
				if ( 0 == $quiz_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...
644
					$html .= '<p class="save-note">';
645
						$html .= esc_html( __( 'Please save your lesson in order to add questions to your quiz.', 'woothemes-sensei' ) );
646
					$html .= '</p>';
647
				} // End If Statement
648
649
			$html .= '</div>';
650
651
			// Question Container DIV
652
			$html .= '<div id="add-question-main"' . $quiz_class . '>';
653
				// Inner DIV
654
				$html .= '<div id="add-question-metadata">';
655
656
					// Count of questions
657
					$html .= '<input type="hidden" name="question_counter" id="question_counter" value="' . esc_attr( $question_count ) . '" />';
658
					// Table headers
659
					$html .= '<table class="widefat" id="sortable-questions">
660
								<thead>
661
								    <tr>
662
								        <th class="question-count-column">#</th>
663
								        <th>' . __( 'Question', 'woothemes-sensei' ) . '</th>
664
								        <th style="width:45px;">' . __( 'Grade', 'woothemes-sensei' ) . '</th>
665
								        <th style="width:125px;">' . __( 'Type', 'woothemes-sensei' ) . '</th>
666
								        <th style="width:125px;">' . __( 'Action', 'woothemes-sensei' ) . '</th>
667
								    </tr>
668
								</thead>
669
								<tfoot>
670
								    <tr>
671
									    <th class="question-count-column">#</th>
672
									    <th>' . __( 'Question', 'woothemes-sensei' ) . '</th>
673
									    <th>' . __( 'Grade', 'woothemes-sensei' ) . '</th>
674
									    <th>' . __( 'Type', 'woothemes-sensei' ) . '</th>
675
									    <th>' . __( 'Action', 'woothemes-sensei' ) . '</th>
676
								    </tr>
677
								</tfoot>';
678
679
					$message_class = '';
680
					if ( 0 < $question_count ) { $message_class = 'hidden'; }
681
682
					$html .= '<tbody id="no-questions-message" class="' . esc_attr( $message_class ) . '">';
683
						$html .= '<tr>';
684
							$html .= '<td colspan="5">' . __( 'There are no Questions for this Quiz yet. Please add some below.', 'woothemes-sensei' ) . '</td>';
685
						$html .= '</tr>';
686
					$html .= '</tbody>';
687
688
					if( 0 < $question_count ) {
689
						$html .= $this->quiz_panel_questions( $questions );
690
					}
691
692
					$html .= '</table>';
693
694
					if( ! isset( $this->question_order ) ) {
695
						$this->question_order = '';
696
					}
697
698
					$html .= '<input type="hidden" id="question-order" name="question-order" value="' . $this->question_order . '" />';
699
700
				$html .= '</div>';
701
702
				// Question Action Container DIV
703
				$html .= '<div id="add-question-actions">';
704
705
					$html .= $this->quiz_panel_add();
706
707
				$html .= '</div>';
708
709
			$html .= '</div>';
710
711
		$html .= '</div>';
712
713
		return $html;
714
715
	}
716
717
	public function quiz_panel_questions( $questions = array() ) {
718
		global $quiz_questions;
719
720
		$quiz_questions = $questions;
721
722
		$html = '';
723
724
		if( count( $questions ) > 0 ) {
725
726
			$question_class = '';
0 ignored issues
show
Unused Code introduced by
$question_class 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...
727
			$question_counter = 1;
728
729
			foreach ( $questions as $question ) {
730
731
				$question_id = $question->ID;
732
733
				$question_type = Sensei()->question->get_question_type( $question_id );
734
735
				$multiple_data = array();
736
				$question_increment = 1;
737
				if( 'multiple_question' == $question->post_type ) {
738
					$question_type = 'category';
739
740
					$question_category = get_post_meta( $question->ID, 'category', true );
741
					$question_cat = get_term( $question_category, 'question-category' );
742
743
					$question_number = get_post_meta( $question->ID, 'number', true );
744
					$question_increment = $question_number;
745
746
					$multiple_data = array( $question_cat->name, $question_number );
747
				}
748
749
				if( ! $question_type ) {
750
					$question_type = 'multiple-choice';
751
				}
752
753
				// Row with question and actions
754
				$html .= $this->quiz_panel_question( $question_type, $question_counter, $question_id, 'quiz', $multiple_data );
755
				$question_counter += $question_increment;
756
757
				if( isset( $this->question_order ) && strlen( $this->question_order ) > 0 ) { $this->question_order .= ','; }
758
				$this->question_order .= $question_id;
759
			} // End For Loop
760
		}
761
762
		return $html;
763
764
	}
765
766
	public function quiz_panel_question( $question_type = '', $question_counter = 0, $question_id = 0, $context = 'quiz', $multiple_data = array() ) {
767
		global $row_counter,  $quiz_questions;
768
769
		$html = '';
770
771
		$question_class = '';
772
		if( 'quiz' == $context ) {
773
			if( ! $row_counter || ! isset( $row_counter ) ) {
774
				$row_counter = 1;
775
			}
776
			if( $row_counter % 2 ) { $question_class = 'alternate'; }
777
			++$row_counter;
778
		}
779
780
		if( $question_id ) {
781
782
			if( $question_type != 'category' ) {
783
784
				$question_grade = Sensei()->question->get_question_grade( $question_id );
785
786
				$question_media = get_post_meta( $question_id, '_question_media', true );
787
				$question_media_type = $question_media_thumb = $question_media_link = $question_media_title = '';
0 ignored issues
show
Unused Code introduced by
$question_media_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...
Unused Code introduced by
$question_media_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...
788
				$question_media_thumb_class = $question_media_link_class = $question_media_delete_class = 'hidden';
789
				$question_media_add_button = __( 'Add file', 'woothemes-sensei' );
790
				if( 0 < intval( $question_media ) ) {
791
					$mimetype = get_post_mime_type( $question_media );
792
					if( $mimetype ) {
793
						$mimetype_array = explode( '/', $mimetype);
794
						if( isset( $mimetype_array[0] ) && $mimetype_array[0] ) {
795
							$question_media_delete_class = '';
796
							$question_media_type = $mimetype_array[0];
797
							if( 'image' == $question_media_type ) {
798
								$question_media_thumb = wp_get_attachment_thumb_url( $question_media );
799
								if( $question_media_thumb ) {
800
									$question_media_thumb_class = '';
801
								}
802
							}
803
							$question_media_url = wp_get_attachment_url( $question_media );
804
							if( $question_media_url ) {
805
								$attachment = get_post( $question_media );
806
								$question_media_title = $attachment->post_title;
807
808
								if( ! $question_media_title ) {
809
									$question_media_filename = basename( $question_media_url );
810
									$question_media_title = $question_media_filename;
811
								}
812
								$question_media_link = '<a class="' . $question_media_type . '" href="' . esc_url( $question_media_url ) . '" target="_blank">' . $question_media_title . '</a>';
813
								$question_media_link_class = '';
814
							}
815
816
							$question_media_add_button = __( 'Change file', 'woothemes-sensei' );
817
						}
818
					}
819
				}
820
821
				$random_order = get_post_meta( $question_id, '_random_order', true );
822
				if( ! $random_order ) {
823
					$random_order = 'yes';
824
				}
825
826
				if( ! $question_type ) { $question_type = 'multiple-choice'; }
827
			}
828
829
			$html .= '<tbody class="' . $question_class . '">';
830
831
				if( 'quiz' == $context ) {
832
					$html .= '<tr>';
833
						if( $question_type != 'category' ) {
834
							$question = get_post( $question_id );
835
							$html .= '<td class="table-count question-number question-count-column"><span class="number">' . $question_counter . '</span></td>';
836
							$html .= '<td>' . esc_html( $question->post_title ) . '</td>';
837
							$html .= '<td class="question-grade-column">' . esc_html( $question_grade ) . '</td>';
0 ignored issues
show
Bug introduced by
The variable $question_grade does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
838
							$question_types_filtered = ucwords( str_replace( array( '-', 'boolean' ), array( ' ', __( 'True/False', 'woothemes-sensei' ) ), $question_type ) );
839
							$html .= '<td>' . esc_html( $question_types_filtered ) . '</td>';
840
							$html .= '<td><a title="' . esc_attr( __( 'Edit Question', 'woothemes-sensei' ) ) . '" href="#question_' . $question_counter .'" class="question_table_edit">' . esc_html( __( 'Edit', 'woothemes-sensei' ) ) . '</a> <a title="' . esc_attr( __( 'Remove Question', 'woothemes-sensei' ) ) . '" href="#add-question-metadata" class="question_table_delete">' . esc_html( __( 'Remove', 'woothemes-sensei' ) ) . '</a></td>';
841
842
						} else {
843
844
							$end_number = intval( $question_counter ) + intval( $multiple_data[1] ) - 1;
845
							if( $question_counter == $end_number ) {
846
								$row_numbers = $question_counter;
847
							} else {
848
								$row_numbers = $question_counter . ' - ' . $end_number;
849
							}
850
							$row_title = sprintf( __( 'Selected from \'%1$s\' ', 'woothemes-sensei' ), $multiple_data[0] );
851
852
							$html .= '<td class="table-count question-number question-count-column"><span class="number hidden">' . $question_counter . '</span><span class="hidden total-number">' . $multiple_data[1] . '</span><span class="row-numbers">' . esc_html( $row_numbers ) . '</span></td>';
853
							$html .= '<td>' . esc_html( $row_title ) . '</td>';
854
							$html .= '<td class="question-grade-column"></td>';
855
							$html .= '<td><input type="hidden" name="question_id" class="row_question_id" id="question_' . $question_counter . '_id" value="' . $question_id . '" /></td>';
856
							$html .= '<td><a title="' . esc_attr( __( 'Edit Question', 'woothemes-sensei' ) ) . '" href="#question_' . $question_counter .'" class="question_table_edit" style="visibility:hidden;">' . esc_html( __( 'Edit', 'woothemes-sensei' ) ) . '</a> <a title="' . esc_attr( __( 'Remove Question(s)', 'woothemes-sensei' ) ) . '" href="#add-question-metadata" class="question_multiple_delete" rel="' . $question_id . '">' . esc_html( __( 'Remove', 'woothemes-sensei' ) ) . '</a></td>';
857
858
						}
859
					$html .= '</tr>';
860
				}
861
862
				if( $question_type != 'category' ) {
863
864
					$edit_class = '';
865
					if( 'quiz' == $context ) {
866
						$edit_class = 'hidden';
867
					}
868
869
					$question = get_post( $question_id );
870
					$html .= '<tr class="question-quick-edit ' . esc_attr( $edit_class ) . '">';
871
						$html .= '<td colspan="5">';
872
							$html .= '<span class="hidden question_original_counter">' . $question_counter . '</span>';
873
					    	$html .= '<div class="question_required_fields">';
874
875
						    	// Question title
876
						    	$html .= '<div>';
877
							    	$html .= '<label for="question_' . $question_counter . '">' . __( 'Question:', 'woothemes-sensei' ) . '</label> ';
878
							    	$html .= '<input type="text" id="question_' . $question_counter . '" name="question" value="' . esc_attr( htmlspecialchars( $question->post_title ) ) . '" size="25" class="widefat" />';
879
						    	$html .= '</div>';
880
881
						    	// Question description
882
						    	$html .= '<div>';
883
							    	$html .= '<label for="question_' . $question_counter . '_desc">' . __( 'Question Description (optional):', 'woothemes-sensei' ) . '</label> ';
884
						    	$html .= '</div>';
885
							    	$html .= '<textarea id="question_' . $question_counter . '_desc" name="question_description" class="widefat" rows="4">' . esc_textarea( $question->post_content ) . '</textarea>';
886
887
						    	// Question grade
888
						    	$html .= '<div>';
889
							    	$html .= '<label for="question_' . $question_counter . '_grade">' . __( 'Question grade:', 'woothemes-sensei' ) . '</label> ';
890
							    	$html .= '<input type="number" id="question_' . $question_counter . '_grade" class="question_grade small-text" name="question_grade" min="0" value="' . $question_grade . '" />';
891
						    	$html .= '</div>';
892
893
						    	// Random order
894
						    	if( $question_type == 'multiple-choice' ) {
895
						    		$html .= '<div>';
896
						    			$html .= '<label for="' . $question_counter . '_random_order"><input type="checkbox" name="random_order" class="random_order" id="' . $question_counter . '_random_order" value="yes" ' . checked( $random_order, 'yes', false ) . ' /> ' . __( 'Randomise answer order', 'woothemes-sensei' ) . '</label>';
0 ignored issues
show
Bug introduced by
The variable $random_order does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
897
						    		$html .= '</div>';
898
						    	}
899
900
						    	// Question media
901
						    	$html .= '<div>';
902
							    	$html .= '<label for="question_' . $question_counter . '_media_button">' . __( 'Question media:', 'woothemes-sensei' ) . '</label><br/>';
903
							    	$html .= '<button id="question_' . $question_counter . '_media_button" class="upload_media_file_button button-secondary" data-uploader_title="' . __( 'Add file to question', 'woothemes-sensei' ) . '" data-uploader_button_text="' . __( 'Add to question', 'woothemes-sensei' ) . '">' . $question_media_add_button . '</button>';
0 ignored issues
show
Bug introduced by
The variable $question_media_add_button does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
904
							    	$html .= '<button id="question_' . $question_counter . '_media_button_delete" class="delete_media_file_button button-secondary ' . $question_media_delete_class . '">' . __( 'Delete file', 'woothemes-sensei' ) . '</button><br/>';
0 ignored issues
show
Bug introduced by
The variable $question_media_delete_class does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
905
							    	$html .= '<span id="question_' . $question_counter . '_media_link" class="question_media_link ' . $question_media_link_class . '">' . $question_media_link . '</span>';
0 ignored issues
show
Bug introduced by
The variable $question_media_link_class does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

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

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
906
							    	$html .= '<br/><img id="question_' . $question_counter . '_media_preview" class="question_media_preview ' . $question_media_thumb_class . '" src="' . $question_media_thumb . '" /><br/>';
0 ignored issues
show
Bug introduced by
The variable $question_media_thumb_class does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

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

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
907
							    	$html .= '<input type="hidden" id="question_' . $question_counter . '_media" class="question_media" name="question_media" value="' . $question_media . '" />';
0 ignored issues
show
Bug introduced by
The variable $question_media does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
908
						    	$html .= '</div>';
909
910
						    $html .= '</div>';
911
912
						    $html .= $this->quiz_panel_question_field( $question_type, $question_id, $question_counter );
913
914
						    $html .= '<input type="hidden" id="question_' . $question_counter . '_question_type" class="question_type" name="question_type" value="' . $question_type . '" />';
915
							$html .= '<input type="hidden" name="question_id" class="row_question_id" id="question_' . $question_counter . '_id" value="' . $question_id . '" />';
916
917
							if( 'quiz' == $context ) {
918
					    		$html .= '<div class="update-question">';
919
						    		$html .= '<a href="#question-edit-cancel" class="lesson_question_cancel" title="' . esc_attr( __( 'Cancel', 'woothemes-sensei' ) ) . '">' . __( 'Cancel', 'woothemes-sensei' ) . '</a> ';
920
						    		$html .= '<a title="' . esc_attr( __( 'Update Question', 'woothemes-sensei' ) ) . '" href="#add-question-metadata" class="question_table_save button button-highlighted">' . esc_html( __( 'Update', 'woothemes-sensei' ) ) . '</a>';
921
					    		$html .= '</div>';
922
					    	}
923
924
			    		$html .= '</td>';
925
					$html .= '</tr>';
926
				}
927
928
			$html .= '</tbody>';
929
930
		}
931
932
		return $html;
933
	}
934
935
	public function quiz_panel_add( $context = 'quiz' ) {
936
937
938
		$html = '<div id="add-new-question">';
939
940
			$question_types = Sensei()->question->question_types();
941
942
			$question_cats = get_terms( 'question-category', array( 'hide_empty' => false ) );
943
944
			if( 'quiz' == $context ) {
945
	    		$html .= '<h2 class="nav-tab-wrapper add-question-tabs">';
946
	    			$html .= '<a id="tab-new" class="nav-tab nav-tab-active">' . __( 'New Question'  , 'woothemes-sensei' ) . '</a>';
947
	    			$html .= '<a id="tab-existing" class="nav-tab">' . __( 'Existing Questions'  , 'woothemes-sensei' ) . '</a>';
948
                    if ( ! empty( $question_cats ) && ! is_wp_error( $question_cats )  && ! Sensei()->teacher->is_admin_teacher() ) {
949
	    				$html .= '<a id="tab-multiple" class="nav-tab">' . __( 'Category Questions'  , 'woothemes-sensei' ) . '</a>';
950
	    			}
951
	    		$html .= '</h2>';
952
	    	}
953
954
	    	$html .= '<div class="tab-content" id="tab-new-content">';
955
956
	    		if( 'quiz' == $context ) {
957
	    			$html .= '<p><em>' . sprintf( __( 'Add a new question to this quiz - your question will also be added to the %1$squestion bank%2$s.', 'woothemes-sensei' ), '<a href="' . admin_url( 'edit.php?post_type=question' ) . '">', '</a>' ) . '</em></p>';
958
	    		}
959
960
				$html .= '<div class="question">';
961
					$html .= '<div class="question_required_fields">';
962
963
						// Question title
964
						$html .= '<p><label>' . __( 'Question:'  , 'woothemes-sensei' ) . '</label> ';
965
	  					$html .= '<input type="text" id="add_question" name="question" value="" size="25" class="widefat" /></p>';
966
967
						// Question description
968
						$html .= '<p>';
969
							$html .= '<label for="question_desc">' . __( 'Question Description (optional):', 'woothemes-sensei' ) . '</label> ';
970
						$html .= '</p>';
971
						$html .= '<textarea id="question_desc" name="question_description" class="widefat" rows="4"></textarea>';
972
973
	  					// Question type
974
						$html .= '<p><label>' . __( 'Question Type:' , 'woothemes-sensei' ) . '</label> ';
975
						$html .= '<select id="add-question-type-options" name="question_type" class="chosen_select widefat question-type-select">' . "\n";
976 View Code Duplication
							foreach ( $question_types as $type => $label ) {
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...
977
								$html .= '<option value="' . esc_attr( $type ) . '">' . esc_html( $label ) . '</option>' . "\n";
978
							} // End For Loop
979
						$html .= '</select></p>' . "\n";
980
981
						// Question category
982
						if( 'quiz' == $context ) {
983
							if ( ! empty( $question_cats ) && ! is_wp_error( $question_cats ) ) {
984
								$html .= '<p><label>' . __( 'Question Category:' , 'woothemes-sensei' ) . '</label> ';
985
								$html .= '<select id="add-question-category-options" name="question_category" class="chosen_select widefat question-category-select">' . "\n";
986
								$html .= '<option value="">' . __( 'None', 'woothemes-sensei' ) . '</option>' . "\n";
987 View Code Duplication
								foreach( $question_cats as $cat ) {
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...
988
									$html .= '<option value="' . esc_attr( $cat->term_id ) . '">' . esc_html( $cat->name ) . '</option>';
989
								} // End For Loop
990
								$html .= '</select></p>' . "\n";
991
							}
992
						}
993
994
	  					// Question grade
995
						$html .= '<p><label>' . __( 'Question Grade:'  , 'woothemes-sensei' ) . '</label> ';
996
						$html .= '<input type="number" id="add-question-grade" name="question_grade" class="small-text" min="0" value="1" /></p>' . "\n";
997
998
						// Random order
999
						$html .= '<p class="add_question_random_order">';
1000
			    			$html .= '<label for="add_random_order"><input type="checkbox" name="random_order" class="random_order" id="add_random_order" value="yes" checked="checked" /> ' . __( 'Randomise answer order', 'woothemes-sensei' ) . '</label>';
1001
			    		$html .= '</p>';
1002
1003
			    		// Question media
1004
						$html .= '<p>';
1005
					    	$html .= '<label for="question_add_new_media_button">' . __( 'Question media:', 'woothemes-sensei' ) . '</label><br/>';
1006
					    	$html .= '<button id="question_add_new_media_button" class="upload_media_file_button button-secondary" data-uploader_title="' . __( 'Add file to question', 'woothemes-sensei' ) . '" data-uploader_button_text="' . __( 'Add to question', 'woothemes-sensei' ) . '">' . __( 'Add file', 'woothemes-sensei' ) . '</button>';
1007
					    	$html .= '<button id="question_add_new_media_button_delete" class="delete_media_file_button button-secondary hidden">' . __( 'Delete file', 'woothemes-sensei' ) . '</button><br/>';
1008
					    	$html .= '<span id="question_add_new_media_link" class="question_media_link hidden"></span>';
1009
					    	$html .= '<br/><img id="question_add_new_media_preview" class="question_media_preview hidden" src="" /><br/>';
1010
					    	$html .= '<input type="hidden" id="question_add_new_media" class="question_media" name="question_media" value="" />';
1011
				    	$html .= '</p>';
1012
1013
					$html .= '</div>';
1014
				$html .= '</div>';
1015
1016
				foreach ( $question_types as $type => $label ) {
1017
					$html .= $this->quiz_panel_question_field( $type );
1018
				}
1019
1020
				if( 'quiz' == $context ) {
1021
					$html .= '<div class="add-question">';
1022
			    		$html .= '<a title="' . esc_attr( __( 'Add Question', 'woothemes-sensei' ) ) . '" href="#add-question-metadata" class="add_question_save button button-primary button-highlighted">' . esc_html( __( 'Add Question', 'woothemes-sensei' ) ) . '</a>';
1023
		    		$html .= '</div>';
1024
		    	}
1025
1026
		    $html .= '</div>';
1027
1028
		    if( 'quiz' == $context ) {
1029
1030
			    $html .= '<div class="tab-content hidden" id="tab-existing-content">';
1031
1032
			    	$html .= '<p><em>' . sprintf( __( 'Add an existing question to this quiz from the %1$squestion bank%2$s.', 'woothemes-sensei' ), '<a href="' . admin_url( 'edit.php?post_type=question' ) . '">', '</a>' ) . '</em></p>';
1033
1034
			    	$html .= '<div id="existing-filters" class="alignleft actions">
1035
			    				<select id="existing-status">
1036
			    					<option value="all">' . __( 'All', 'woothemes-sensei' ) . '</option>
1037
			    					<option value="unused">' . __( 'Unused', 'woothemes-sensei' ) . '</option>
1038
			    					<option value="used">' . __( 'Used', 'woothemes-sensei' ) . '</option>
1039
			    				</select>
1040
			    				<select id="existing-type">
1041
			    					<option value="">' . __( 'All Types', 'woothemes-sensei' ) . '</option>';
1042 View Code Duplication
							    	foreach ( $question_types as $type => $label ) {
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...
1043
										$html .= '<option value="' . esc_attr( $type ) . '">' . esc_html( $label ) . '</option>';
1044
									}
1045
    				$html .= '</select>
1046
    							<select id="existing-category">
1047
			    					<option value="">' . __( 'All Categories', 'woothemes-sensei' ) . '</option>';
1048 View Code Duplication
				    				foreach( $question_cats as $cat ) {
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...
1049
										$html .= '<option value="' . esc_attr( $cat->slug ) . '">' . esc_html( $cat->name ) . '</option>';
1050
									}
1051
    				$html .= '</select>
1052
    							<input type="text" id="existing-search" placeholder="' . __( 'Search', 'woothemes-sensei' ) . '" />
1053
    							<a class="button" id="existing-filter-button">' . __( 'Filter', 'woothemes-sensei' ) . '</a>
1054
			    			</div>';
1055
1056
			    	$html .= '<table id="existing-table" class="widefat">';
1057
1058
			    		$html .= '<thead>
1059
									    <tr>
1060
									        <th scope="col" class="column-cb check-column"><input type="checkbox" /></th>
1061
									        <th scope="col">' . __( 'Question', 'woothemes-sensei' ) . '</th>
1062
									        <th scope="col">' . __( 'Type', 'woothemes-sensei' ) . '</th>
1063
									        <th scope="col">' . __( 'Category', 'woothemes-sensei' ) . '</th>
1064
									    </tr>
1065
									</thead>
1066
									<tfoot>
1067
									    <tr>
1068
										    <th scope="col" class="check-column"><input type="checkbox" /></th>
1069
									        <th scope="col">' . __( 'Question', 'woothemes-sensei' ) . '</th>
1070
									        <th scope="col">' . __( 'Type', 'woothemes-sensei' ) . '</th>
1071
									        <th scope="col">' . __( 'Category', 'woothemes-sensei' ) . '</th>
1072
									    </tr>
1073
									</tfoot>';
1074
						$html .= '<tbody id="existing-questions">';
1075
1076
						$questions = $this->quiz_panel_get_existing_questions();
1077
1078
						$row = 1;
1079
						foreach( $questions['questions'] as $question ) {
1080
							$html .= $this->quiz_panel_add_existing_question( $question->ID, $row );
1081
							++$row;
1082
						}
1083
1084
						$html .= '</tbody>';
1085
1086
			    	$html .= '</table>';
1087
1088
			    	$next_class = '';
1089
			    	if( $questions['count'] <= 10 ) {
1090
			    		$next_class = 'hidden';
1091
			    	}
1092
1093
			    	$html .= '<div id="existing-pagination">';
1094
			    		$html .= '<input type="hidden" id="existing-page" value="1" />';
1095
			    		$html .= '<a class="prev no-paging">&larr; ' . __( 'Previous', 'woothemes-sensei') . '</a> <a class="next ' . esc_attr( $next_class ) . '">' . __( 'Next', 'woothemes-sensei') . ' &rarr;</a>';
1096
			    	$html .= '</div>';
1097
1098
			    	$html .= '<div class="existing-actions">';
1099
			    		$html .= '<a title="' . esc_attr( __( 'Add Selected Question(s)', 'woothemes-sensei' ) ) . '" class="add_existing_save button button-primary button-highlighted">' . esc_html( __( 'Add Selected Question(s)', 'woothemes-sensei' ) ) . '</a></p>';
1100
			    	$html .= '</div>';
1101
1102
			    $html .= '</div>';
1103
1104
			    if ( ! empty( $question_cats ) && ! is_wp_error( $question_cats ) ) {
1105
				    $html .= '<div class="tab-content hidden" id="tab-multiple-content">';
1106
1107
				    	$html .= '<p><em>' . sprintf( __( 'Add any number of questions from a specified category. Edit your question categories %1$shere%2$s.', 'woothemes-sensei' ), '<a href="' . admin_url( 'edit-tags.php?taxonomy=question-category&post_type=question' ) . '">', '</a>' ) . '</em></p>';
1108
1109
						$html .= '<p><select id="add-multiple-question-category-options" name="multiple_category" class="chosen_select widefat question-category-select">' . "\n";
1110
						$html .= '<option value="">' . __( 'Select a Question Category', 'woothemes-sensei' ) . '</option>' . "\n";
1111 View Code Duplication
						foreach( $question_cats as $cat ) {
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...
1112
							$html .= '<option value="' . esc_attr( $cat->term_id ) . '">' . esc_html( $cat->name ) . '</option>';
1113
						} // End For Loop
1114
						$html .= '</select></p>' . "\n";
1115
1116
						$html .= '<p>' . __( 'Number of questions:', 'woothemes-sensei' ) . ' <input type="number" min="1" value="1" max="1" id="add-multiple-question-count" class="small-text"/>';
1117
1118
						$html .= '<a title="' . esc_attr( __( 'Add Question(s)', 'woothemes-sensei' ) ) . '" class="add_multiple_save button button-primary button-highlighted">' . esc_html( __( 'Add Question(s)', 'woothemes-sensei' ) ) . '</a></p>';
1119
1120
				    $html .= '</div>';
1121
				}
1122
			}
1123
1124
		$html .= '</div>';
1125
1126
		return $html;
1127
	}
1128
1129
	public function quiz_panel_get_existing_questions( $question_status = 'all', $question_type = '', $question_category = '', $question_search = '', $page = 1 ) {
1130
1131
		$args = array(
1132
			'post_type' => 'question',
1133
			'posts_per_page' => 10,
1134
			'post_status' => 'publish',
1135
			'suppress_filters' => 0,
1136
		);
1137
1138
		switch( $question_status ) {
1139
			case 'unused': $quiz_status = 'NOT EXISTS'; break;
1140
			case 'used': $quiz_status = 'EXISTS'; break;
1141
			default: $quiz_status = ''; break;
1142
		}
1143
1144
		if( $quiz_status ) {
1145
			switch( $quiz_status ) {
1146
				case 'EXISTS':
1147
					$args['meta_query'][] = array(
1148
						'key' => '_quiz_id',
1149
						'compare' => $quiz_status,
1150
					);
1151
				break;
1152
1153
				case 'NOT EXISTS':
1154
					$args['meta_query'][] = array(
1155
						'key' => '_quiz_id',
1156
						'value' => 'bug #23268',
1157
						'compare' => $quiz_status,
1158
					);
1159
				break;
1160
			}
1161
		}
1162
1163 View Code Duplication
		if( $question_type ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1164
			$args['tax_query'][] = array(
1165
				'taxonomy' => 'question-type',
1166
				'field' => 'slug',
1167
				'terms' => $question_type,
1168
			);
1169
		}
1170
1171 View Code Duplication
		if( $question_category ) {
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...
1172
			$args['tax_query'][] = array(
1173
				'taxonomy' => 'question-category',
1174
				'field' => 'slug',
1175
				'terms' => $question_category,
1176
			);
1177
		}
1178
1179
		if( $question_type && $question_category ) {
1180
			$args['tax_query']['relation'] = 'AND';
1181
		}
1182
1183
		if( $question_search ) {
1184
			$args['s'] = $question_search;
1185
		}
1186
1187
		if( $page ) {
1188
			$args['paged'] = $page;
1189
		}
1190
1191
		$qry = new WP_Query( $args );
1192
1193
        /**
1194
         * Filter existing questions query
1195
         *
1196
         * @since 1.8.0
1197
         *
1198
         * @param WP_Query $wp_query
1199
         */
1200
        $qry = apply_filters( 'sensei_existing_questions_query_results', $qry );
1201
1202
		$questions['questions'] = $qry->posts;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$questions was never initialized. Although not strictly required by PHP, it is generally a good practice to add $questions = array(); before regardless.

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

Let’s take a look at an example:

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

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

    // do something with $myArray
}

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

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

Loading history...
1203
		$questions['count'] = intval( $qry->found_posts );
1204
		$questions['page'] = $page;
1205
1206
		return $questions;
1207
	}
1208
1209
	public function quiz_panel_add_existing_question( $question_id = 0, $row = 1 ) {
1210
1211
		$html = '';
1212
1213
		if( ! $question_id ) {
1214
1215
            return;
1216
1217
        }
1218
1219
		$existing_class = '';
1220
		if( $row % 2 ) {
1221
            $existing_class = 'alternate';
1222
        }
1223
1224
		$question_type = Sensei()->question->get_question_type( $question_id );
1225
1226
		$question_cat_list = strip_tags( get_the_term_list( $question_id, 'question-category', '', ', ', '' ) );
1227
1228
		$html .= '<tr class="' . esc_attr( $existing_class ) . '">
1229
					<td class="cb"><input type="checkbox" value="' . $question_id . '" class="existing-item" /></td>
1230
					<td>' . get_the_title( $question_id ) . '</td>
1231
					<td>' . esc_html( $question_type ) . '</td>
1232
					<td>' . esc_html( $question_cat_list ) . '</td>
1233
				  </tr>';
1234
1235
		return $html;
1236
1237
	}
1238
1239
	public function quiz_panel_filter_existing_questions() {
1240
1241
		$return = '';
1242
1243
		//Add nonce security to the request
1244
		$nonce = '';
1245
		if( isset( $_POST['filter_existing_questions_nonce'] ) ) {
1246
			$nonce = esc_html( $_POST['filter_existing_questions_nonce'] );
1247
		} // End If Statement
1248
1249
		if( ! wp_verify_nonce( $nonce, 'filter_existing_questions_nonce' ) ) {
1250
			die( $return );
1251
		} // End If Statement
1252
1253
		// Parse POST data
1254
		$data = $_POST['data'];
1255
		$question_data = array();
1256
		parse_str( $data, $question_data );
1257
1258
		if( 0 < count( $question_data ) ) {
1259
1260
			$question_status = '';
1261
			if( isset( $question_data['question_status'] ) ) {
1262
				$question_status = $question_data['question_status'];
1263
			}
1264
1265
			$question_type = '';
1266
			if( isset( $question_data['question_type'] ) ) {
1267
				$question_type = $question_data['question_type'];
1268
			}
1269
1270
			$question_category = '';
1271
			if( isset( $question_data['question_category'] ) ) {
1272
				$question_category = $question_data['question_category'];
1273
			}
1274
1275
			$question_search = '';
1276
			if( isset( $question_data['question_search'] ) ) {
1277
				$question_search = $question_data['question_search'];
1278
			}
1279
1280
			$question_page = 1;
1281
			if( isset( $question_data['question_page'] ) ) {
1282
				$question_page = intval( $question_data['question_page'] );
1283
			}
1284
1285
			$questions = $this->quiz_panel_get_existing_questions( $question_status, $question_type, $question_category, $question_search, $question_page );
1286
1287
			$row = 1;
1288
			$html = '';
1289
			foreach( $questions['questions'] as $question ) {
1290
				$html .= $this->quiz_panel_add_existing_question( $question->ID, $row );
1291
				++$row;
1292
			}
1293
1294
			if( ! $html ) {
1295
				$html = '<tr class="alternate">
1296
								<td class="no-results" colspan="4"><em>' . __( 'There are no questions matching your search.', 'woothemes-sensei' ) . '</em></td>
1297
							  </tr>';
1298
			}
1299
1300
			$return['html'] = $html;
1301
			$return['count'] = $questions['count'];
1302
			$return['page'] = $questions['page'];
1303
1304
			wp_send_json( $return );
1305
		}
1306
1307
		die( $return );
1308
	}
1309
1310
	public function quiz_panel_question_field( $question_type = '', $question_id = 0, $question_counter = 0 ) {
1311
1312
		$html = '';
1313
1314
		if( $question_type ) {
1315
1316
			$right_answer = '';
1317
			$wrong_answers = array();
1318
			$answer_order_string = '';
1319
			$answer_order = array();
1320
			if( $question_id ) {
1321
				$right_answer = get_post_meta( $question_id, '_question_right_answer', true);
1322
				$wrong_answers = get_post_meta( $question_id, '_question_wrong_answers', true);
1323
				$answer_order_string = get_post_meta( $question_id, '_answer_order', true );
1324
				$answer_order = array_filter( explode( ',', $answer_order_string ) );
1325
				$question_class = '';
1326
			} else {
1327
				$question_id = '';
1328
				$question_class = 'answer-fields question_required_fields hidden';
1329
			}
1330
1331
			switch ( $question_type ) {
1332
				case 'multiple-choice':
1333
					$html .= '<div class="question_default_fields multiple-choice-answers ' . str_replace( ' hidden', '', $question_class ) . '">';
1334
1335
						$right_answers = (array) $right_answer;
1336
						// Calculate total right answers available (defaults to 1)
1337
						$total_right = 0;
1338
						if( $question_id ) {
1339
							$total_right = get_post_meta( $question_id, '_right_answer_count', true );
1340
						}
1341
						if( 0 == intval( $total_right ) ) {
1342
							$total_right = 1;
1343
						}
1344
						for ( $i = 0; $i < $total_right; $i++ ) {
1345
							if ( !isset( $right_answers[ $i ] ) ) { $right_answers[ $i ] = ''; }
1346
							$right_answer_id = $this->get_answer_id( $right_answers[ $i ] );
1347
							// Right Answer
1348
							$right_answer = '<label class="answer" for="question_' . $question_counter . '_right_answer_' . $i . '"><span>' . __( 'Right:' , 'woothemes-sensei' ) . '</span> <input rel="' . esc_attr( $right_answer_id ) . '" type="text" id="question_' . $question_counter . '_right_answer_' . $i . '" name="question_right_answers[]" value="' . esc_attr( $right_answers[ $i ] ) . '" size="25" class="question_answer widefat" /> <a class="remove_answer_option"></a></label>';
1349
							if( $question_id ) {
1350
								$answers[ $right_answer_id ] = $right_answer;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$answers was never initialized. Although not strictly required by PHP, it is generally a good practice to add $answers = array(); before regardless.

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

Let’s take a look at an example:

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

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

    // do something with $myArray
}

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

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

Loading history...
1351
							} else {
1352
								$answers[] = $right_answer;
0 ignored issues
show
Bug introduced by
The variable $answers does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1353
							}
1354
						}
1355
1356
				    	// Calculate total wrong answers available (defaults to 4)
1357
				    	$total_wrong = 0;
1358
				    	if( $question_id ) {
1359
				    		$total_wrong = get_post_meta( $question_id, '_wrong_answer_count', true );
1360
				    	}
1361
				    	if( 0 == intval( $total_wrong ) ) {
1362
				    		$total_wrong = 1;
1363
				    	}
1364
1365
                        // Setup Wrong Answer HTML
1366
                        foreach ( $wrong_answers as $i => $answer ){
1367
1368
                            $answer_id = $this->get_answer_id( $answer );
1369
                            $wrong_answer = '<label class="answer" for="question_' . $question_counter . '_wrong_answer_' . $i . '"><span>' . __( 'Wrong:' , 'woothemes-sensei' ) ;
1370
                            $wrong_answer .= '</span> <input rel="' . esc_attr( $answer_id ) . '" type="text" id="question_' . $question_counter . '_wrong_answer_' . $i ;
1371
                            $wrong_answer .= '" name="question_wrong_answers[]" value="' . esc_attr( $answer ) . '" size="25" class="question_answer widefat" /> <a class="remove_answer_option"></a></label>';
1372
                            if( $question_id ) {
1373
1374
                                $answers[ $answer_id ] = $wrong_answer;
1375
1376
                            } else {
1377
1378
                                $answers[] = $wrong_answer;
1379
1380
                            }
1381
1382
                        } // end for each
1383
1384
				    	$answers_sorted = $answers;
1385 View Code Duplication
				    	if( $question_id && count( $answer_order ) > 0 ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1386
				    		$answers_sorted = array();
1387
				    		foreach( $answer_order as $answer_id ) {
1388
				    			if( isset( $answers[ $answer_id ] ) ) {
1389
				    				$answers_sorted[ $answer_id ] = $answers[ $answer_id ];
1390
				    				unset( $answers[ $answer_id ] );
1391
				    			}
1392
				    		}
1393
1394
				    		if( count( $answers ) > 0 ) {
1395
						    	foreach( $answers as $id => $answer ) {
1396
						    		$answers_sorted[ $id ] = $answer;
1397
						    	}
1398
						    }
1399
				    	}
1400
1401
						foreach( $answers_sorted as $id => $answer ) {
1402
				    		$html .= $answer;
1403
				    	}
1404
1405
				    	$html .= '<input type="hidden" class="answer_order" name="answer_order" value="' . $answer_order_string . '" />';
1406
				    	$html .= '<span class="hidden right_answer_count">' . $total_right . '</span>';
1407
				    	$html .= '<span class="hidden wrong_answer_count">' . $total_wrong . '</span>';
1408
1409
				    	$html .= '<div class="add_answer_options">';
1410
					    	$html .= '<a class="add_right_answer_option add_answer_option button" rel="' . $question_counter . '">' . __( 'Add right answer', 'woothemes-sensei' ) . '</a>';
1411
					    	$html .= '<a class="add_wrong_answer_option add_answer_option button" rel="' . $question_counter . '">' . __( 'Add wrong answer', 'woothemes-sensei' ) . '</a>';
1412
				    	$html .= '</div>';
1413
1414
                        $html .= $this->quiz_panel_question_feedback( $question_counter, $question_id , 'multiple-choice' );
1415
1416
			    	$html .= '</div>';
1417
				break;
1418
				case 'boolean':
1419
					$html .= '<div class="question_boolean_fields ' . $question_class . '">';
1420
						if( $question_id ) {
1421
							$field_name = 'question_' . $question_id . '_right_answer_boolean';
1422
						} else {
1423
							$field_name = 'question_right_answer_boolean';
1424
							$right_answer = 'true';
1425
						}
1426
						$html .= '<label for="question_' . $question_id . '_boolean_true"><input id="question_' . $question_id . '_boolean_true" type="radio" name="' . $field_name . '" value="true" '. checked( $right_answer, 'true', false ) . ' /> ' . __( 'True', 'woothemes-sensei' ) . '</label>';
1427
						$html .= '<label for="question_' . $question_id . '_boolean_false"><input id="question_' . $question_id . '_boolean_false" type="radio" name="' . $field_name . '" value="false" '. checked( $right_answer, 'false', false ) . ' /> ' . __( 'False', 'woothemes-sensei' ) . '</label>';
1428
1429
                    $html .= $this->quiz_panel_question_feedback( $question_counter, $question_id, 'boolean' );
1430
1431
					$html .= '</div>';
1432
				break;
1433
				case 'gap-fill':
1434
					$gapfill_array = explode( '||', $right_answer );
1435
					if ( isset( $gapfill_array[0] ) ) { $gapfill_pre = $gapfill_array[0]; } else { $gapfill_pre = ''; }
1436
					if ( isset( $gapfill_array[1] ) ) { $gapfill_gap = $gapfill_array[1]; } else { $gapfill_gap = ''; }
1437
					if ( isset( $gapfill_array[2] ) ) { $gapfill_post = $gapfill_array[2]; } else { $gapfill_post = ''; }
1438
					$html .= '<div class="question_gapfill_fields ' . $question_class . '">';
1439
						// Fill in the Gaps
1440
						$html .= '<label>' . __( 'Text before the Gap:' , 'woothemes-sensei' ) . '</label> ';
1441
						$html .= '<input type="text" id="question_' . $question_counter . '_add_question_right_answer_gapfill_pre" name="add_question_right_answer_gapfill_pre" value="' . $gapfill_pre . '" size="25" class="widefat gapfill-field" />';
1442
	  					$html .= '<label>' . __( 'The Gap:' , 'woothemes-sensei' ) . '</label> ';
1443
	  					$html .= '<input type="text" id="question_' . $question_counter . '_add_question_right_answer_gapfill_gap" name="add_question_right_answer_gapfill_gap" value="' . $gapfill_gap . '" size="25" class="widefat gapfill-field" />';
1444
	  					$html .= '<label>' . __( 'Text after the Gap:' , 'woothemes-sensei' ) . '</label> ';
1445
	  					$html .= '<input type="text" id="question_' . $question_counter . '_add_question_right_answer_gapfill_post" name="add_question_right_answer_gapfill_post" value="' . $gapfill_post . '" size="25" class="widefat gapfill-field" />';
1446
	  					$html .= '<label>' . __( 'Preview:' , 'woothemes-sensei' ) . '</label> ';
1447
	  					$html .= '<p class="gapfill-preview">' . $gapfill_pre . '&nbsp;<u>' . $gapfill_gap . '</u>&nbsp;' . $gapfill_post . '</p>';
1448
	  				$html .= '</div>';
1449
				break;
1450 View Code Duplication
				case 'multi-line':
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...
1451
					$html .= '<div class="question_multiline_fields ' . $question_class . '">';
1452
						// Guides for grading
1453
						if( $question_counter ) {
1454
							$field_id = 'question_' . $question_counter . '_add_question_right_answer_multiline';
1455
						} else {
1456
							$field_id = 'add_question_right_answer_multiline';
1457
						}
1458
						$html .= '<label>' . __( 'Guide/Teacher Notes for grading the answer' , 'woothemes-sensei' ) . '</label> ';
1459
						$html .= '<textarea id="' . $field_id . '" name="add_question_right_answer_multiline" rows="4" cols="40" class="widefat">' . $right_answer . '</textarea>';
1460
					$html .= '</div>';
1461
				break;
1462 View Code Duplication
				case 'single-line':
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...
1463
					$html .= '<div class="question_singleline_fields ' . $question_class . '">';
1464
						// Recommended Answer
1465
						if( $question_counter ) {
1466
							$field_id = 'question_' . $question_counter . '_add_question_right_answer_singleline';
1467
						} else {
1468
							$field_id = 'add_question_right_answer_singleline';
1469
						}
1470
						$html .= '<label>' . __( 'Recommended Answer' , 'woothemes-sensei' ) . '</label> ';
1471
						$html .= '<input type="text" id="' . $field_id . '" name="add_question_right_answer_singleline" value="' . $right_answer . '" size="25" class="widefat" />';
1472
					$html .= '</div>';
1473
				break;
1474
				case 'file-upload':
1475
					$html .= '<div class="question_fileupload_fields ' . $question_class . '">';
1476
						if( $question_counter ) {
1477
							$right_field_id = 'question_' . $question_counter . '_add_question_right_answer_fileupload';
1478
							$wrong_field_id = 'question_' . $question_counter . '_add_question_wrong_answer_fileupload';
1479
						} else {
1480
							$right_field_id = 'add_question_right_answer_fileupload';
1481
							$wrong_field_id = 'add_question_wrong_answer_fileupload';
1482
						}
1483
1484
						$wrong_answer = '';
1485
						if( isset( $wrong_answers[0] ) ) {
1486
							$wrong_answer = $wrong_answers[0];
1487
						}
1488
						$html .= '<label>' . __( 'Description for student explaining what needs to be uploaded' , 'woothemes-sensei' ) . '</label> ';
1489
						$html .= '<textarea id="' . $wrong_field_id . '" name="add_question_wrong_answer_fileupload" rows="4" cols="40" class="widefat">' . $wrong_answer . '</textarea>';
1490
1491
						// Guides for grading
1492
						$html .= '<label>' . __( 'Guide/Teacher Notes for grading the upload' , 'woothemes-sensei' ) . '</label> ';
1493
						$html .= '<textarea id="' . $right_field_id . '" name="add_question_right_answer_fileupload" rows="4" cols="40" class="widefat">' . $right_answer . '</textarea>';
1494
					$html .= '</div>';
1495
				break;
1496
			}
1497
		}
1498
1499
		return $html;
1500
	}
1501
1502
	public function quiz_panel_question_feedback( $question_counter = 0, $question_id = 0, $question_type = '' ) {
1503
1504
        // default field name
1505
        $field_name = 'answer_feedback';
1506
        if( 'boolean' == $question_type ){
1507
1508
            $field_name = 'answer_feedback_boolean';
1509
1510
        }elseif( 'multiple-choice' == $question_type ){
1511
1512
            $field_name = 'answer_feedback_multiple_choice';
1513
1514
        }// end if
1515
1516
		if( $question_counter ) {
1517
			$field_name = 'answer_' . $question_counter . '_feedback';
1518
		}
1519
1520
		$feedback = '';
1521
		if( $question_id ) {
1522
			$feedback = get_post_meta( $question_id, '_answer_feedback', true );
1523
		}
1524
1525
		$html = '<p title="' . __( 'This feedback will be automatically displayed to the student once they have completed the quiz.', 'woothemes-sensei' ) . '">';
1526
		$html .= '<label for="' . $field_name . '">' . __( 'Answer Feedback' , 'woothemes-sensei' ) . ':</label>';
1527
		$html .= '<textarea id="' . $field_name . '" name="' . $field_name . '" rows="4" cols="40" class="answer_feedback widefat">' . $feedback . '</textarea>';
1528
		$html .= '</p>';
1529
1530
		return $html;
1531
	}
1532
1533
	public function question_get_answer_id() {
1534
		$data = $_POST['data'];
1535
		$answer_data = array();
1536
		parse_str( $data, $answer_data );
1537
		$answer = $answer_data['answer_value'];
1538
		$answer_id = $this->get_answer_id( $answer );
1539
		echo $answer_id;
1540
		die();
1541
	}
1542
1543
	public function get_answer_id( $answer = '' ) {
1544
1545
		$answer_id = '';
1546
1547
		if( $answer ) {
1548
			$answer_id = md5( $answer );
1549
		}
1550
1551
		return $answer_id;
1552
1553
	}
1554
1555
	/**
1556
	 * lesson_quiz_meta_box_content function.
1557
	 *
1558
	 * @access public
1559
	 * @return void
1560
	 */
1561
	public function lesson_quiz_meta_box_content () {
1562
		global $post;
1563
1564
		// Get quiz panel
1565
		$quiz_id = 0;
1566
		$quizzes = array();
0 ignored issues
show
Unused Code introduced by
$quizzes 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...
1567
		if ( 0 < $post->ID ) {
1568
			$quiz_id = $this->lesson_quizzes( $post->ID, 'any' );
1569
		}
1570
1571
		echo $this->quiz_panel( $quiz_id );
1572
1573
	} // End lesson_quiz_meta_box_content()
1574
1575
	/**
1576
	 * Quiz settings metabox
1577
	 * @return void
1578
	 */
1579
	public function lesson_quiz_settings_meta_box_content() {
1580
		global $post;
1581
1582
		$html = '';
1583
1584
		// Get quiz panel
1585
		$quiz_id = 0;
1586
		$lesson_id = $post->ID;
1587
		$quizzes = array();
0 ignored issues
show
Unused Code introduced by
$quizzes 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...
1588
		if ( 0 < $lesson_id ) {
1589
			$quiz_id = $this->lesson_quizzes( $lesson_id, 'any' );
1590
		}
1591
1592
		if( $quiz_id ) {
1593
			$html .= $this->quiz_settings_panel( $lesson_id, $quiz_id );
1594
		} else {
1595
			$html .= '<p><em>' . __( 'There is no quiz for this lesson yet - please add one in the \'Quiz Questions\' box.', 'woothemes-sensei' ) . '</em></p>';
1596
		}
1597
1598
		echo $html;
1599
	}
1600
1601
	public function quiz_settings_panel( $lesson_id = 0, $quiz_id = 0 ) {
1602
1603
1604
		$html = '';
1605
1606
		if( ! $lesson_id && ! $quiz_id ) return $html;
1607
1608
		$settings = $this->get_quiz_settings( $quiz_id );
1609
1610
		$html = Sensei()->admin->render_settings( $settings, $quiz_id, 'quiz-settings' );
1611
1612
		return $html;
1613
1614
	}
1615
1616
	public function get_quiz_settings( $quiz_id = 0 ) {
1617
1618
		$disable_passmark = '';
1619
		$pass_required = get_post_meta( $quiz_id, '_pass_required', true );
1620
		if( ! $pass_required ) {
1621
			$disable_passmark = 'hidden';
1622
		}
1623
1624
		// Setup Questions Query
1625
		$questions = array();
1626
		if ( 0 < $quiz_id ) {
1627
			$questions = $this->lesson_quiz_questions( $quiz_id );
1628
		}
1629
1630
		// Count questions
1631
		$question_count = 0;
1632 View Code Duplication
		foreach( $questions as $question ) {
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...
1633
			if( $question->post_type == 'multiple_question' ) {
1634
				$question_number = get_post_meta( $question->ID, 'number', true );
1635
				$question_count += $question_number;
1636
			} else {
1637
				++$question_count;
1638
			}
1639
		}
1640
1641
		$settings = array(
1642
			array(
1643
				'id' 			=> 'pass_required',
1644
				'label'			=> __( 'Pass required to complete lesson', 'woothemes-sensei' ),
1645
				'description'	=> __( 'The passmark must be achieved before the lesson is complete.', 'woothemes-sensei' ),
1646
				'type'			=> 'checkbox',
1647
				'default'		=> '',
1648
				'checked'		=> 'on',
1649
			),
1650
			array(
1651
				'id' 			=> 'quiz_passmark',
1652
				'label'			=> __( 'Quiz passmark percentage', 'woothemes-sensei' ),
1653
				'description'	=> '',
1654
				'type'			=> 'number',
1655
				'default'		=> 0,
1656
				'placeholder'	=> 0,
1657
				'min'			=> 0,
1658
				'max'			=> 100,
1659
				'class'			=> $disable_passmark,
1660
			),
1661
			array(
1662
				'id' 			=> 'show_questions',
1663
				'label'			=> __( 'Number of questions to show', 'woothemes-sensei' ),
1664
				'description'	=> __( 'Show a random selection of questions from this quiz each time a student views it.', 'woothemes-sensei' ),
1665
				'type'			=> 'number',
1666
				'default'		=> '',
1667
				'placeholder'	=> __( 'All', 'woothemes-sensei' ),
1668
				'min'			=> 1,
1669
				'max'			=> $question_count,
1670
			),
1671
			array(
1672
				'id' 			=> 'random_question_order',
1673
				'label'			=> __( 'Randomise question order', 'woothemes-sensei' ),
1674
				'description'	=> '',
1675
				'type'			=> 'checkbox',
1676
				'default'		=> 'no',
1677
				'checked'		=> 'yes',
1678
			),
1679
			array(
1680
				'id' 			=> 'quiz_grade_type',
1681
				'label'			=> __( 'Grade quiz automatically', 'woothemes-sensei' ),
1682
				'description'	=> __( 'Grades quiz and displays answer explanation immediately after completion. Only applicable if quiz is limited to Multiple Choice, True/False and Gap Fill questions. Questions that have a grade of zero are skipped during autograding.', 'woothemes-sensei' ),
1683
				'type'			=> 'checkbox',
1684
				'default'		=> 'auto',
1685
				'checked'		=> 'auto',
1686
			),
1687
			array(
1688
				'id' 			=> 'enable_quiz_reset',
1689
				'label'			=> __( 'Allow user to retake the quiz', 'woothemes-sensei' ),
1690
				'description'	=> __( 'Enables the quiz reset button.', 'woothemes-sensei' ),
1691
				'type'			=> 'checkbox',
1692
				'default'		=> '',
1693
				'checked'		=> 'on',
1694
			),
1695
		);
1696
1697
		return apply_filters( 'sensei_quiz_settings', $settings );
1698
	}
1699
1700
	/**
1701
	 * enqueue_scripts function.
1702
	 *
1703
	 * @access public
1704
	 * @return void
1705
	 */
1706
	public function enqueue_scripts( $hook ) {
1707
		global  $post_type;
1708
1709
		$allowed_post_types = apply_filters( 'sensei_scripts_allowed_post_types', array( 'lesson', 'course', 'question' ) );
1710
		$allowed_post_type_pages = apply_filters( 'sensei_scripts_allowed_post_type_pages', array( 'edit.php', 'post-new.php', 'post.php', 'edit-tags.php' ) );
1711
		$allowed_pages = apply_filters( 'sensei_scripts_allowed_pages', array( 'sensei_grading', 'sensei_analysis', 'sensei_learners', 'sensei_updates', 'woothemes-sensei-settings', 'lesson-order' ) );
1712
1713
		// Test for Write Panel Pages
1714
		if ( ( ( isset( $post_type ) && in_array( $post_type, $allowed_post_types ) ) && ( isset( $hook ) && in_array( $hook, $allowed_post_type_pages ) ) ) || ( isset( $_GET['page'] ) && in_array( $_GET['page'], $allowed_pages ) ) ) {
1715
1716
			$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
1717
1718
			// Load the lessons script
1719
            wp_enqueue_media();
1720
			wp_enqueue_script( 'sensei-lesson-metadata', Sensei()->plugin_url . 'assets/js/lesson-metadata' . $suffix . '.js', array( 'jquery', 'select2' ,'jquery-ui-sortable' ), Sensei()->version, true );
1721
			wp_enqueue_script( 'sensei-lesson-chosen', Sensei()->plugin_url . 'assets/chosen/chosen.jquery' . $suffix . '.js', array( 'jquery' ), Sensei()->version, true );
1722
			wp_enqueue_script( 'sensei-chosen-ajax', Sensei()->plugin_url . 'assets/chosen/ajax-chosen.jquery' . $suffix . '.js', array( 'jquery', 'sensei-lesson-chosen' ), Sensei()->version, true );
1723
1724
            // Load the bulk edit screen script
1725
            if( 'edit.php' == $hook && 'lesson'==$_GET['post_type'] ) {
1726
                wp_enqueue_script( 'sensei-lessons-bulk-edit', Sensei()->plugin_url . 'assets/js/admin/lesson-bulk-edit' . $suffix . '.js', array( 'jquery' ), Sensei()->version , true);
1727
            }
1728
1729
			// Localise script
1730
			$translation_strings = array( 'right_colon' => __( 'Right:', 'woothemes-sensei' ), 'wrong_colon' => __( 'Wrong:', 'woothemes-sensei' ), 'add_file' => __( 'Add file', 'woothemes-sensei' ), 'change_file' => __( 'Change file', 'woothemes-sensei' ), 'confirm_remove' => __( 'Are you sure you want to remove this question?', 'woothemes-sensei' ), 'confirm_remove_multiple' => __( 'Are you sure you want to remove these questions?', 'woothemes-sensei' ), 'too_many_for_cat' => __( 'You have selected more questions than this category contains - please reduce the number of questions that you are adding.', 'woothemes-sensei' ) );
1731
			$ajax_vars = array( 'lesson_update_question_nonce' => wp_create_nonce( 'lesson_update_question_nonce' ), 'lesson_add_course_nonce' => wp_create_nonce( 'lesson_add_course_nonce' ), 'lesson_update_grade_type_nonce' => wp_create_nonce( 'lesson_update_grade_type_nonce' ), 'lesson_update_question_order_nonce' => wp_create_nonce( 'lesson_update_question_order_nonce' ), 'lesson_update_question_order_random_nonce' => wp_create_nonce( 'lesson_update_question_order_random_nonce' ), 'lesson_add_multiple_questions_nonce' => wp_create_nonce( 'lesson_add_multiple_questions_nonce' ), 'lesson_remove_multiple_questions_nonce' => wp_create_nonce( 'lesson_remove_multiple_questions_nonce' ), 'lesson_add_existing_questions_nonce' => wp_create_nonce( 'lesson_add_existing_questions_nonce' ), 'filter_existing_questions_nonce' => wp_create_nonce( 'filter_existing_questions_nonce' ) );
1732
			$data = array_merge( $translation_strings, $ajax_vars );
1733
			wp_localize_script( 'sensei-lesson-metadata', 'woo_localized_data', $data );
1734
1735
			// Chosen RTL
1736
			if ( is_rtl() ) {
1737
				wp_enqueue_script( 'sensei-chosen-rtl', Sensei()->plugin_url . 'assets/chosen/chosen-rtl' . $suffix . '.js', array( 'jquery' ), Sensei()->version, true );
1738
			}
1739
1740
		}
1741
1742
	} // End enqueue_scripts()
1743
1744
	/**
1745
	 * Load in CSS styles where necessary.
1746
	 *
1747
	 * @access public
1748
	 * @since  1.4.0
1749
	 * @return void
1750
	 */
1751
	public function enqueue_styles ( $hook ) {
1752
		global  $post_type;
1753
1754
		$allowed_post_types = apply_filters( 'sensei_scripts_allowed_post_types', array( 'lesson', 'course', 'question', 'sensei_message' ) );
1755
		$allowed_post_type_pages = apply_filters( 'sensei_scripts_allowed_post_type_pages', array( 'edit.php', 'post-new.php', 'post.php', 'edit-tags.php' ) );
1756
		$allowed_pages = apply_filters( 'sensei_scripts_allowed_pages', array( 'sensei_grading', 'sensei_analysis', 'sensei_learners', 'sensei_updates', 'woothemes-sensei-settings' ) );
1757
1758
		// Test for Write Panel Pages
1759
		if ( ( ( isset( $post_type ) && in_array( $post_type, $allowed_post_types ) ) && ( isset( $hook ) && in_array( $hook, $allowed_post_type_pages ) ) ) || ( isset( $_GET['page'] ) && in_array( $_GET['page'], $allowed_pages ) ) ) {
1760
			wp_enqueue_style( 'woothemes-sensei-settings-api', esc_url( Sensei()->plugin_url . 'assets/css/settings.css' ), '', Sensei()->version );
1761
		}
1762
1763
	} // End enqueue_styles()
1764
1765
	/**
1766
	 * Add column headings to the "lesson" post list screen.
1767
	 * @access public
1768
	 * @since  1.0.0
1769
	 * @param  array $defaults
1770
	 * @return array $new_columns
1771
	 */
1772 View Code Duplication
	public function add_column_headings ( $defaults ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1773
		$new_columns['cb'] = '<input type="checkbox" />';
0 ignored issues
show
Coding Style Comprehensibility introduced by
$new_columns was never initialized. Although not strictly required by PHP, it is generally a good practice to add $new_columns = array(); before regardless.

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

Let’s take a look at an example:

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

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

    // do something with $myArray
}

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

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

Loading history...
1774
		$new_columns['title'] = _x( 'Lesson Title', 'column name', 'woothemes-sensei' );
1775
		$new_columns['lesson-course'] = _x( 'Course', 'column name', 'woothemes-sensei' );
1776
		$new_columns['lesson-prerequisite'] = _x( 'Pre-requisite Lesson', 'column name', 'woothemes-sensei' );
1777
		if ( isset( $defaults['date'] ) ) {
1778
			$new_columns['date'] = $defaults['date'];
1779
		}
1780
		return $new_columns;
1781
	} // End add_column_headings()
1782
1783
	/**
1784
	 * Add data for our newly-added custom columns.
1785
	 * @access public
1786
	 * @since  1.0.0
1787
	 * @param  string $column_name
1788
	 * @param  int $id
1789
	 * @return void
1790
	 */
1791
	public function add_column_data ( $column_name, $id ) {
1792
		global $wpdb, $post;
1793
1794
		switch ( $column_name ) {
1795
			case 'id':
1796
				echo $id;
1797
			break;
1798 View Code Duplication
			case 'lesson-course':
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...
1799
				$lesson_course_id = get_post_meta( $id, '_lesson_course', true);
1800
				if ( 0 < absint( $lesson_course_id ) ) {
1801
					echo '<a href="' . esc_url( get_edit_post_link( absint( $lesson_course_id ) ) ) . '" title="' . esc_attr( sprintf( __( 'Edit %s', 'woothemes-sensei' ), get_the_title( absint( $lesson_course_id ) ) ) ) . '">' . get_the_title( absint( $lesson_course_id ) ) . '</a>';
1802
				} // End If Statement
1803
			break;
1804 View Code Duplication
			case 'lesson-prerequisite':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1805
				$lesson_prerequisite_id = get_post_meta( $id, '_lesson_prerequisite', true);
1806
				if ( 0 < absint( $lesson_prerequisite_id ) ) {
1807
					echo '<a href="' . esc_url( get_edit_post_link( absint( $lesson_prerequisite_id ) ) ) . '" title="' . esc_attr( sprintf( __( 'Edit %s', 'woothemes-sensei' ), get_the_title( absint( $lesson_prerequisite_id ) ) ) ) . '">' . get_the_title( absint( $lesson_prerequisite_id ) ) . '</a>';
1808
				} // End If Statement
1809
			break;
1810
			default:
1811
			break;
1812
		} // End Switch Statement
1813
	} // End add_column_data()
1814
1815
	/**
1816
	 * lesson_add_course function.
1817
	 *
1818
	 * @access public
1819
	 * @return void
1820
	 */
1821
	public function lesson_add_course () {
1822
		global $current_user;
1823
		//Add nonce security to the request
1824
		if ( isset($_POST['lesson_add_course_nonce']) ) {
1825
			$nonce = esc_html( $_POST['lesson_add_course_nonce'] );
1826
		} // End If Statement
1827
		if ( ! wp_verify_nonce( $nonce, 'lesson_add_course_nonce' ) ) {
0 ignored issues
show
Bug introduced by
The variable $nonce does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1828
			die('');
1829
		} // End If Statement
1830
		// Parse POST data
1831
		$data = $_POST['data'];
1832
		$course_data = array();
1833
		parse_str($data, $course_data);
1834
		// Save the Course
1835
		$updated = false;
0 ignored issues
show
Unused Code introduced by
$updated 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...
1836
		$current_user = wp_get_current_user();
1837
		$question_data['post_author'] = $current_user->ID;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$question_data was never initialized. Although not strictly required by PHP, it is generally a good practice to add $question_data = array(); before regardless.

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

Let’s take a look at an example:

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

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

    // do something with $myArray
}

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

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

Loading history...
1838
		$updated = $this->lesson_save_course($course_data);
0 ignored issues
show
Bug introduced by
It seems like $course_data can also be of type null; however, Sensei_Lesson::lesson_save_course() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Bug introduced by
Are you sure the assignment to $updated is correct as $this->lesson_save_course($course_data) (which targets Sensei_Lesson::lesson_save_course()) seems to always return null.

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

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

}

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

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

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

Loading history...
1839
		echo $updated;
1840
		die(); // WordPress may print out a spurious zero without this can be particularly bad if using JSON
1841
	} // End lesson_add_course()
1842
1843
	/**
1844
	 * lesson_update_question function.
1845
	 *
1846
	 * @access public
1847
	 * @return void
1848
	 */
1849
	public function lesson_update_question () {
1850
		global $current_user;
1851
		//Add nonce security to the request
1852
		if ( isset($_POST['lesson_update_question_nonce']) ) {
1853
			$nonce = esc_html( $_POST['lesson_update_question_nonce'] );
1854
		} // End If Statement
1855
		if ( ! wp_verify_nonce( $nonce, 'lesson_update_question_nonce' ) ) {
0 ignored issues
show
Bug introduced by
The variable $nonce does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1856
			die('');
1857
		} // End If Statement
1858
		// Parse POST data
1859
		// WP slashes all incoming data regardless of Magic Quotes setting (see wp_magic_quotes()), which means that
1860
		// even the $_POST['data'] encoded with encodeURIComponent has it's apostrophes slashed.
1861
		// So first restore the original unslashed apostrophes by removing those slashes
1862
		$data = wp_unslash( $_POST['data'] );
1863
		// Then parse the string to an array (note that parse_str automatically urldecodes all the variables)
1864
		$question_data = array();
1865
		parse_str($data, $question_data);
1866
		// Finally re-slash all elements to ensure consistancy for lesson_save_question()
1867
		$question_data = wp_slash( $question_data );
1868
		// Save the question
1869
		$return = false;
1870
		// Question Save and Delete logic
1871
		if ( isset( $question_data['action'] ) && ( $question_data['action'] == 'delete' ) ) {
1872
			// Delete the Question
1873
			$return = $this->lesson_delete_question($question_data);
1874
		} else {
1875
			// Save the Question
1876
			if ( isset( $question_data['quiz_id'] ) && ( 0 < absint( $question_data['quiz_id'] ) ) ) {
1877
				$current_user = wp_get_current_user();
1878
				$question_data['post_author'] = $current_user->ID;
1879
				$question_id = $this->lesson_save_question( $question_data );
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $question_id is correct as $this->lesson_save_question($question_data) (which targets Sensei_Lesson::lesson_save_question()) seems to always return null.

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

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

}

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

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

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

Loading history...
1880
				$question_type = Sensei()->question->get_question_type( $question_id );
1881
1882
				$question_count = intval( $question_data['question_count'] );
1883
				++$question_count;
1884
1885
				$return = $this->quiz_panel_question( $question_type, $question_count, $question_id );
1886
			} // End If Statement
1887
		} // End If Statement
1888
1889
		echo $return;
1890
1891
		die();
1892
	} // End lesson_update_question()
1893
1894
	public function lesson_add_multiple_questions() {
1895
1896
		$return = '';
1897
1898
		//Add nonce security to the request
1899
		$nonce = '';
1900
		if( isset( $_POST['lesson_add_multiple_questions_nonce'] ) ) {
1901
			$nonce = esc_html( $_POST['lesson_add_multiple_questions_nonce'] );
1902
		} // End If Statement
1903
1904
		if( ! wp_verify_nonce( $nonce, 'lesson_add_multiple_questions_nonce' ) ) {
1905
			die( $return );
1906
		} // End If Statement
1907
1908
		// Parse POST data
1909
		$data = $_POST['data'];
1910
		$question_data = array();
1911
		parse_str( $data, $question_data );
1912
1913
		if( is_array( $question_data ) ) {
1914
			if( isset( $question_data['quiz_id'] ) && ( 0 < absint( $question_data['quiz_id'] ) ) ) {
1915
1916
				$quiz_id = intval( $question_data['quiz_id'] );
1917
				$question_number = intval( $question_data['question_number'] );
1918
				$question_category = intval( $question_data['question_category'] );
1919
1920
				$question_counter = intval( $question_data['question_count'] );
1921
				++$question_counter;
1922
1923
				$cat = get_term( $question_category, 'question-category' );
1924
1925
				$post_data = array(
1926
					'post_content' => '',
1927
					'post_status' => 'publish',
1928
					'post_title' => sprintf( __( '%1$s Question(s) from %2$s', 'woothemes-sensei' ), $question_number, $cat->name ),
1929
					'post_type' => 'multiple_question'
1930
				);
1931
1932
				$multiple_id = wp_insert_post( $post_data );
1933
1934
				if( $multiple_id && ! is_wp_error( $multiple_id ) ) {
1935
					add_post_meta( $multiple_id, 'category', $question_category );
1936
					add_post_meta( $multiple_id, 'number', $question_number );
1937
					add_post_meta( $multiple_id, '_quiz_id', $quiz_id, false );
1938
					add_post_meta( $multiple_id, '_quiz_question_order' . $quiz_id, $quiz_id . '000' . $question_counter );
1939
					$lesson_id = get_post_meta( $quiz_id, '_quiz_lesson', true );
1940
					update_post_meta( $lesson_id, '_quiz_has_questions', '1' );
1941
					$return = $this->quiz_panel_question( 'category', $question_counter, $multiple_id, 'quiz', array( $cat->name, $question_number ) );
1942
				}
1943
			}
1944
		}
1945
1946
		echo $return;
1947
1948
		die();
1949
	}
1950
1951
	public function lesson_remove_multiple_questions() {
1952
1953
		//Add nonce security to the request
1954
		$nonce = '';
1955
		if( isset( $_POST['lesson_remove_multiple_questions_nonce'] ) ) {
1956
			$nonce = esc_html( $_POST['lesson_remove_multiple_questions_nonce'] );
1957
		} // End If Statement
1958
1959
		if( ! wp_verify_nonce( $nonce, 'lesson_remove_multiple_questions_nonce' ) ) {
1960
			die('');
1961
		} // End If Statement
1962
1963
		// Parse POST data
1964
		$data = $_POST['data'];
1965
		$question_data = array();
1966
		parse_str( $data, $question_data );
1967
1968
		if( is_array( $question_data ) ) {
1969
			wp_delete_post( $question_data['question_id'], true );
1970
		}
1971
1972
		die( 'Deleted' );
1973
	}
1974
1975
	public function get_question_category_limit() {
1976
1977
		// Set default
1978
		$return = 1;
1979
1980
		// Parse POST data
1981
		$data = $_POST['data'];
1982
		$cat_data = array();
1983
		parse_str( $data, $cat_data );
1984
1985
		if( isset( $cat_data['cat'] ) && '' != $cat_data['cat'] ) {
1986
			$cat = get_term( $cat_data['cat'], 'question-category' );
1987
			if( isset( $cat->count ) ) {
1988
				$return = $cat->count;
1989
			}
1990
		}
1991
1992
		echo $return;
1993
1994
		die('');
1995
	}
1996
1997
	public function lesson_add_existing_questions() {
1998
1999
		//Add nonce security to the request
2000
		$nonce = '';
2001
		if( isset( $_POST['lesson_add_existing_questions_nonce'] ) ) {
2002
			$nonce = esc_html( $_POST['lesson_add_existing_questions_nonce'] );
2003
		} // End If Statement
2004
2005
		if( ! wp_verify_nonce( $nonce, 'lesson_add_existing_questions_nonce' ) ) {
2006
			die('');
2007
		} // End If Statement
2008
2009
		// Parse POST data
2010
		$data = $_POST['data'];
2011
		$question_data = array();
2012
		parse_str( $data, $question_data );
2013
2014
		$return = '';
2015
2016
		if( is_array( $question_data ) ) {
2017
2018
			if( isset( $question_data['questions'] ) && '' != $question_data['questions'] ) {
2019
2020
				$questions = explode( ',', trim( $question_data['questions'], ',' ) );
2021
				$quiz_id = $question_data['quiz_id'];
2022
				$question_count = intval( $question_data['question_count'] );
2023
2024
				foreach( $questions as $question_id ) {
2025
2026
					++$question_count;
2027
2028
					$quizzes = get_post_meta( $question_id, '_quiz_id', false );
2029 View Code Duplication
					if( ! in_array( $quiz_id, $quizzes ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
2030
			    		add_post_meta( $question_id, '_quiz_id', $quiz_id, false );
2031
						$lesson_id = get_post_meta( $quiz_id, '_quiz_lesson', true );
2032
						update_post_meta( $lesson_id, '_quiz_has_questions', '1' );
2033
			    	}
2034
2035
			    	add_post_meta( $question_id, '_quiz_question_order' . $quiz_id, $quiz_id . '000' . $question_count );
2036
					$question_type = Sensei()->question->get_question_type( $question_id );
2037
2038
					$return .= $this->quiz_panel_question( $question_type, $question_count, $question_id );
2039
				}
2040
			}
2041
		}
2042
2043
		echo $return;
2044
2045
		die('');
2046
	}
2047
2048 View Code Duplication
	public function lesson_update_grade_type() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2049
		//Add nonce security to the request
2050
		if ( isset($_POST['lesson_update_grade_type_nonce']) ) {
2051
			$nonce = esc_html( $_POST['lesson_update_grade_type_nonce'] );
2052
		} // End If Statement
2053
		if ( ! wp_verify_nonce( $nonce, 'lesson_update_grade_type_nonce' ) ) {
0 ignored issues
show
Bug introduced by
The variable $nonce does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
2054
			die('');
2055
		} // End If Statement
2056
		// Parse POST data
2057
		$data = $_POST['data'];
2058
		$quiz_data = array();
2059
		parse_str($data, $quiz_data);
2060
		update_post_meta( $quiz_data['quiz_id'], '_quiz_grade_type', $quiz_data['quiz_grade_type'] );
2061
		die();
2062
	}
2063
2064
	public function lesson_update_question_order() {
2065
		// Add nonce security to the request
2066
		if ( isset($_POST['lesson_update_question_order_nonce']) ) {
2067
			$nonce = esc_html( $_POST['lesson_update_question_order_nonce'] );
2068
		} // End If Statement
2069
		if ( ! wp_verify_nonce( $nonce, 'lesson_update_question_order_nonce' ) ) {
0 ignored issues
show
Bug introduced by
The variable $nonce does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
2070
			die('');
2071
		} // End If Statement
2072
		// Parse POST data
2073
		$data = $_POST['data'];
2074
		$quiz_data = array();
2075
		parse_str($data, $quiz_data);
2076
		if( strlen( $quiz_data['question_order'] ) > 0 ) {
2077
			$questions = explode( ',', $quiz_data['question_order'] );
2078
			$o = 1;
2079
			foreach( $questions as $question_id ) {
2080
				update_post_meta( $question_id, '_quiz_question_order' . $quiz_data['quiz_id'], $quiz_data['quiz_id'] . '000' . $o );
2081
				++$o;
2082
			}
2083
			update_post_meta( $quiz_data['quiz_id'], '_question_order', $questions );
2084
		}
2085
		die();
2086
	}
2087
2088 View Code Duplication
	public function lesson_update_question_order_random() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2089
		//Add nonce security to the request
2090
		if ( isset($_POST['lesson_update_question_order_random_nonce']) ) {
2091
			$nonce = esc_html( $_POST['lesson_update_question_order_random_nonce'] );
2092
		} // End If Statement
2093
		if ( ! wp_verify_nonce( $nonce, 'lesson_update_question_order_random_nonce' ) ) {
0 ignored issues
show
Bug introduced by
The variable $nonce does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
2094
			die('');
2095
		} // End If Statement
2096
		// Parse POST data
2097
		$data = $_POST['data'];
2098
		$quiz_data = array();
2099
		parse_str($data, $quiz_data);
2100
		update_post_meta( $quiz_data['quiz_id'], '_random_question_order', $quiz_data['random_question_order'] );
2101
		die();
2102
	}
2103
2104
	/**
2105
	 * lesson_save_course function.
2106
	 *
2107
	 * @access private
2108
	 * @param array $data (default: array())
2109
	 * @return void
2110
	 */
2111
	private function lesson_save_course( $data = array() ) {
2112
		global $current_user;
2113
		$return = false;
2114
		// Setup the course data
2115
		$course_id = 0;
2116
		$course_content = '';
2117
		$course_title = '';
2118
		$course_prerequisite = 0;
0 ignored issues
show
Unused Code introduced by
$course_prerequisite 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...
2119
		$course_category = 0;
0 ignored issues
show
Unused Code introduced by
$course_category 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...
2120 View Code Duplication
		if ( isset( $data[ 'course_id' ] ) && ( 0 < absint( $data[ 'course_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...
2121
			$course_id = absint( $data[ 'course_id' ] );
2122
		} // End If Statement
2123
		if ( isset( $data[ 'course_title' ] ) && ( '' != $data[ 'course_title' ] ) ) {
2124
			$course_title = $data[ 'course_title' ];
2125
		} // End If Statement
2126
		$post_title = $course_title;
2127
		if ( isset($data[ 'post_author' ]) ) {
2128
			$post_author = $data[ 'post_author' ];
0 ignored issues
show
Unused Code introduced by
$post_author 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...
2129
		} else {
2130
			$current_user = wp_get_current_user();
2131
			$post_author = $current_user->ID;
0 ignored issues
show
Unused Code introduced by
$post_author 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...
2132
		} // End If Statement
2133
		$post_status = 'publish';
2134
		$post_type = 'course';
2135
		if ( isset( $data[ 'course_content' ] ) && ( '' != $data[ 'course_content' ] ) ) {
2136
			$course_content = $data[ 'course_content' ];
2137
		} // End If Statement
2138
		$post_content = $course_content;
2139
		// Course Query Arguments
2140
		$post_type_args = array(	'post_content' => $post_content,
2141
  		    						'post_status' => $post_status,
2142
  		    						'post_title' => $post_title,
2143
  		    						'post_type' => $post_type
2144
  		    						);
2145
  		// Only save if there is a valid title
2146
  		if ( $post_title != '' ) {
2147
  		    // Check for prerequisite courses & product id
2148
  		    $course_prerequisite_id = absint( $data[ 'course_prerequisite' ] );
2149
  		    $course_woocommerce_product_id = absint( $data[ 'course_woocommerce_product' ] );
2150
  		    $course_category_id = absint( $data[ 'course_category' ] );
2151
  		    if ( 0 == $course_woocommerce_product_id ) { $course_woocommerce_product_id = '-'; }
2152
  		    // Insert or Update the Lesson Quiz
2153
		    if ( 0 < $course_id ) {
2154
		    	$post_type_args[ 'ID' ] = $course_id;
2155
		    	$course_id = wp_update_post($post_type_args);
2156
		    	update_post_meta( $course_id, '_course_prerequisite', $course_prerequisite_id );
2157
		    	update_post_meta( $course_id, '_course_woocommerce_product', $course_woocommerce_product_id );
2158
		    	if ( 0 < $course_category_id ) {
2159
		    		wp_set_object_terms( $course_id, $course_category_id, 'course-category' );
2160
		    	} // End If Statement
2161
		    } else {
2162
		    	$course_id = wp_insert_post($post_type_args);
2163
		    	add_post_meta( $course_id, '_course_prerequisite', $course_prerequisite_id );
2164
		    	add_post_meta( $course_id, '_course_woocommerce_product', $course_woocommerce_product_id );
2165
		    	if ( 0 < $course_category_id ) {
2166
		    		wp_set_object_terms( $course_id, $course_category_id, 'course-category' );
2167
		    	} // End If Statement
2168
		    } // End If Statement
2169
		} // End If Statement
2170
  		// Check that the insert or update saved by testing the post id
2171
  		if ( 0 < $course_id ) {
2172
  			$return = $course_id;
2173
  		} // End If Statement
2174
  		return $return;
2175
  	} // End lesson_save_course()
2176
2177
2178
	/**
2179
	 * lesson_save_question function.
2180
	 *
2181
	 * @access private
2182
	 * @param array $data (default: array())
2183
	 * @return void
2184
	 */
2185
	public function lesson_save_question( $data = array(), $context = 'quiz' ) {
2186
		$return = false;
2187
		// Save the Questions
2188
		// Setup the Question data
2189
		$question_id = 0;
2190
		$question_text = '';
2191
		$question_right_answer = '';
2192
		$question_wrong_answers = $question_right_answers = array();
2193
		$question_type = 'multiple-choice';
2194
		$question_category = '';
2195
2196
		// Handle Question Type
2197
		if ( isset( $data[ 'question_type' ] ) && ( '' != $data[ 'question_type' ] ) ) {
2198
			$question_type = $data[ 'question_type' ];
2199
		} // End If Statement
2200
2201
		if ( isset( $data[ 'question_category' ] ) && ( '' != $data[ 'question_category' ] ) ) {
2202
			$question_category = $data[ 'question_category' ];
2203
		} // End If Statement
2204
2205 View Code Duplication
		if ( isset( $data[ 'question_id' ] ) && ( 0 < absint( $data[ 'question_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...
2206
			$question_id = absint( $data[ 'question_id' ] );
2207
		} // End If Statement
2208
		if ( isset( $data[ 'question' ] ) && ( '' != $data[ 'question' ] ) ) {
2209
			$question_text = $data[ 'question' ];
2210
		} // End If Statement
2211
		$post_title = $question_text;
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...
2212
		// Handle Default Fields (multiple choice)
2213
		if ( 'multiple-choice' == $question_type && isset( $data[ 'question_right_answers' ] ) && ( '' != $data[ 'question_right_answers' ] ) ) {
2214
			$question_right_answers = $data[ 'question_right_answers' ];
2215
		} // End If Statement
2216
		elseif ( 'multiple-choice' == $question_type && isset( $data[ 'question_right_answer' ] ) && ( '' != $data[ 'question_right_answer' ] ) ) {
2217
			$question_right_answer = $data[ 'question_right_answer' ];
2218
		} // End If Statement
2219
		if ( 'multiple-choice' == $question_type && isset( $data[ 'question_wrong_answers' ] ) && ( '' != $data[ 'question_wrong_answers' ] ) ) {
2220
			$question_wrong_answers = $data[ 'question_wrong_answers' ];
2221
		} // End If Statement
2222
		// Handle Boolean Fields - Edit
2223
		if ( 'boolean' == $question_type && isset( $data[ 'question_' . $question_id . '_right_answer_boolean' ] ) && ( '' != $data[ 'question_' . $question_id . '_right_answer_boolean' ] ) ) {
2224
			$question_right_answer = $data[ 'question_' . $question_id . '_right_answer_boolean' ];
2225
		} // End If Statement
2226
		// Handle Boolean Fields - Add
2227
		if ( 'boolean' == $question_type && isset( $data[ 'question_right_answer_boolean' ] ) && ( '' != $data[ 'question_right_answer_boolean' ] ) ) {
2228
			$question_right_answer = $data[ 'question_right_answer_boolean' ];
2229
		} // End If Statement
2230
		// Handle Gap Fill Fields
2231
		if ( 'gap-fill' == $question_type && isset( $data[ 'add_question_right_answer_gapfill_gap' ] ) && '' != $data[ 'add_question_right_answer_gapfill_gap' ] ) {
2232
			$question_right_answer = $data[ 'add_question_right_answer_gapfill_pre' ] . '||' . $data[ 'add_question_right_answer_gapfill_gap' ] . '||' . $data[ 'add_question_right_answer_gapfill_post' ];
2233
		} // End If Statement
2234
		// Handle Multi Line Fields
2235
		if ( 'multi-line' == $question_type && isset( $data[ 'add_question_right_answer_multiline' ] ) && ( '' != $data[ 'add_question_right_answer_multiline' ] ) ) {
2236
			$question_right_answer = $data[ 'add_question_right_answer_multiline' ];
2237
		} // End If Statement
2238
		// Handle Single Line Fields
2239
		if ( 'single-line' == $question_type && isset( $data[ 'add_question_right_answer_singleline' ] ) && ( '' != $data[ 'add_question_right_answer_singleline' ] ) ) {
2240
			$question_right_answer = $data[ 'add_question_right_answer_singleline' ];
2241
		} // End If Statement
2242
		// Handle File Upload Fields
2243
		if ( 'file-upload' == $question_type && isset( $data[ 'add_question_right_answer_fileupload' ] ) && ( '' != $data[ 'add_question_right_answer_fileupload' ] ) ) {
2244
			$question_right_answer = $data[ 'add_question_right_answer_fileupload' ];
2245
		} // End If Statement
2246
		if ( 'file-upload' == $question_type && isset( $data[ 'add_question_wrong_answer_fileupload' ] ) && ( '' != $data[ 'add_question_wrong_answer_fileupload' ] ) ) {
2247
			$question_wrong_answers = array( $data[ 'add_question_wrong_answer_fileupload' ] );
2248
		} // End If Statement
2249
2250
		// Handle Question Grade
2251
		if ( isset( $data[ 'question_grade' ] ) && ( '' != $data[ 'question_grade' ] ) ) {
2252
			$question_grade = $data[ 'question_grade' ];
2253
		} // End If Statement
2254
2255
		// Handle Answer Feedback
2256
		$answer_feedback = '';
2257
		if ( isset( $data[ 'answer_feedback_boolean' ] ) && !empty( $data[ 'answer_feedback_boolean' ] ) ) {
2258
2259
            $answer_feedback = $data[ 'answer_feedback_boolean' ];
2260
2261
		}elseif( isset( $data[ 'answer_feedback_multiple_choice' ] ) && !empty( $data[ 'answer_feedback_multiple_choice' ] ) ){
2262
2263
            $answer_feedback = $data[ 'answer_feedback_multiple_choice' ];
2264
2265
        }elseif( isset( $data[ 'answer_feedback' ] )  ){
2266
2267
            $answer_feedback = $data[ 'answer_feedback' ];
2268
2269
        } // End If Statement
2270
2271
		$post_title = $question_text;
2272
		$post_author = $data[ 'post_author' ];
0 ignored issues
show
Unused Code introduced by
$post_author 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...
2273
		$post_status = 'publish';
2274
		$post_type = 'question';
2275
		// Handle the extended question text
2276
		if ( isset( $data[ 'question_description' ] ) && ( '' != $data[ 'question_description' ] ) ) {
2277
			$post_content = $data[ 'question_description' ];
2278
		}
2279
		else {
2280
			$post_content = '';
2281
		}
2282
		// Question Query Arguments
2283
		$post_type_args = array(	'post_content' => $post_content,
2284
  		    						'post_status' => $post_status,
2285
  		    						'post_title' => $post_title,
2286
  		    						'post_type' => $post_type
2287
  		    						);
2288
2289
  		// Remove empty values and reindex the array
2290
  		if ( is_array( $question_right_answers ) && 0 < count($question_right_answers) ) {
2291
  			$question_right_answers_array = array_values( array_filter( $question_right_answers, 'strlen' ) );
2292
  			$question_right_answers = array();
2293
2294
  			foreach( $question_right_answers_array as $answer ) {
2295
  				if( ! in_array( $answer, $question_right_answers ) ) {
2296
  					$question_right_answers[] = $answer;
2297
  				}
2298
  			}
2299
  			if ( 0 < count($question_right_answers) ) {
2300
  				$question_right_answer = $question_right_answers;
2301
  			}
2302
  		} // End If Statement
2303
  		$right_answer_count = count( $question_right_answer );
2304
2305
		// Remove empty values and reindex the array
2306
  		if ( is_array( $question_wrong_answers ) ) {
2307
  			$question_wrong_answers_array = array_values( array_filter( $question_wrong_answers, 'strlen' ) );
2308
  			$question_wrong_answers = array();
2309
  		} // End If Statement
2310
2311
  		foreach( $question_wrong_answers_array as $answer ) {
0 ignored issues
show
Bug introduced by
The variable $question_wrong_answers_array does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
2312
  			if( ! in_array( $answer, $question_wrong_answers ) ) {
2313
  				$question_wrong_answers[] = $answer;
2314
  			}
2315
  		}
2316
2317
  		$wrong_answer_count = count( $question_wrong_answers );
2318
2319
  		// Only save if there is a valid title
2320
  		if ( $post_title != '' ) {
2321
2322
  			// Get Quiz ID for the question
2323
  		    $quiz_id = $data['quiz_id'];
2324
2325
  		    // Get question media
2326
			$question_media = $data['question_media'];
2327
2328
  		    // Get answer order
2329
  		    $answer_order = '';
2330
  		    if( isset( $data['answer_order'] ) ) {
2331
				$answer_order = $data['answer_order'];
2332
			}
2333
2334
			// Get random order selection
2335
			$random_order = 'no';
2336
			if( isset( $data['random_order'] ) ) {
2337
				$random_order = $data['random_order'];
2338
			}
2339
2340
  		    // Insert or Update the question
2341
  		    if ( 0 < $question_id ) {
2342
2343
  		    	$post_type_args[ 'ID' ] = $question_id;
2344
		    	$question_id = wp_update_post( $post_type_args );
2345
2346
		    	// Update poast meta
2347
		    	if( 'quiz' == $context ) {
2348
		    		$quizzes = get_post_meta( $question_id, '_quiz_id', false );
2349
		    		if( ! in_array( $quiz_id, $quizzes ) ) {
2350
			    		add_post_meta( $question_id, '_quiz_id', $quiz_id, false );
2351
			    	}
2352
		    	}
2353
2354
		    	update_post_meta( $question_id, '_question_grade', $question_grade );
0 ignored issues
show
Bug introduced by
The variable $question_grade does not seem to be defined for all execution paths leading up to this point.

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

Let’s take a look at an example:

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

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

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

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

Available Fixes

  1. Check for existence of the variable explicitly:

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

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

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
2355
		    	update_post_meta( $question_id, '_question_right_answer', $question_right_answer );
2356
		    	update_post_meta( $question_id, '_right_answer_count', $right_answer_count );
2357
		    	update_post_meta( $question_id, '_question_wrong_answers', $question_wrong_answers );
2358
		    	update_post_meta( $question_id, '_wrong_answer_count', $wrong_answer_count );
2359
		    	update_post_meta( $question_id, '_question_media', $question_media );
2360
		    	update_post_meta( $question_id, '_answer_order', $answer_order );
2361
		    	update_post_meta( $question_id, '_random_order', $random_order );
2362
2363
		    	if( 'quiz' != $context ) {
2364
		    		wp_set_post_terms( $question_id, array( $question_type ), 'question-type', false );
2365
		    	}
2366
				// Don't store empty value, no point
2367
				if ( !empty($answer_feedback) ) {
2368
					update_post_meta( $question_id, '_answer_feedback', $answer_feedback );
2369
				}
2370
2371
		    } else {
2372
				$question_id = wp_insert_post( $post_type_args );
2373
				$question_count = intval( $data['question_count'] );
2374
				++$question_count;
2375
2376
				// Set post meta
2377 View Code Duplication
				if( 'quiz' == $context ) {
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...
2378
					add_post_meta( $question_id, '_quiz_id', $quiz_id, false );
2379
					$lesson_id = get_post_meta( $quiz_id, '_quiz_lesson', true );
2380
					update_post_meta( $lesson_id, '_quiz_has_questions', '1' );
2381
				}
2382
2383
				if( isset( $question_grade ) ) {
2384
		    		add_post_meta( $question_id, '_question_grade', $question_grade );
2385
		    	}
2386
		    	add_post_meta( $question_id, '_question_right_answer', $question_right_answer );
2387
		    	add_post_meta( $question_id, '_right_answer_count', $right_answer_count );
2388
		    	add_post_meta( $question_id, '_question_wrong_answers', $question_wrong_answers );
2389
		    	add_post_meta( $question_id, '_wrong_answer_count', $wrong_answer_count );
2390
		    	add_post_meta( $question_id, '_quiz_question_order' . $quiz_id, $quiz_id . '000' . $question_count );
2391
		    	add_post_meta( $question_id, '_question_media', $question_media );
2392
		    	add_post_meta( $question_id, '_answer_order', $answer_order );
2393
		    	add_post_meta( $question_id, '_random_order', $random_order );
2394
				// Don't store empty value, no point
2395
				if ( !empty($answer_feedback) ) {
2396
					add_post_meta( $question_id, '_answer_feedback', $answer_feedback );
2397
				}
2398
2399
		    	// Set the post terms for question-type
2400
			    wp_set_post_terms( $question_id, array( $question_type ), 'question-type' );
2401
2402
			    if( $question_category ) {
2403
	    			wp_set_post_terms( $question_id, array( $question_category ), 'question-category' );
2404
	    		}
2405
2406
		    } // End If Statement
2407
		} // End If Statement
2408
  		// Check that the insert or update saved by testing the post id
2409
  		if ( 0 < $question_id ) {
2410
  			$return = $question_id;
2411
  		} // End If Statement
2412
  		return $return;
2413
  	} // End lesson_question_save()
2414
2415
2416
	/**
2417
	 * lesson_delete_question function.
2418
	 *
2419
	 * @access private
2420
	 * @param array $data (default: array())
2421
	 * @return void
2422
	 */
2423
	private function lesson_delete_question( $data = array() ) {
2424
2425
		// Get which question to delete
2426
		$question_id = 0;
2427 View Code Duplication
		if ( isset( $data[ 'question_id' ] ) && ( 0 < absint( $data[ 'question_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...
2428
			$question_id = absint( $data[ 'question_id' ] );
2429
		} // End If Statement
2430
		// Delete the question
2431
		if ( 0 < $question_id ) {
2432
			$quizzes = get_post_meta( $question_id, '_quiz_id', false );
2433
2434
			foreach( $quizzes as $quiz_id ) {
2435
				if( $quiz_id == $data['quiz_id'] ) {
2436
					delete_post_meta( $question_id, '_quiz_id', $quiz_id );
2437
				}
2438
			}
2439
2440
			return true;
2441
		} // End If Statement
2442
		return false;
2443
	} // End lesson_delete_question()
2444
2445
2446
	/**
2447
	 * lesson_complexities function.
2448
	 *
2449
	 * @access public
2450
	 * @return array $lesson_complexities
2451
	 */
2452
	public function lesson_complexities() {
2453
2454
		// V2 - make filter for this array
2455
        $lesson_complexities = array( 	'easy' => __( 'Easy', 'woothemes-sensei' ),
2456
									'std' => __( 'Standard', 'woothemes-sensei' ),
2457
									'hard' => __( 'Hard', 'woothemes-sensei' )
2458
									);
2459
2460
		return $lesson_complexities;
2461
2462
	} // End lesson_complexities
2463
2464
2465
	/**
2466
	 * lesson_count function.
2467
	 *
2468
	 * @access public
2469
	 * @param string $post_status (default: 'publish')
2470
	 * @return int
2471
	 */
2472
	public function lesson_count( $post_status = 'publish', $course_id = false ) {
2473
2474
		$post_args = array(	'post_type'         => 'lesson',
2475
							'posts_per_page'    => -1,
2476
//							'orderby'           => 'menu_order date',
0 ignored issues
show
Unused Code Comprehensibility introduced by
54% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
2477
//							'order'             => 'ASC',
2478
							'post_status'       => $post_status,
2479
							'suppress_filters'  => 0,
2480
							'fields'            => 'ids',
2481
							);
2482
		if( $course_id ) {
2483
			$post_args['meta_query'][] = array(
2484
				'key' => '_lesson_course',
2485
				'value' => $course_id,
2486
			);
2487
		}
2488
		else {
2489
			// Simple check for connection to a Course
2490
			$post_args['meta_query'][] = array(
2491
				'key' => '_lesson_course',
2492
				'value' => 0,
2493
				'compare' => '>=',
2494
			);
2495
		}
2496
2497
		// Allow WP to generate the complex final query, just shortcut to only do an overall count
2498
//		add_filter( 'posts_clauses', array( 'WooThemes_Sensei_Utils', 'get_posts_count_only_filter' ) );
2499
		$lessons_query = new WP_Query( apply_filters( 'sensei_lesson_count', $post_args ) );
2500
//		remove_filter( 'posts_clauses', array( 'WooThemes_Sensei_Utils', 'get_posts_count_only_filter' ) );
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

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

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

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

Loading history...
2501
2502
		return count( $lessons_query->posts );
2503
	} // End lesson_count()
2504
2505
2506
	/**
2507
	 * lesson_quizzes function.
2508
	 *
2509
	 * @access public
2510
	 * @param int $lesson_id (default: 0)
2511
	 * @param string $post_status (default: 'publish')
2512
	 * @param string $fields (default: 'ids')
2513
	 * @return int $quiz_id
2514
	 */
2515 View Code Duplication
	public function lesson_quizzes( $lesson_id = 0, $post_status = 'any', $fields = 'ids' ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
2516
2517
		$posts_array = array();
0 ignored issues
show
Unused Code introduced by
$posts_array 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...
2518
2519
		$post_args = array(	'post_type' 		=> 'quiz',
2520
							'posts_per_page' 		=> 1,
2521
							'orderby'         	=> 'title',
2522
    						'order'           	=> 'DESC',
2523
    						'post_parent'      	=> $lesson_id,
2524
    						'post_status'		=> $post_status,
2525
							'suppress_filters' 	=> 0,
2526
							'fields'            => $fields
2527
							);
2528
		$posts_array = get_posts( $post_args );
2529
        $quiz_id = array_shift($posts_array);
2530
2531
		return $quiz_id;
2532
	} // End lesson_quizzes()
2533
2534
2535
	/**
2536
	 * Fetches all the questions for a quiz depending on certain conditions.
2537
     *
2538
     * Determine which questions should be shown depending on:
2539
     * - admin/teacher selected questions to be shown
2540
     * - questions shown to a user previously (saved as asked questions)
2541
     * - limit number of questions lesson setting
2542
	 *
2543
     * @since 1.0
2544
	 * @param int $quiz_id (default: 0)
2545
	 * @param string $post_status (default: 'publish')
2546
	 * @param string $orderby (default: 'meta_value_num title')
2547
	 * @param string $order (default: 'ASC')
2548
     *
2549
	 * @return array $questions { $question type WP_Post }
2550
	 */
2551
	public function lesson_quiz_questions( $quiz_id = 0, $post_status = 'any', $orderby = 'meta_value_num title', $order = 'ASC' ) {
2552
2553
		$quiz_id = (string) $quiz_id;
2554
        $quiz_lesson_id = Sensei()->quiz->get_lesson_id( $quiz_id );
2555
2556
        // setup the user id
2557
        if( is_admin() ) {
2558
            $user_id = isset( $_GET['user'] ) ? $_GET['user'] : '' ;
2559
        } else {
2560
            $user_id = get_current_user_id();
2561
        }
2562
2563
        // get the users current status on the lesson
2564
        $user_lesson_status = WooThemes_Sensei_Utils::user_lesson_status( $quiz_lesson_id, $user_id );
2565
2566
		// Set the default question order if it has not already been set for this quiz
2567
		$this->set_default_question_order( $quiz_id );
2568
2569
		// If viewing quiz on the frontend then show questions in random order if set
2570
		if ( ! is_admin() ) {
2571
			$random_order = get_post_meta( $quiz_id, '_random_question_order', true );
2572
			if( $random_order && $random_order == 'yes' ) {
2573
				$orderby = 'rand';
2574
			}
2575
		}
2576
2577
		// Get all questions and multiple questions
2578
		$question_query_args = array(
2579
			'post_type' 		=> array( 'question', 'multiple_question' ),
2580
			'posts_per_page' 	=> -1,
2581
			'meta_key'        	=> '_quiz_question_order' . $quiz_id,
2582
			'orderby'         	=> $orderby,
2583
			'order'           	=> $order,
2584
			'meta_query'		=> array(
2585
				array(
2586
					'key'       => '_quiz_id',
2587
					'value'     => $quiz_id,
2588
				)
2589
			),
2590
			'post_status'		=> $post_status,
2591
			'suppress_filters' 	=> 0
2592
		);
2593
2594
        //query the questions
2595
		$questions_query = new WP_Query( $question_query_args );
2596
2597
        // Set return array to initially include all items
2598
        $questions = $questions_query->posts;
2599
2600
        // set the questions array that will be manipulated within this function
2601
        $questions_array = $questions_query->posts;
2602
2603
		// If viewing quiz on frontend or in grading then only single questions must be shown
2604
		$selected_questions = false;
2605
		if( ! is_admin() || ( is_admin() && isset( $_GET['page'] ) && 'sensei_grading' == $_GET['page'] && isset( $_GET['user'] ) && isset( $_GET['quiz_id'] ) ) ) {
2606
2607
			// Fetch the questions that the user was asked in their quiz if they have already completed it
2608
			$questions_asked_string = !empty( $user_lesson_status->comment_ID) ? get_comment_meta( $user_lesson_status->comment_ID, 'questions_asked', true ) : false;
2609
			if( !empty($questions_asked_string) ) {
2610
2611
				$selected_questions = explode( ',', $questions_asked_string );
2612
2613
				// Fetch each question in the order in which they were asked
2614
				$questions = array();
2615
				foreach( $selected_questions as $question_id ) {
2616
					if( ! $question_id ) continue;
2617
					$question = get_post( $question_id );
2618
					if( ! isset( $question ) || ! isset( $question->ID ) ) continue;
2619
					$questions[] = $question;
2620
				}
2621
2622
			} else {
2623
2624
				// Otherwise, make sure that we convert all multiple questions into single questions
2625
2626
				$multiple_array = array();
0 ignored issues
show
Unused Code introduced by
$multiple_array 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...
2627
				$existing_questions = array();
2628
2629
				// Set array of questions that already exist so we can prevent duplicates from appearing
2630
				foreach( $questions_array as $question ) {
2631
					if( 'question' != $question->post_type ) continue;
2632
					$existing_questions[] = $question->ID;
2633
				}
2634
2635
				// Include only single questions in the return array
2636
				$questions_loop = $questions_array;
2637
				$questions_array = array();
2638
				foreach( $questions_loop as $k => $question ) {
2639
2640
					// If this is a single question then include it
2641
					if( 'question' == $question->post_type ) {
2642
						$questions_array[] = $question;
2643
					} else {
2644
2645
						// If this is a multiple question then get the specified amount of questions from the specified category
2646
						$question_cat = intval( get_post_meta( $question->ID, 'category', true ) );
2647
						$question_number = intval( get_post_meta( $question->ID, 'number', true ) );
2648
2649
						$qargs = array(
2650
							'post_type' 		=> 'question',
2651
							'posts_per_page' 		=> $question_number,
2652
							'orderby'         	=> $orderby,
2653
							'tax_query'			=> array(
2654
								array(
2655
									'taxonomy'  => 'question-category',
2656
									'field'     => 'term_id',
2657
									'terms'		=> $question_cat
2658
								)
2659
							),
2660
							'post_status'		=> $post_status,
2661
							'suppress_filters' 	=> 0,
2662
							'post__not_in'		=> $existing_questions,
2663
						);
2664
						$cat_questions = get_posts( $qargs );
2665
2666
						// Merge results into return array
2667
						$questions_array = array_merge( $questions_array, $cat_questions );
2668
2669
						// Add selected questions to existing questions array to prevent duplicates from being added
2670
						foreach( $questions_array as $cat_question ) {
2671
							if( in_array( $cat_question->ID, $existing_questions ) ) continue;
2672
							$existing_questions[] = $cat_question->ID;
2673
						}
2674
					}
2675
				}
2676
2677
				// Set return data
2678
				$questions = $questions_array;
2679
			}
2680
		}
2681
2682
		// If user has not already taken the quiz and a limited number of questions are to be shown, then show a random selection of the specified amount of questions
2683
		if( ! $selected_questions ) {
2684
2685
			// Only limit questions like this on the frontend
2686
			if( ! is_admin() ) {
2687
2688
				// Get number of questions to show
2689
				$show_questions = intval( get_post_meta( $quiz_id, '_show_questions', true ) );
2690
				if( $show_questions ) {
2691
2692
					// Get random set of array keys from selected questions array
2693
					$selected_questions = array_rand( $questions_array, $show_questions );
2694
2695
					// Loop through all questions and pick the the ones to be shown based on the random key selection
2696
					$questions = array();
2697
					foreach( $questions_array as $k => $question ) {
2698
2699
						// Random keys will always be an array, unless only one question is to be shown
2700
						if( is_array( $selected_questions ) ) {
2701
							if( in_array( $k, $selected_questions ) ) {
2702
								$questions[] = $question;
2703
							}
2704
						} elseif( 1 == $show_questions ) {
2705
							if ( $selected_questions == $k ) {
2706
								$questions[] = $question;
2707
							}
2708
						}
2709
					}
2710
				}
2711
			}
2712
		}
2713
2714
        // Save the questions that will be asked for the current user
2715
        // this happens only once per user/quiz, unless the user resets the quiz
2716
        if( ! is_admin() ){
2717
2718
            if( $user_lesson_status ) {
2719
2720
                $questions_asked = get_comment_meta($user_lesson_status->comment_ID, 'questions_asked', true);
2721
                if ( empty($questions_asked) && $user_lesson_status) {
2722
2723
                    $questions_asked = array();
2724
                    foreach ($questions as $question) {
2725
2726
                        $questions_asked[] = $question->ID;
2727
2728
                    }
2729
2730
                    // save the questions asked id
2731
                    $questions_asked_csv = implode(',', $questions_asked);
2732
                    update_comment_meta($user_lesson_status->comment_ID, 'questions_asked', $questions_asked_csv);
2733
2734
                }
2735
            }
2736
        }
2737
2738
        /**
2739
         * Filter the questions returned by Sensei_Lesson::lessons_quiz_questions
2740
         *
2741
         * @hooked Sensei_Teacher::allow_teacher_access_to_questions
2742
         * @since 1.8.0
2743
         */
2744
		return apply_filters( 'sensei_lesson_quiz_questions', $questions,  $quiz_id  );
2745
2746
	} // End lesson_quiz_questions()
2747
2748
	/**
2749
	 * Set the default quiz order
2750
	 * @param integer $quiz_id ID of quiz
2751
	 */
2752
	public function set_default_question_order( $quiz_id = 0 ) {
2753
2754
		if( $quiz_id ) {
2755
2756
			$question_order = get_post_meta( $quiz_id, '_question_order', true );
2757
2758
			if( ! $question_order ) {
2759
2760
				$args = array(
2761
					'post_type' 		=> 'question',
2762
					'posts_per_page' 		=> -1,
2763
					'orderby'         	=> 'ID',
2764
					'order'           	=> 'ASC',
2765
					'meta_query'		=> array(
2766
						array(
2767
							'key'       => '_quiz_id',
2768
							'value'     => $quiz_id
2769
						)
2770
					),
2771
					'post_status'		=> 'any',
2772
					'suppress_filters' 	=> 0
2773
				);
2774
				$questions = get_posts( $args );
2775
2776
				$o = 1;
2777
				foreach( $questions as $question ) {
2778
					add_post_meta( $question->ID, '_quiz_question_order' . $quiz_id, $quiz_id . '000' . $o, true );
2779
					$o++;
2780
				}
2781
			}
2782
		}
2783
2784
	}
2785
2786
	/**
2787
	 * lesson_image function.
2788
	 *
2789
	 * Handles output of the lesson image
2790
	 *
2791
	 * @access public
2792
	 * @param int $lesson_id (default: 0)
2793
	 * @param string $width (default: '100')
2794
	 * @param string $height (default: '100')
2795
	 * @return string
2796
	 */
2797
	public function lesson_image( $lesson_id = 0, $width = '100', $height = '100', $widget = false ) {
2798
2799
		$html = '';
2800
2801
		// Get Width and Height settings
2802
		if ( ( $width == '100' ) && ( $height == '100' ) ) {
2803
2804
			if ( is_singular( 'lesson' ) ) {
2805
2806
				if ( ! $widget && ! Sensei()->settings->settings[ 'lesson_single_image_enable' ] ) {
2807
2808
					return '';
2809
2810
				} // End If Statement
2811
2812
				$image_thumb_size = 'lesson_single_image';
2813
				$dimensions = Sensei()->get_image_size( $image_thumb_size );
2814
				$width = $dimensions['width'];
2815
				$height = $dimensions['height'];
2816
				$crop = $dimensions['crop'];
0 ignored issues
show
Unused Code introduced by
$crop 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...
2817
2818
			} else {
2819
2820
				if ( ! $widget && ! Sensei()->settings->settings[ 'course_lesson_image_enable' ] ) {
2821
2822
					return '';
2823
				} // End If Statement
2824
2825
				$image_thumb_size = 'lesson_archive_image';
2826
				$dimensions = Sensei()->get_image_size( $image_thumb_size );
2827
				$width = $dimensions['width'];
2828
				$height = $dimensions['height'];
2829
				$crop = $dimensions['crop'];
0 ignored issues
show
Unused Code introduced by
$crop 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...
2830
2831
			} // End If Statement
2832
2833
		} // End If Statement
2834
2835
		$img_url = '';
2836
2837
		if ( has_post_thumbnail( $lesson_id ) ) {
2838
2839
   			// Get Featured Image
2840
   			$img_url = get_the_post_thumbnail( $lesson_id, array( $width, $height ), array( 'class' => 'woo-image thumbnail alignleft') );
2841
2842 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...
2843
2844
 			// Display Image Placeholder if none
2845
			if ( Sensei()->settings->settings[ 'placeholder_images_enable' ] ) {
2846
2847
                $img_url = apply_filters( 'sensei_lesson_placeholder_image_url', '<img src="http://placehold.it/' . $width . 'x' . $height . '" class="woo-image thumbnail alignleft" />' );
2848
2849
			} // End If Statement
2850
2851
		} // End If Statement
2852
2853
		$html .= '<a href="' . get_permalink( $lesson_id ) . '" title="' . esc_attr( get_post_field( 'post_title', $lesson_id ) ) . '">' . $img_url . '</a>';
2854
2855
		return $html;
2856
2857
	} // End lesson_image()
2858
2859
	/**
2860
	 * Returns the the lesson excerpt.
2861
	 *
2862
	 * @param WP_Post $lesson
2863
     * @param bool $add_p_tags should the excerpt be wrapped by calling wpautop()
2864
	 * @return string
2865
	 */
2866
	public static function lesson_excerpt( $lesson = null, $add_p_tags = true ) {
2867
		$html = '';
2868
		if ( is_a( $lesson, 'WP_Post' ) && 'lesson' == $lesson->post_type ) {
2869
2870
            $excerpt =  $lesson->post_excerpt;
2871
2872
            // if $add_p_tags true wrap with <p> else return the excerpt as is
2873
            $html =  $add_p_tags ? wpautop( $excerpt ) : $excerpt;
2874
2875
		}
2876
		return apply_filters( 'sensei_lesson_excerpt', $html );
2877
2878
	} // End lesson_excerpt()
2879
2880
    /**
2881
     * Returns the course for a given lesson
2882
     *
2883
     * @since 1.7.4
2884
     * @access public
2885
     *
2886
     * @param int $lesson_id
2887
     * @return int|bool $course_id or bool when nothing is found.
2888
     */
2889
     public function get_course_id( $lesson_id ){
2890
2891
         if( ! isset( $lesson_id ) || empty( $lesson_id )
2892
         ||  'lesson' != get_post_type( $lesson_id ) ){
2893
             return false;
2894
         }
2895
2896
         $lesson_course_id = get_post_meta( $lesson_id, '_lesson_course', true);
2897
2898
         // make sure the course id is valid
2899
         if( empty( $lesson_course_id )
2900
             || is_array( $lesson_course_id )
2901
             || intval( $lesson_course_id ) < 1
2902
             || 'course' != get_post_type( $lesson_course_id ) ){
2903
2904
             return false;
2905
2906
         }
2907
2908
         return $lesson_course_id;
2909
2910
     }// en get_course_id
2911
2912
    /**
2913
     * Add the admin all lessons screen edit options.
2914
     *
2915
     * The fields in this function work for both quick and bulk edit. The ID attributes is used
2916
     * by bulk edit javascript in the front end to retrieve the new values set byt the user. Then
2917
     * name attribute is will be used by the quick edit and submitted via standard POST. This
2918
     * will use this classes save_post_meta function to save the new field data.
2919
     *
2920
     * @hooked quick_edit_custom_box
2921
     * @hooked bulk_edit_custom_box
2922
     *
2923
     * @since 1.8.0
2924
     *
2925
     * @param string $column_name
2926
     * @param string $post_type
2927
     * @return void
2928
     */
2929
    public function all_lessons_edit_fields( $column_name, $post_type ) {
2930
2931
        // only show these options ont he lesson post type edit screen
2932
        if( 'lesson' != $post_type || 'lesson-course' != $column_name ){
2933
            return;
2934
        }
2935
2936
        ?>
2937
        <fieldset class="sensei-edit-field-set inline-edit-lesson">
2938
            <div class="sensei-inline-edit-col column-<?php echo $column_name ?>">
2939
                    <?php
2940
                    echo '<h4>' . __('Lesson Information', 'woothemes-sensei') . '</h4>';
2941
                    // create a nonce field to be  used as a security measure when saving the data
2942
                    wp_nonce_field( 'bulk-edit-lessons', '_edit_lessons_nonce' );
2943
                    wp_nonce_field( 'sensei-save-post-meta','woo_' . $this->token . '_nonce'  );
2944
2945
                    // unchanged option - we need this in because
2946
                    // the default option in bulk edit should not be empty. If it is
2947
                    // the user will erase data they didn't want to touch.
2948
                    $no_change_text = '-- ' . __('No Change', 'woothemes-sensei') . ' --';
2949
2950
                    //
2951
                    //course selection
2952
                    //
2953
                    $courses =  WooThemes_Sensei_Course::get_all_courses();
2954
                    $course_options = array();
2955
                    if ( count( $courses ) > 0 ) {
2956
                        foreach ($courses as $course ){
2957
                            $course_options[ $course->ID ] = get_the_title( $course->ID );
2958
                        }
2959
                    }
2960
                    //pre-append the no change option
2961
                    $course_options['-1']=  $no_change_text;
2962
                    $course_attributes = array( 'name'=> 'lesson_course', 'id'=>'sensei-edit-lesson-course' , 'class'=>' ' );
2963
                    $course_field =  WooThemes_Sensei_Utils::generate_drop_down( '-1', $course_options, $course_attributes );
2964
                    echo $this->generate_all_lessons_edit_field( __('Lesson Course', 'woothemes-sensei'),   $course_field  );
2965
2966
                    //
2967
                    // lesson complexity selection
2968
                    //
2969
                    $lesson_complexities =  $this->lesson_complexities();
2970
                    //pre-append the no change option
2971
                    $lesson_complexities['-1']=  $no_change_text;
2972
                    $complexity_dropdown_attributes = array( 'name'=> 'lesson_complexity', 'id'=>'sensei-edit-lesson-complexity' , 'class'=>' ');
2973
                    $complexity_filed =  WooThemes_Sensei_Utils::generate_drop_down( '-1', $lesson_complexities, $complexity_dropdown_attributes );
2974
                    echo $this->generate_all_lessons_edit_field( __('Lesson Complexity', 'woothemes-sensei'),   $complexity_filed  );
2975
2976
                    ?>
2977
2978
                    <h4><?php _e('Quiz Settings', 'woothemes-sensei'); ?> </h4>
2979
2980
                    <?php
2981
2982
                    //
2983
                    // Lesson require pass to complete
2984
                    //
2985
                    $pass_required_options = array(
2986
                        '-1' => $no_change_text,
2987
                         '0' => __('No','woothemes'),
2988
                         '1' => __('Yes','woothemes'),
2989
                    );
2990
2991
                    $pass_required_select_attributes = array( 'name'=> 'pass_required',
2992
                                                                'id'=> 'sensei-edit-lesson-pass-required',
2993
                                                                'class'=>' '   );
2994
                    $require_pass_field =  WooThemes_Sensei_Utils::generate_drop_down( '-1', $pass_required_options, $pass_required_select_attributes, false );
2995
                    echo $this->generate_all_lessons_edit_field( __('Pass required', 'woothemes-sensei'),   $require_pass_field  );
2996
2997
                    //
2998
                    // Quiz pass percentage
2999
                    //
3000
                    $quiz_pass_percentage_field = '<input name="quiz_passmark" id="sensei-edit-quiz-pass-percentage" type="number" />';
3001
                    echo $this->generate_all_lessons_edit_field( __('Pass Percentage', 'woothemes-sensei'), $quiz_pass_percentage_field  );
3002
3003
                    //
3004
                    // Enable quiz reset button
3005
                    //
3006
                    $quiz_reset_select__options = array(
3007
                        '-1' => $no_change_text,
3008
                        '0' => __('No','woothemes'),
3009
                        '1' => __('Yes','woothemes'),
3010
                    );
3011
                    $quiz_reset_name_id = 'sensei-edit-enable-quiz-reset';
3012
                    $quiz_reset_select_attributes = array( 'name'=> 'enable_quiz_reset', 'id'=>$quiz_reset_name_id, 'class'=>' ' );
3013
                    $quiz_reset_field =  WooThemes_Sensei_Utils::generate_drop_down( '-1', $quiz_reset_select__options, $quiz_reset_select_attributes, false );
3014
                    echo $this->generate_all_lessons_edit_field( __('Enable quiz reset button', 'woothemes-sensei'), $quiz_reset_field  );
3015
3016
                    ?>
3017
            </div>
3018
        </fieldset>
3019
    <?php
3020
    }// all_lessons_edit_fields
3021
3022
    /**
3023
     * Create the html for the edit field
3024
     *
3025
     * Wraps the passed in field and title combination with the correct html.
3026
     *
3027
     * @since 1.8.0
3028
     *
3029
     * @param string $title that will stand to the left of the field.
3030
     * @param string $field type markup for the field that must be wrapped.
3031
     * @return string $field_html
3032
     */
3033
    public function generate_all_lessons_edit_field( $title  ,$field ){
3034
3035
        $html = '';
0 ignored issues
show
Unused Code introduced by
$html 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...
3036
        $html = '<div class="inline-edit-group" >';
3037
        $html .=  '<span class="title">'. $title .'</span> ';
3038
        $html .= '<span class="input-text-wrap">';
3039
        $html .= $field;
3040
        $html .= '</span>';
3041
        $html .= '</label></div>';
3042
3043
        return $html ;
3044
3045
    }//end generate_all_lessons_edit_field
3046
3047
    /**
3048
     * Respond to the ajax call from the bulk edit save function. This comes
3049
     * from the admin all lesson screen.
3050
     *
3051
     * @since 1.8.0
3052
     * @return void
3053
     */
3054
    function save_all_lessons_edit_fields() {
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...
3055
3056
        // verify all the data before attempting to save
3057
        if( ! isset( $_POST['security'] ) || ! check_ajax_referer( 'bulk-edit-lessons', 'security' )
3058
            ||  empty( $_POST[ 'post_ids' ] )  || ! is_array( $_POST[ 'post_ids' ] ) ) {
3059
            die();
3060
        }
3061
3062
        // get our variables
3063
        $new_course = sanitize_text_field(  $_POST['sensei_edit_lesson_course'] );
3064
        $new_complexity = sanitize_text_field(  $_POST['sensei_edit_complexity'] );
3065
        $new_pass_required = sanitize_text_field(  $_POST['sensei_edit_pass_required'] );
3066
        $new_pass_percentage = sanitize_text_field(  $_POST['sensei_edit_pass_percentage'] );
3067
        $new_enable_quiz_reset = sanitize_text_field(  $_POST['sensei_edit_enable_quiz_reset'] );
3068
        // store the values for all selected posts
3069
        foreach( $_POST[ 'post_ids' ] as $lesson_id ) {
3070
3071
            // get the quiz id needed for the quiz meta
3072
            $quiz_id = Sensei()->lesson->lesson_quizzes( $lesson_id );
3073
3074
            // do not save the items if the value is -1 as this
3075
            // means it was not changed
3076
3077
            // update lesson course
3078
            if( -1 != $new_course ){
3079
                update_post_meta( $lesson_id, '_lesson_course', $new_course );
3080
            }
3081
            // update lesson complexity
3082
            if( -1 != $new_complexity ){
3083
                update_post_meta( $lesson_id, '_lesson_complexity', $new_complexity );
3084
            }
3085
3086
            // Quiz Related settings
3087
            if( isset( $quiz_id) && 0 < intval( $quiz_id ) ) {
3088
3089
                // update pass required
3090
                if (-1 != $new_pass_required) {
3091
3092
                    $checked = $new_pass_required  ? 'on' : '';
3093
                    update_post_meta($quiz_id, '_pass_required', $checked);
3094
                    unset( $checked );
3095
                }
3096
3097
                // update pass percentage
3098
                if( !empty( $new_pass_percentage) && is_numeric( $new_pass_percentage ) ){
3099
3100
                        update_post_meta($quiz_id, '_quiz_passmark', $new_pass_percentage);
3101
3102
                }
3103
3104
                //
3105
                // update enable quiz reset
3106
                //
3107
                if (-1 != $new_enable_quiz_reset ) {
3108
3109
                    $checked = $new_enable_quiz_reset ? 'on' : ''  ;
3110
                    update_post_meta($quiz_id, '_enable_quiz_reset', $checked);
3111
                    unset( $checked );
3112
3113
                }
3114
3115
3116
            } // end if quiz
3117
3118
        }// end for each
3119
3120
        die();
3121
3122
    } // end save_all_lessons_edit_fields
3123
3124
    /**
3125
     * Loading the quick edit fields defaults.
3126
     *
3127
     * This function will localise the default values along with the script that will
3128
     * add these values to the inputs.
3129
     *
3130
     * NOTE: this function runs for each row in the edit column
3131
     *
3132
     * @since 1.8.0
3133
     * @return void
3134
     */
3135
    public function set_quick_edit_admin_defaults( $column_name, $post_id ){
3136
3137
        if( 'lesson-course' != $column_name ){
3138
            return;
3139
        }
3140
        // load the script
3141
        $suffix = defined( 'SCRIPT_DEBUG') && SCRIPT_DEBUG ? '' : '.min';
3142
        wp_enqueue_script( 'sensei-lesson-quick-edit', Sensei()->plugin_url . 'assets/js/admin/lesson-quick-edit' . $suffix . '.js', array( 'jquery' ), Sensei()->version, true );
3143
3144
        // setup the values for all meta fields
3145
        $data = array();
3146
        foreach( $this->meta_fields as $field ){
3147
3148
            $data[$field] =  get_post_meta( $post_id, '_'.$field, true );
3149
3150
        }
3151
        // add quiz meta fields
3152
        $quiz_id = Sensei()->lesson->lesson_quizzes( $post_id );
3153
        foreach( Sensei()->quiz->meta_fields as $field ){
3154
3155
            $data[$field] =  get_post_meta( $quiz_id, '_'.$field, true );
3156
3157
        }
3158
3159
        wp_localize_script( 'sensei-lesson-quick-edit', 'sensei_quick_edit_'.$post_id, $data );
3160
3161
    }// end quick edit admin defaults
3162
3163
    /**
3164
     * Filter the classes for lessons on the single course page.
3165
     *
3166
     * Adds the nesecary classes depending on the user data
3167
     *
3168
     * @since 1.9.0
3169
     * @param array $classes
3170
     * @return array $classes
3171
     */
3172
    public static function single_course_lessons_classes( $classes ){
3173
3174
        if(  is_singular('course') ){
3175
3176
            global $post;
3177
            $course_id = $post->ID;
3178
3179
            $lesson_classes = array( 'course', 'post' );
3180
            if ( is_user_logged_in() ) {
3181
3182
                // Check if Lesson is complete
3183
                $single_lesson_complete = WooThemes_Sensei_Utils::user_completed_lesson( get_the_ID(), get_current_user_id() );
3184
                if ( $single_lesson_complete ) {
3185
3186
                    $lesson_classes[] = 'lesson-completed';
3187
3188
                } // End If Statement
3189
3190
            } // End If Statement
3191
3192
            $is_user_taking_course = WooThemes_Sensei_Utils::user_started_course( $course_id, get_current_user_id() );
3193
            if (  WooThemes_Sensei_Utils::is_preview_lesson( get_the_ID() ) && !$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...
3194
3195
                $lesson_classes[] = 'lesson-preview';
3196
3197
            }
3198
3199
            $classes = array_merge( $classes, $lesson_classes  );
3200
3201
        }
3202
3203
        return $classes;
3204
3205
    }// end single_course_lessons_classes
3206
3207
    /**
3208
     * Output the lesson meta for the given lesson
3209
     *
3210
     * @since 1.9.0
3211
     * @param $lesson_id
3212
     */
3213
    public static function the_lesson_meta( $lesson_id ){
3214
3215
        global $wp_query;
3216
        $loop_lesson_number = $wp_query->current_post + 1;
3217
3218
        $course_id = Sensei()->lesson->get_course_id( $lesson_id );
3219
        $single_lesson_complete = false;
3220
        $is_user_taking_course = WooThemes_Sensei_Utils::user_started_course( $course_id, get_current_user_id() );
0 ignored issues
show
Bug introduced by
It seems like $course_id defined by Sensei()->lesson->get_course_id($lesson_id) on line 3218 can also be of type boolean; however, Sensei_Utils::user_started_course() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
3221
3222
        // Get Lesson data
3223
        $complexity_array = Sensei()->lesson->lesson_complexities();
3224
3225
        $lesson_complexity = get_post_meta( $lesson_id, '_lesson_complexity', true );
3226
        if ( '' != $lesson_complexity ) {
3227
3228
            $lesson_complexity = $complexity_array[$lesson_complexity];
3229
3230
        }
3231
        $user_info = get_userdata( absint( get_post()->post_author ) );
3232
        $is_preview = WooThemes_Sensei_Utils::is_preview_lesson( $lesson_id);
3233
        $preview_label = '';
3234
        if ( $is_preview && !$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...
3235
3236
            $preview_label = Sensei()->frontend->sensei_lesson_preview_title_text( $lesson_id);
3237
            $preview_label = '<span class="preview-heading">' . $preview_label . '</span>';
3238
3239
        }
3240
3241
3242
        $count_markup= '';
3243
        /**
3244
         * Filter for if you want the $lesson_count to show next to the lesson.
3245
         *
3246
         * @since 1.0
3247
         * @param bool default false.
3248
         */
3249
        if( apply_filters( 'sensei_show_lesson_numbers', false ) ) {
3250
3251
            $count_markup =  '<span class="lesson-number">' . $loop_lesson_number. '</span>';
3252
3253
        }
3254
3255
        $heading_link_title = sprintf( __( 'Start %s', 'woothemes-sensei' ), get_the_title( $lesson_id ) );
3256
3257
        ?>
3258
        <header>
3259
            <h2>
3260
                <a href="<?php echo esc_url_raw( get_permalink( $lesson_id ) ) ?>"
3261
                   title="<?php esc_attr_e( $heading_link_title ) ?>" >
3262
                    <?php echo $count_markup. get_the_title( $lesson_id ) . $preview_label; ?>
3263
                </a>
3264
            </h2>
3265
3266
            <p class="lesson-meta">
3267
3268
                <?php
3269
3270
                $meta_html = '';
3271
                $user_lesson_status = WooThemes_Sensei_Utils::user_lesson_status( get_the_ID(), get_current_user_id() );
3272
3273
                $lesson_length = get_post_meta( $lesson_id, '_lesson_length', true );
3274 View Code Duplication
                if ( '' != $lesson_length ) {
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...
3275
3276
                    $meta_html .= '<span class="lesson-length">' .  __( 'Length: ', 'woothemes-sensei' ) . $lesson_length . __( ' minutes', 'woothemes-sensei' ) . '</span>';
3277
3278
                }
3279
3280
                if ( Sensei()->settings->get( 'lesson_author' ) ) {
3281
3282
                    $meta_html .= '<span class="lesson-author">' .  __( 'Author: ', 'woothemes-sensei' ) . '<a href="' . get_author_posts_url( absint( get_post()->post_author ) ) . '" title="' . esc_attr( $user_info->display_name ) . '">' . esc_html( $user_info->display_name ) . '</a></span>';
3283
3284
                } // End If Statement
3285
                if ( '' != $lesson_complexity ) {
3286
3287
                    $meta_html .= '<span class="lesson-complexity">' .  __( 'Complexity: ', 'woothemes-sensei' ) . $lesson_complexity .'</span>';
3288
3289
                }
3290
3291 View Code Duplication
                if ( $single_lesson_complete ) {
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...
3292
3293
                    $meta_html .= '<span class="lesson-status complete">' .__( 'Complete', 'woothemes-sensei' ) .'</span>';
3294
3295
                } elseif ( $user_lesson_status ) {
3296
3297
                    $meta_html .= '<span class="lesson-status in-progress">' . __( 'In Progress', 'woothemes-sensei' ) .'</span>';
3298
3299
                } // End If Statement
3300
3301
                echo $meta_html;
3302
3303
                ?>
3304
3305
            </p> <!-- lesson meta -->
3306
3307
        </header>
3308
3309
    <?php
3310
3311
    } // end the_lesson_meta
3312
3313
    /**
3314
     * Output the lessons thumbnail
3315
     *
3316
     * 1.9.0
3317
     *
3318
     * @param $lesson_id
3319
     */
3320
    public static function the_lesson_thumbnail( $lesson_id ){
3321
3322
        if( empty( $lesson_id ) ){
3323
3324
            $lesson_id = get_the_ID();
3325
3326
        }
3327
3328
        if( 'lesson' != get_post_type( $lesson_id ) ){
3329
            return;
3330
        }
3331
3332
        echo Sensei()->lesson->lesson_image( $lesson_id );
3333
    }
3334
3335
3336
    /**
3337
     * Alter the sensei lesson excerpt.
3338
     *
3339
     * @since 1.9.0
3340
     * @param string $excerpt
3341
     * @return string $excerpt
3342
     */
3343
    public static function alter_the_lesson_excerpt( $excerpt ) {
3344
3345
        if ('lesson' == get_post_type(get_the_ID())){
3346
3347
            // remove this hooks to avoid an infinite loop.
3348
            remove_filter( 'get_the_excerpt', array( 'WooThemes_Sensei_Lesson','alter_the_lesson_excerpt') );
3349
3350
            return WooThemes_Sensei_Lesson::lesson_excerpt( get_post( get_the_ID() ) );
3351
        }
3352
3353
        return $excerpt;
3354
3355
    }// end the_lesson_excerpt
3356
3357
    /**
3358
     * Returns the lesson prerequisite for the given lesson id.
3359
     *
3360
     * @since 1.9.0
3361
     *
3362
     * @param $current_lesson_id
3363
     * @return mixed | bool | int $prerequisite_lesson_id or false
3364
     */
3365
    public static function get_lesson_prerequisite_id( $current_lesson_id  ){
3366
3367
        $prerequisite_lesson_id = get_post_meta( $current_lesson_id , '_lesson_prerequisite', true );
3368
3369
        // set ti to false if not a valid prerequisite lesson id
3370
        if(  empty( $prerequisite_lesson_id )
3371
            || 'lesson' != get_post_type( $prerequisite_lesson_id )
3372
            || $prerequisite_lesson_id == $current_lesson_id  ) {
3373
3374
            $prerequisite_lesson_id = false;
3375
3376
        }
3377
3378
        return apply_filters( 'sensei_lesson_prerequisite', $prerequisite_lesson_id, $current_lesson_id );
3379
3380
    }
3381
3382
    /**
3383
     * This function requires that you pass in the lesson you would like to check for
3384
     * a pre-requisite and not the pre-requisite. It will check if the
3385
     * lesson has a pre-requiste and then check if it is completed.
3386
     *
3387
     * @since 1.9.0
3388
     *
3389
     * @param $lesson_id
3390
     * @param $user_id
3391
     * @return bool
3392
     */
3393
    public  static function is_prerequisite_complete( $lesson_id, $user_id  ){
3394
3395 View Code Duplication
        if( empty( $lesson_id ) || empty( $user_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...
3396
        || 'lesson' != get_post_type( $lesson_id )
3397
        ||  ! is_a( get_user_by( 'id', $user_id ), 'WP_User' )){
3398
3399
            return false;
3400
3401
        }
3402
3403
        $pre_requisite_id = (string) self::get_lesson_prerequisite_id( $lesson_id );
3404
3405
        // not a valid pre-requisite so pre-requisite is completed
3406
        if( 'lesson' != get_post_type( $pre_requisite_id )
3407
            || ! is_numeric( $pre_requisite_id ) ){
3408
3409
            return true;
3410
3411
        }
3412
3413
        return  Sensei_Utils::user_completed_lesson( $pre_requisite_id, $user_id );
3414
3415
    }// end is_prerequisite_complete
3416
3417
    /**
3418
     * Show the user not taking course message if it is the case
3419
     *
3420
     * @since 1.9.0
3421
     */
3422
    public  static function user_not_taking_course_message(){
3423
3424
        $lesson_id = get_the_ID();
3425
3426
        if( 'lesson' != get_post_type( $lesson_id ) ){
3427
            return;
3428
        }
3429
3430
        $is_preview = WooThemes_Sensei_Utils::is_preview_lesson( $lesson_id );
3431
        $pre_requisite_complete = self::is_prerequisite_complete( $lesson_id , get_current_user_id() );
3432
        $lesson_course_id = get_post_meta( $lesson_id, '_lesson_course', true );
3433
        $user_taking_course = WooThemes_Sensei_Utils::user_started_course( $lesson_course_id, get_current_user_id() );
3434
3435
        if ( $pre_requisite_complete && $is_preview && !$user_taking_course ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $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...
3436
            ?>
3437
3438
            <div class="sensei-message alert">
3439
                <?php echo Sensei()->permissions_message['message']; ?>
3440
            </div>
3441
3442
            <?php
3443
3444
        }// end if
3445
3446
    } // end user_not_taking_course_message
3447
3448
    /**
3449
     * Outputs the lessons course signup lingk
3450
     *
3451
     * This hook runs inside the single lesson page.
3452
     *
3453
     * @since 1.9.0
3454
     */
3455
    public static function course_signup_link( ){
3456
3457
        $course_id =  Sensei()->lesson->get_course_id( get_the_ID() );
3458
3459
        if ( empty( $course_id ) || 'course' != get_post_type( $course_id ) || sensei_all_access() ) {
3460
3461
            return;
3462
3463
        }
3464
        ?>
3465
3466
        <section class="course-signup lesson-meta">
3467
3468
            <?php
3469
            $wc_post_id = (int) get_post_meta( $course_id, '_course_woocommerce_product', true );
3470
3471
            if ( Sensei_WC::is_woocommerce_active() && ( 0 < $wc_post_id ) ) {
3472
3473
                global $current_user;
3474
                if( is_user_logged_in() ) {
3475
                    wp_get_current_user();
3476
3477
                    $course_purchased = WooThemes_Sensei_Utils::sensei_customer_bought_product( $current_user->user_email, $current_user->ID, $wc_post_id );
3478
3479
                    if( $course_purchased ) {
3480
3481
                        $prereq_course_id = get_post_meta( $course_id, '_course_prerequisite',true );
3482
                        $course_link = '<a href="' . esc_url( get_permalink( $prereq_course_id ) ) . '" title="' . esc_attr( get_the_title( $prereq_course_id ) ) . '">' . __( 'the previous course', 'woothemes-sensei' )  . '</a>';
3483
                        ?>
3484
                            <div class="sensei-message info">
3485
3486
                                <?php  echo sprintf( __( 'Please complete %1$s before starting the lesson.', 'woothemes-sensei' ), $course_link ); ?>
3487
3488
                            </div>
3489
3490 View Code Duplication
                    <?php } 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...
3491
3492
                        <div class="sensei-message info">
3493
3494
                            <?php
3495
                            $course_link = '<a href="' . esc_url( get_permalink( $course_id ) )
3496
                                            . '"title="' . __( 'Sign Up', 'woothemes-sensei' )
3497
                                            . '">' . __( 'course', 'woothemes-sensei' )
3498
                                            . '</a>';
3499
3500
                            echo  sprintf( __( 'Please purchase the %1$s before starting the lesson.', 'woothemes-sensei' ), $course_link );
3501
3502
                            ?>
3503
3504
                        </div>
3505
                    <?php } ?>
3506
3507 View Code Duplication
                <?php } 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...
3508
3509
                    <div class="sensei-message info"><?php echo sprintf( __( 'Please purchase the %1$s before starting the lesson.', 'woothemes-sensei' ), '<a href="' . esc_url( get_permalink( $course_id ) ) . '" title="' . __( 'Sign Up', 'woothemes-sensei' )  . '">' . __( 'course', 'woothemes-sensei' ) . '</a>' ); ?></div>
3510
3511
                <?php } ?>
3512
3513
            <?php } else { ?>
3514
3515
            <?php if( ! Sensei_Utils::user_started_course( $course_id, get_current_user_id() ) ) : ?>
0 ignored issues
show
Bug introduced by
It seems like $course_id defined by Sensei()->lesson->get_course_id(get_the_ID()) on line 3457 can also be of type boolean; however, Sensei_Utils::user_started_course() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Bug Best Practice introduced by
The expression \Sensei_Utils::user_star... get_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...
3516
3517
                <div class="sensei-message info">
3518
                    <?php
3519
                    $course_link =  '<a href="'
3520
                                        . esc_url( get_permalink( $course_id ) )
3521
                                        . '" title="' . __( 'Sign Up', 'woothemes-sensei' )
3522
                                        . '">' . __( 'course', 'woothemes-sensei' )
3523
                                    . '</a>';
3524
3525
                    echo sprintf( __( 'Please sign up for the %1$s before starting the lesson.', 'woothemes-sensei' ),  $course_link );
3526
                    ?>
3527
                </div>
3528
3529
            <?php endif; ?>
3530
3531
            <?php } // End If Statement ?>
3532
3533
        </section>
3534
3535
        <?php
3536
    }// end course_signup_link
3537
3538
    /**
3539
     * Show a message telling the user to complete the previous message if they haven't done so yet
3540
     *
3541
     * @since 1.9.0
3542
     */
3543
    public  static function prerequisite_complete_message(){
3544
3545
        $lesson_prerequisite =  WooThemes_Sensei_Lesson::get_lesson_prerequisite_id( get_the_ID() );
3546
        $lesson_has_pre_requisite = $lesson_prerequisite > 0;
3547
        if ( ! WooThemes_Sensei_Lesson::is_prerequisite_complete(  get_the_ID(), get_current_user_id() ) && $lesson_has_pre_requisite ) {
3548
3549
            $prerequisite_lesson_link  = '<a href="' . esc_url( get_permalink( $lesson_prerequisite ) ) . '" title="' . esc_attr(  sprintf( __( 'You must first complete: %1$s', 'woothemes-sensei' ), get_the_title( $lesson_prerequisite ) ) ) . '">' . get_the_title( $lesson_prerequisite ). '</a>';
3550
            echo sprintf( __( 'You must first complete %1$s before viewing this Lesson', 'woothemes-sensei' ), $prerequisite_lesson_link );
3551
3552
        }
3553
3554
    }
3555
3556
    /**
3557
     * Deprecate the sensei_lesson_archive_header hook but keep it
3558
     * active for backwards compatibility.
3559
     *
3560
     * @deprecated since 1.9.0
3561
     */
3562
    public static function deprecate_sensei_lesson_archive_header_hook(){
3563
3564
        sensei_do_deprecated_action('sensei_lesson_archive_header', '1.9.0', 'sensei_loop_lesson_inside_before');
3565
3566
    }
3567
3568
    /**
3569
     * Outputs the the lesson archive header.
3570
     *
3571
     * @since  1.9.0
3572
     * @return void
3573
     */
3574
    public function the_archive_header( ) {
3575
3576
        $before_html = '<header class="archive-header"><h1>';
3577
        $after_html = '</h1></header>';
3578
        $html = $before_html .  __( 'Lessons Archive', 'woothemes-sensei' ) . $after_html;
3579
3580
        echo apply_filters( 'sensei_lesson_archive_title', $html );
3581
3582
    } // sensei_course_archive_header()
3583
3584
    /**
3585
     * Output the title for the single lesson page
3586
     *
3587
     * @global $post
3588
     * @since 1.9.0
3589
     */
3590
    public static function the_title(){
3591
3592
        global $post;
3593
3594
        ?>
3595
        <header>
3596
3597
            <h1>
3598
3599
                <?php
3600
                /**
3601
                 * Filter documented in class-sensei-messages.php the_title
3602
                 */
3603
                echo apply_filters( 'sensei_single_title', get_the_title( $post ), $post->post_type );
3604
                ?>
3605
3606
            </h1>
3607
3608
        </header>
3609
3610
        <?php
3611
3612
    }//the_title
3613
3614
    /**
3615
     * Flush the rewrite rules for a lesson post type
3616
     *
3617
     * @since 1.9.0
3618
     *
3619
     * @param $post_id
3620
     */
3621 View Code Duplication
    public static function flush_rewrite_rules( $post_id ){
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
3622
3623
        if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE){
3624
3625
            return;
3626
3627
        }
3628
3629
3630
        if( 'lesson' == get_post_type( $post_id )  ){
3631
3632
            Sensei()->initiate_rewrite_rules_flush();
3633
3634
        }
3635
3636
    }
3637
3638
    /**
3639
     * Output the quiz specific buttons and messaging on the single lesson page
3640
     *
3641
     *
3642
     * @since 1.0.0 moved here from frontend class
3643
     *
3644
     * @param int $lesson_id
3645
     * @param int $user_id
3646
     */
3647
    public static function footer_quiz_call_to_action( $lesson_id = 0, $user_id = 0 ) {
3648
3649
3650
        $lesson_id                 =  empty( $lesson_id ) ?  get_the_ID() : $lesson_id;
3651
        $user_id                   = empty( $lesson_id ) ?  get_current_user_id() : $user_id;
3652
        $lesson_prerequisite       = (int) get_post_meta( $lesson_id, '_lesson_prerequisite', true );
3653
        $lesson_course_id          = (int) get_post_meta( $lesson_id, '_lesson_course', true );
0 ignored issues
show
Unused Code introduced by
$lesson_course_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...
3654
        $quiz_id                   = Sensei()->lesson->lesson_quizzes( $lesson_id );
3655
        $has_user_completed_lesson = WooThemes_Sensei_Utils::user_completed_lesson( intval( $lesson_id ), $user_id );
3656
        $show_actions              = is_user_logged_in() ? true : false;
3657
3658
        if( intval( $lesson_prerequisite ) > 0 ) {
3659
3660
            // If the user hasn't completed the prereq then hide the current actions
3661
            $show_actions = WooThemes_Sensei_Utils::user_completed_lesson( $lesson_prerequisite, $user_id );
3662
3663
        }
3664
        ?>
3665
3666
        <footer>
3667
3668
            <?php
3669
            if( $show_actions && $quiz_id && Sensei()->access_settings() ) {
3670
3671
                $has_quiz_questions = get_post_meta( $lesson_id, '_quiz_has_questions', true );
3672
                if( $has_quiz_questions ) {
3673
                    ?>
3674
3675
                    <p>
3676
3677
                        <a class="button"
3678
                           href="<?php echo esc_url_raw( get_permalink( $quiz_id ) ); ?>"
3679
                           title="<?php _e( 'View the Lesson Quiz', 'woothemes-sensei'  ); ?>">
3680
3681
                            <?php  _e( 'View the Lesson Quiz', 'woothemes-sensei' ); ?>
3682
3683
                        </a>
3684
3685
                    </p>
3686
3687
                    <?php
3688
                }
3689
3690
            } // End If Statement
3691
3692
            if ( $show_actions && ! $has_user_completed_lesson ) {
3693
3694
                sensei_complete_lesson_button();
3695
3696
            } elseif( $show_actions ) {
3697
3698
                sensei_reset_lesson_button();
3699
3700
            } // End If Statement
3701
            ?>
3702
3703
        </footer>
3704
3705
        <?php
3706
    } // End sensei_lesson_quiz_meta()
3707
3708
    /**
3709
     * Show the lesson comments. This should be used in the loop.
3710
     *
3711
     * @since 1.9.0
3712
     */
3713
    public static function output_comments(){
3714
3715
        if( ! is_user_logged_in() ){
3716
            return;
3717
        }
3718
3719
        $pre_requisite_complete = Sensei()->lesson->is_prerequisite_complete( get_the_ID(), get_current_user_id() );
3720
        $course_id = Sensei()->lesson->get_course_id( get_the_ID() );
3721
        $allow_comments = Sensei()->settings->settings[ 'lesson_comments' ];
3722
        $user_taking_course = Sensei_Utils::user_started_course($course_id );
0 ignored issues
show
Bug introduced by
It seems like $course_id defined by Sensei()->lesson->get_course_id(get_the_ID()) on line 3720 can also be of type boolean; however, Sensei_Utils::user_started_course() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
3723
3724
        $lesson_allow_comments = $allow_comments && $pre_requisite_complete  && $user_taking_course;
0 ignored issues
show
Bug Best Practice introduced by
The expression $user_taking_course of type false|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
3725
3726
        if (  $lesson_allow_comments || is_singular( 'sensei_message' ) ) {
3727
3728
            comments_template();
3729
3730
        } // End If Statement
3731
3732
    } //output_comments
3733
3734
    /**
3735
     * Display the leeson quiz status if it should be shown
3736
     *
3737
     * @param int $lesson_id defaults to the global lesson id
3738
     * @param int $user_id defaults to the current user id
3739
     *
3740
     * @since 1.9.0
3741
     */
3742
    public static function user_lesson_quiz_status_message( $lesson_id = 0, $user_id = 0){
3743
3744
        $lesson_id                 =  empty( $lesson_id ) ?  get_the_ID() : $lesson_id;
3745
        $user_id                   = empty( $lesson_id ) ?  get_current_user_id() : $user_id;
3746
        $lesson_course_id          = (int) get_post_meta( $lesson_id, '_lesson_course', true );
3747
        $quiz_id                   = Sensei()->lesson->lesson_quizzes( $lesson_id );
3748
        $has_user_completed_lesson = WooThemes_Sensei_Utils::user_completed_lesson( intval( $lesson_id ), $user_id );
3749
3750
3751
        if ( $quiz_id && is_user_logged_in()
3752
            && WooThemes_Sensei_Utils::user_started_course( $lesson_course_id, $user_id ) ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression \WooThemes_Sensei_Utils:...on_course_id, $user_id) of type false|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
3753
3754
            $no_quiz_count = 0;
0 ignored issues
show
Unused Code introduced by
$no_quiz_count 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...
3755
            $has_quiz_questions = get_post_meta( $lesson_id, '_quiz_has_questions', true );
3756
3757
            // Display lesson quiz status message
3758
            if ( $has_user_completed_lesson || $has_quiz_questions ) {
3759
                $status = WooThemes_Sensei_Utils::sensei_user_quiz_status_message( $lesson_id, $user_id, true );
3760
                echo '<div class="sensei-message ' . $status['box_class'] . '">' . $status['message'] . '</div>';
3761
                if( $has_quiz_questions ) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
3762
                   // echo $status['extra'];
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% 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...
3763
                } // End If Statement
3764
            } // End If Statement
3765
3766
        }
3767
3768
    }
3769
3770
} // End Class
3771
3772
/**
3773
 * Class WooThemes_Sensei_Lesson
3774
 * for backward compatibility
3775
 * @since 1.9.0
3776
 */
3777
class WooThemes_Sensei_Lesson extends Sensei_Lesson{}
3778