PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 1.4.3
Tutor LMS – eLearning and online course solution v1.4.3
4.0.1 4.0.0 3.9.15 3.9.14 3.9.13 3.9.12 3.9.11 trunk 1.0.0 1.0.0-alpha 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.2.0 1.2.1 1.2.11 1.2.12 1.2.13 1.2.20 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9 1.8.0 1.8.1 1.8.10 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9.0 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.14 1.9.15 1.9.16 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1 2.0.10 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1.0 2.1.1 2.1.10 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.3.0 2.4.0 2.5.0 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 3.0.0 3.0.1 3.0.2 3.1.0 3.2.0 3.2.1 3.2.2 3.2.3 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.7.0 3.7.1 3.7.2 3.7.3 3.7.4 3.8.0 3.8.1 3.8.2 3.8.3 3.9.0 3.9.1 3.9.10 3.9.2 3.9.3 3.9.4 3.9.5 3.9.6 3.9.7 3.9.8 3.9.9
tutor / classes / Quiz.php
tutor / classes Last commit date
Addons.php 6 years ago Admin.php 6 years ago Ajax.php 6 years ago Assets.php 6 years ago Course.php 6 years ago Course_Settings_Tabs.php 6 years ago Course_Widget.php 6 years ago Dashboard.php 6 years ago Email.php 6 years ago FormHandler.php 6 years ago Gutenberg.php 6 years ago Instructor.php 6 years ago Instructors_List.php 6 years ago Lesson.php 6 years ago Options.php 6 years ago Post_types.php 6 years ago Q_and_A.php 6 years ago Question_Answers_List.php 6 years ago Quiz.php 6 years ago Quiz_Attempts_List.php 6 years ago Rewrite_Rules.php 6 years ago Shortcode.php 6 years ago Student.php 6 years ago Students_List.php 6 years ago Taxonomies.php 6 years ago Template.php 6 years ago Theme_Compatibility.php 6 years ago Tools.php 6 years ago Tutor.php 6 years ago TutorEDD.php 6 years ago Tutor_Base.php 6 years ago Tutor_List_Table.php 6 years ago Upgrader.php 6 years ago User.php 6 years ago Utils.php 6 years ago Video_Stream.php 6 years ago Withdraw.php 6 years ago Withdraw_Requests_List.php 6 years ago WooCommerce.php 6 years ago
Quiz.php
990 lines
1 <?php
2
3 /**
4 * Quize class
5 *
6 * @author: themeum
7 * @author_uri: https://themeum.com
8 * @package Tutor
9 * @since v.1.0.0
10 */
11
12 namespace TUTOR;
13
14 if ( ! defined( 'ABSPATH' ) )
15 exit;
16
17 class Quiz {
18
19 public function __construct() {
20 add_action('save_post_tutor_quiz', array($this, 'save_quiz_meta'));
21
22 add_action('wp_ajax_tutor_load_quiz_builder_modal', array($this, 'tutor_load_quiz_builder_modal'));
23 add_action('wp_ajax_remove_quiz_from_post', array($this, 'remove_quiz_from_post'));
24
25 add_action('wp_ajax_tutor_quiz_timeout', array($this, 'tutor_quiz_timeout'));
26
27 //User take the quiz
28 add_action('template_redirect', array($this, 'start_the_quiz'));
29 add_action('template_redirect', array($this, 'answering_quiz'));
30 add_action('template_redirect', array($this, 'finishing_quiz_attempt'));
31
32 add_action('admin_action_review_quiz_answer', array($this, 'review_quiz_answer'));
33 add_action('wp_ajax_review_quiz_answer', array($this, 'review_quiz_answer'));
34
35 /**
36 * New Design Quiz
37 */
38
39 add_action('wp_ajax_tutor_create_quiz_and_load_modal', array($this, 'tutor_create_quiz_and_load_modal'));
40 add_action('wp_ajax_tutor_delete_quiz_by_id', array($this, 'tutor_delete_quiz_by_id'));
41 add_action('wp_ajax_tutor_quiz_builder_quiz_update', array($this, 'tutor_quiz_builder_quiz_update'));
42 add_action('wp_ajax_tutor_load_edit_quiz_modal', array($this, 'tutor_load_edit_quiz_modal'));
43 add_action('wp_ajax_tutor_quiz_builder_get_question_form', array($this, 'tutor_quiz_builder_get_question_form'));
44 add_action('wp_ajax_tutor_quiz_modal_update_question', array($this, 'tutor_quiz_modal_update_question'));
45 add_action('wp_ajax_tutor_quiz_builder_question_delete', array($this, 'tutor_quiz_builder_question_delete'));
46 add_action('wp_ajax_tutor_quiz_add_question_answers', array($this, 'tutor_quiz_add_question_answers'));
47 add_action('wp_ajax_tutor_quiz_edit_question_answer', array($this, 'tutor_quiz_edit_question_answer'));
48 add_action('wp_ajax_tutor_save_quiz_answer_options', array($this, 'tutor_save_quiz_answer_options'));
49 add_action('wp_ajax_tutor_update_quiz_answer_options', array($this, 'tutor_update_quiz_answer_options'));
50 add_action('wp_ajax_tutor_quiz_builder_get_answers_by_question', array($this, 'tutor_quiz_builder_get_answers_by_question'));
51 add_action('wp_ajax_tutor_quiz_builder_delete_answer', array($this, 'tutor_quiz_builder_delete_answer'));
52 add_action('wp_ajax_tutor_quiz_question_sorting', array($this, 'tutor_quiz_question_sorting'));
53 add_action('wp_ajax_tutor_quiz_answer_sorting', array($this, 'tutor_quiz_answer_sorting'));
54 add_action('wp_ajax_tutor_mark_answer_as_correct', array($this, 'tutor_mark_answer_as_correct'));
55 add_action('wp_ajax_tutor_quiz_modal_update_settings', array($this, 'tutor_quiz_modal_update_settings'));
56
57 /**
58 * Frontend Stuff
59 */
60 add_action('wp_ajax_tutor_render_quiz_content', array($this, 'tutor_render_quiz_content'));
61 }
62
63
64 public function save_quiz_meta($post_ID){
65 if (isset($_POST['quiz_option'])){
66 $quiz_option = tutor_utils()->sanitize_array($_POST['quiz_option']);
67 update_post_meta($post_ID, 'tutor_quiz_option', $quiz_option);
68 }
69 }
70
71 /**
72 * Tutor Quiz Builder Modal
73 */
74 public function tutor_load_quiz_builder_modal(){
75 ob_start();
76 include tutor()->path.'views/modal/add_quiz.php';
77 $output = ob_get_clean();
78
79 wp_send_json_success(array('output' => $output));
80
81 }
82
83 public function remove_quiz_from_post(){
84 global $wpdb;
85 $quiz_id = (int) tutor_utils()->avalue_dot('quiz_id', $_POST);
86 $wpdb->update($wpdb->posts, array('post_parent' => 0), array('ID' => $quiz_id) );
87 wp_send_json_success();
88 }
89
90 /**
91 *
92 * Start Quiz from here...
93 *
94 * @since v.1.0.0
95 */
96
97 public function start_the_quiz(){
98 if ( ! isset($_POST['tutor_action']) || $_POST['tutor_action'] !== 'tutor_start_quiz' ){
99 return;
100 }
101 //Checking nonce
102 tutor_utils()->checking_nonce();
103
104 if ( ! is_user_logged_in()){
105 //TODO: need to set a view in the next version
106 die('Please sign in to do this operation');
107 }
108
109 global $wpdb;
110
111 $user_id = get_current_user_id();
112 $user = get_userdata($user_id);
113
114 $quiz_id = (int) sanitize_text_field($_POST['quiz_id']);
115
116 $quiz = get_post($quiz_id);
117 $course = tutor_utils()->get_course_by_quiz($quiz_id);
118 if ( empty($course->ID)){
119 die('There is something went wrong with course, please check if quiz attached with a course');
120 }
121
122 $date = date("Y-m-d H:i:s");
123
124 $tutor_quiz_option = (array) maybe_unserialize(get_post_meta($quiz_id, 'tutor_quiz_option', true));
125 $attempts_allowed = tutor_utils()->get_quiz_option($quiz_id, 'attempts_allowed', 0);
126
127 $time_limit = tutor_utils()->get_quiz_option($quiz_id, 'time_limit.time_value');
128 $time_limit_seconds = 0;
129 $time_type = 'seconds';
130 if ($time_limit){
131 $time_type = tutor_utils()->get_quiz_option($quiz_id, 'time_limit.time_type');
132
133 switch ($time_type){
134 case 'seconds':
135 $time_limit_seconds = $time_limit;
136 break;
137 case 'minutes':
138 $time_limit_seconds = $time_limit * 60;
139 break;
140 case 'hours':
141 $time_limit_seconds = $time_limit * 60 * 60;
142 break;
143 case 'days':
144 $time_limit_seconds = $time_limit * 60 * 60 * 24;
145 break;
146 case 'weeks':
147 $time_limit_seconds = $time_limit * 60 * 60 * 24 * 7;
148 break;
149 }
150 }
151
152 $max_question_allowed = tutor_utils()->max_questions_for_take_quiz($quiz_id);
153 $tutor_quiz_option['time_limit']['time_limit_seconds'] = $time_limit_seconds;
154
155 $attempt_data = array(
156 'course_id' => $course->ID,
157 'quiz_id' => $quiz_id,
158 'user_id' => $user_id,
159 'total_questions' => $max_question_allowed,
160 'total_answered_questions' => 0,
161 'attempt_info' => maybe_serialize($tutor_quiz_option),
162 'attempt_status' => 'attempt_started',
163 'attempt_ip' => tutor_utils()->get_ip(),
164 'attempt_started_at' => $date,
165 );
166
167 $wpdb->insert($wpdb->prefix.'tutor_quiz_attempts', $attempt_data);
168 $attempt_id = (int) $wpdb->insert_id;
169
170 wp_redirect(get_permalink($quiz_id));
171 die();
172 }
173
174 public function answering_quiz(){
175 if ( tutils()->array_get('tutor_action', $_POST) !== 'tutor_answering_quiz_question' ){
176 return;
177 }
178 //Checking nonce
179 tutor_utils()->checking_nonce();
180
181 $attempt_id = (int) sanitize_text_field(tutor_utils()->avalue_dot('attempt_id', $_POST));
182 $attempt = tutor_utils()->get_attempt($attempt_id);
183
184 $attempt_answers = isset($_POST['attempt']) ? $_POST['attempt'] : false;
185 if ( ! is_user_logged_in()){
186 die('Please sign in to do this operation');
187 }
188
189 global $wpdb;
190 $user_id = get_current_user_id();
191
192 do_action('tutor_quiz/attempt_analysing/before', $attempt_id);
193
194 if ($attempt_answers && is_array($attempt_answers) && count($attempt_answers)){
195 foreach ($attempt_answers as $attempt_id => $attempt_answers){
196
197 /**
198 * Get total marks of all question comes
199 */
200 $question_ids = tutor_utils()->avalue_dot('quiz_question_ids', $attempt_answers);
201 if (is_array($question_ids) && count($question_ids)){
202 $question_ids_string = "'".implode("','", $question_ids)."'";
203 $total_question_marks = $wpdb->get_var("SELECT SUM(question_mark) FROM {$wpdb->prefix}tutor_quiz_questions WHERE question_id IN({$question_ids_string}) ;");
204 $wpdb->update($wpdb->prefix.'tutor_quiz_attempts', array('total_marks' =>$total_question_marks ), array('attempt_id' => $attempt_id ));
205 }
206
207 if ( ! $attempt || $user_id != $attempt->user_id){
208 die('Operation not allowed, attempt not found or permission denied');
209 }
210
211 $quiz_answers = tutor_utils()->avalue_dot('quiz_question', $attempt_answers);
212 $total_marks = 0;
213 foreach ($quiz_answers as $question_id => $answers){
214 $question = tutor_utils()->get_quiz_question_by_id($question_id);
215 $question_type = $question->question_type;
216
217 $is_answer_was_correct = false;
218 $given_answer = '';
219
220 if ($question_type === 'true_false' || $question_type === 'single_choice'){
221
222 $given_answer = $answers;
223 $is_answer_was_correct = (bool) $wpdb->get_var("SELECT is_correct FROM {$wpdb->prefix}tutor_quiz_question_answers WHERE answer_id = {$answers} ");
224
225 }elseif ($question_type === 'multiple_choice'){
226
227 $given_answer = maybe_serialize($answers);
228 $get_original_answers = (array) $wpdb->get_col("SELECT answer_id FROM {$wpdb->prefix}tutor_quiz_question_answers WHERE belongs_question_id = {$question->question_id} AND belongs_question_type = '{$question_type}' AND is_correct = 1 ;");
229 if (maybe_serialize($get_original_answers) == $given_answer){
230 $is_answer_was_correct = true;
231 }
232
233 }elseif ($question_type === 'fill_in_the_blank'){
234
235 $given_answer = (array) array_map('sanitize_text_field', $answers);
236 $given_answer = maybe_serialize($given_answer);
237
238 $get_original_answer = $wpdb->get_row("SELECT * FROM {$wpdb->prefix}tutor_quiz_question_answers WHERE belongs_question_id = {$question->question_id} AND belongs_question_type = '{$question_type}' ;");
239 $gap_answer = (array) explode('|', $get_original_answer->answer_two_gap_match);
240
241 $gap_answer = array_map('sanitize_text_field', $gap_answer);
242 if ($given_answer == maybe_serialize($gap_answer)){
243 $is_answer_was_correct = true;
244 }
245
246 }elseif ($question_type === 'open_ended' || $question_type === 'short_answer'){
247
248 $given_answer = wp_kses_post($answers);
249
250 }elseif ($question_type === 'ordering' || $question_type === 'matching'|| $question_type === 'image_matching' ){
251
252 $given_answer = (array) array_map('sanitize_text_field', tutor_utils()->avalue_dot('answers', $answers));
253 $given_answer = maybe_serialize($given_answer);
254
255 $get_original_answers = (array) $wpdb->get_col("SELECT answer_id FROM {$wpdb->prefix}tutor_quiz_question_answers WHERE belongs_question_id = {$question->question_id} AND belongs_question_type = '{$question_type}' ORDER BY answer_order ASC ;");
256 $get_original_answers = array_map('sanitize_text_field', $get_original_answers);
257
258 if ($given_answer == maybe_serialize($get_original_answers)){
259 $is_answer_was_correct = true;
260 }
261
262 }elseif ($question_type === 'image_answering'){
263 echo '<pre>';
264
265 $image_inputs = tutor_utils()->avalue_dot('answer_id', $answers);
266 $image_inputs = (array) array_map('sanitize_text_field', $image_inputs);
267 $given_answer = maybe_serialize($image_inputs);
268 $is_answer_was_correct = false;
269
270 $db_answer = $wpdb->get_col("SELECT answer_title FROM {$wpdb->prefix}tutor_quiz_question_answers WHERE belongs_question_id = {$question_id} AND belongs_question_type =
271 'image_answering' ORDER BY answer_order asc ;");
272
273 if (is_array($db_answer) && count($db_answer)){
274 $is_answer_was_correct = (strtolower(maybe_serialize(array_values($image_inputs))) == strtolower(maybe_serialize($db_answer)) );
275 }
276 }
277
278 $question_mark = $is_answer_was_correct ? $question->question_mark : 0;
279 $total_marks += $question_mark;
280
281 $answers_data = array(
282 'user_id' => $user_id,
283 'quiz_id' => $attempt->quiz_id,
284 'question_id' => $question_id,
285 'quiz_attempt_id' => $attempt_id,
286 'given_answer' => $given_answer,
287 'question_mark' => $question->question_mark,
288 'achieved_mark' => $question_mark,
289 'minus_mark' => 0,
290 'is_correct' => $is_answer_was_correct ? 1 : 0,
291 );
292 $wpdb->insert($wpdb->prefix.'tutor_quiz_attempt_answers', $answers_data);
293 }
294
295 $attempt_info = array(
296 'total_answered_questions' => count($quiz_answers),
297 'earned_marks' => $total_marks,
298 'attempt_status' => 'attempt_ended',
299 'attempt_ended_at' => date("Y-m-d H:i:s"),
300 );
301 $wpdb->update($wpdb->prefix.'tutor_quiz_attempts', $attempt_info, array('attempt_id' => $attempt_id));
302 }
303
304 do_action('tutor_quiz/attempt_ended', $attempt_id);
305 }
306
307 wp_redirect(get_the_permalink($attempt->quiz_id));
308 die();
309 }
310
311
312 /**
313 * Quiz attempt will be finish here
314 *
315 */
316
317 public function finishing_quiz_attempt(){
318 if ( ! isset($_POST['tutor_action']) || $_POST['tutor_action'] !== 'tutor_finish_quiz_attempt' ){
319 return;
320 }
321 //Checking nonce
322 tutor_utils()->checking_nonce();
323
324 if ( ! is_user_logged_in()){
325 die('Please sign in to do this operation');
326 }
327
328 global $wpdb;
329
330 $quiz_id = (int) sanitize_text_field($_POST['quiz_id']);
331 $attempt = tutor_utils()->is_started_quiz($quiz_id);
332 $attempt_id = $attempt->attempt_id;
333
334 $attempt_info = array(
335 'total_answered_questions' => 0,
336 'earned_marks' => 0,
337 'attempt_status' => 'attempt_ended',
338 'attempt_ended_at' => date("Y-m-d H:i:s"),
339 );
340
341 do_action('tutor_quiz_before_finish', $attempt_id, $quiz_id, $attempt->user_id);
342 $wpdb->update($wpdb->prefix.'tutor_quiz_attempts', $attempt_info, array('attempt_id' => $attempt_id));
343 do_action('tutor_quiz_finished', $attempt_id, $quiz_id, $attempt->user_id);
344
345 wp_redirect(tutor_utils()->input_old('_wp_http_referer'));
346 }
347
348 /**
349 * Quiz timeout by ajax
350 */
351 public function tutor_quiz_timeout(){
352 global $wpdb;
353
354 $quiz_id = (int) sanitize_text_field($_POST['quiz_id']);
355 $attempt = tutor_utils()->is_started_quiz($quiz_id);
356
357 if ($attempt) {
358 $attempt_id = $attempt->attempt_id;
359
360 $data = array(
361 'attempt_status' => 'attempt_timeout',
362 'attempt_ended_at' => date("Y-m-d H:i:s"),
363 );
364 $wpdb->update($wpdb->prefix.'tutor_quiz_attempts', $data, array('attempt_id' => $attempt->attempt_id));
365
366 do_action('tutor_quiz_timeout', $attempt_id, $quiz_id, $attempt->user_id);
367
368 wp_send_json_success();
369 }
370
371 wp_send_json_error(__('Quiz has been timeout already', 'tutor'));
372 }
373
374 /**
375 * Review the answer and change individual answer result
376 */
377
378 public function review_quiz_answer(){
379 global $wpdb;
380 $attempt_id = (int) sanitize_text_field($_GET['attempt_id']);
381 $attempt_answer_id = (int) sanitize_text_field($_GET['attempt_answer_id']);
382 $mark_as = sanitize_text_field($_GET['mark_as']);
383
384 $attempt_answer = $wpdb->get_row("SELECT * FROM {$wpdb->prefix}tutor_quiz_attempt_answers WHERE attempt_answer_id = {$attempt_answer_id} ");
385 $attempt = tutor_utils()->get_attempt($attempt_id);
386
387 $is_correct = (int) $attempt_answer->is_correct;
388
389 do_action('tutor_quiz_review_answer_before', $attempt_answer_id, $attempt_id, $mark_as);
390
391 if ($mark_as === 'correct' && ! $is_correct){
392
393 $answer_update_data = array(
394 'achieved_mark' => $attempt_answer->question_mark,
395 'is_correct' => 1,
396 );
397 $wpdb->update($wpdb->prefix.'tutor_quiz_attempt_answers', $answer_update_data, array('attempt_answer_id' => $attempt_answer_id ));
398
399 $attempt_update_data = array(
400 'earned_marks' => $attempt->earned_marks + $attempt_answer->question_mark,
401 'is_manually_reviewed' => 1,
402 'manually_reviewed_at' => date("Y-m-d H:i:s"),
403 );
404
405 $wpdb->update($wpdb->prefix.'tutor_quiz_attempts', $attempt_update_data, array('attempt_id' => $attempt_id ));
406
407 }elseif($mark_as === 'incorrect' && $is_correct){
408
409 $answer_update_data = array(
410 'achieved_mark' => '0.00',
411 'is_correct' => 0,
412 );
413 $wpdb->update($wpdb->prefix.'tutor_quiz_attempt_answers', $answer_update_data, array('attempt_answer_id' => $attempt_answer_id ));
414
415 $attempt_update_data = array(
416 'earned_marks' => $attempt->earned_marks - $attempt_answer->question_mark,
417 'is_manually_reviewed' => 1,
418 'manually_reviewed_at' => date("Y-m-d H:i:s"),
419 );
420
421 $wpdb->update($wpdb->prefix.'tutor_quiz_attempts', $attempt_update_data, array('attempt_id' => $attempt_id ));
422 }
423 do_action('tutor_quiz_review_answer_after', $attempt_answer_id, $attempt_id, $mark_as);
424
425 if (wp_doing_ajax()){
426 wp_send_json_success();
427 }else{
428 wp_redirect(admin_url("admin.php?page=tutor_quiz_attempts&sub_page=view_attempt&attempt_id=".$attempt_id));
429 }
430
431 die();
432 }
433
434
435 /**
436 * New Design Quiz
437 */
438 public function tutor_create_quiz_and_load_modal(){
439 $topic_id = sanitize_text_field($_POST['topic_id']);
440 $quiz_title = sanitize_text_field($_POST['quiz_title']);
441 $quiz_description = sanitize_text_field($_POST['quiz_description']);
442 $next_order_id = tutor_utils()->get_next_course_content_order_id($topic_id);
443
444 $post_arr = array(
445 'post_type' => 'tutor_quiz',
446 'post_title' => $quiz_title,
447 'post_content' => $quiz_description,
448 'post_status' => 'publish',
449 'post_author' => get_current_user_id(),
450 'post_parent' => $topic_id,
451 'menu_order' => $next_order_id,
452 );
453 $quiz_id = wp_insert_post( $post_arr );
454 do_action('tutor_initial_quiz_created', $quiz_id);
455
456 ob_start();
457 include tutor()->path.'views/modal/edit_quiz.php';
458 $output = ob_get_clean();
459
460 ob_start();
461 ?>
462 <div id="tutor-quiz-<?php echo $quiz_id; ?>" class="course-content-item tutor-quiz tutor-quiz-<?php echo $quiz_id; ?>">
463 <div class="tutor-lesson-top">
464 <i class="tutor-icon-move"></i>
465 <a href="javascript:;" class="open-tutor-quiz-modal" data-quiz-id="<?php echo $quiz_id; ?>" data-topic-id="<?php echo $topic_id;
466 ?>"> <i class=" tutor-icon-doubt"></i>[QUIZ] <?php echo $quiz_title; ?> </a>
467 <a href="javascript:;" class="tutor-delete-quiz-btn" data-quiz-id="<?php echo $quiz_id; ?>"><i class="tutor-icon-garbage"></i></a>
468 </div>
469 </div>
470 <?php
471 $output_quiz_row = ob_get_clean();
472
473 wp_send_json_success(array('output' => $output, 'output_quiz_row' => $output_quiz_row));
474 }
475
476 public function tutor_delete_quiz_by_id(){
477 global $wpdb;
478
479 $quiz_id = (int) sanitize_text_field($_POST['quiz_id']);
480 $post = get_post($quiz_id);
481
482 if ( $post->post_type === 'tutor_quiz'){
483 do_action('tutor_delete_quiz_before', $quiz_id);
484
485 $wpdb->delete($wpdb->prefix.'tutor_quiz_attempts', array('quiz_id' => $quiz_id));
486 $wpdb->delete($wpdb->prefix.'tutor_quiz_attempt_answers', array('quiz_id' => $quiz_id));
487
488 $questions_ids = $wpdb->get_col("SELECT question_id FROM {$wpdb->prefix}tutor_quiz_questions WHERE quiz_id = {$quiz_id} ");
489 if (is_array($questions_ids) && count($questions_ids)){
490 $in_question_ids = "'".implode("','", $questions_ids)."'";
491 $wpdb->query("DELETE FROM {$wpdb->prefix}tutor_quiz_question_answers WHERE belongs_question_id IN({$in_question_ids}) ");
492 }
493 $wpdb->delete($wpdb->prefix.'tutor_quiz_questions', array('quiz_id' => $quiz_id));
494
495 wp_delete_post($quiz_id, true);
496 delete_post_meta($quiz_id, '_tutor_course_id_for_lesson');
497
498 do_action('tutor_delete_quiz_after', $quiz_id);
499
500
501 wp_send_json_success();
502 }
503
504 wp_send_json_error();
505 }
506
507 /**
508 * Update Quiz from quiz builder modal
509 *
510 * @since v.1.0.0
511 */
512 public function tutor_quiz_builder_quiz_update(){
513 $quiz_id = sanitize_text_field($_POST['quiz_id']);
514 $topic_id = sanitize_text_field($_POST['topic_id']);
515 $quiz_title = sanitize_text_field($_POST['quiz_title']);
516 $quiz_description = sanitize_text_field($_POST['quiz_description']);
517
518 $post_arr = array(
519 'ID' => $quiz_id,
520 'post_title' => $quiz_title,
521 'post_content' => $quiz_description,
522
523 );
524 $quiz_id = wp_update_post( $post_arr );
525
526 do_action('tutor_quiz_updated', $quiz_id);
527
528 ob_start();
529 ?>
530 <div class="tutor-lesson-top">
531 <i class="tutor-icon-move"></i>
532 <a href="javascript:;" class="open-tutor-quiz-modal" data-quiz-id="<?php echo $quiz_id; ?>" data-topic-id="<?php echo $topic_id;
533 ?>"> <i class=" tutor-icon-doubt"></i>[QUIZ] <?php echo $quiz_title; ?> </a>
534 <a href="javascript:;" class="tutor-delete-quiz-btn" data-quiz-id="<?php echo $quiz_id; ?>"><i class="tutor-icon-garbage"></i></a>
535 </div>
536 <?php
537 $output_quiz_row = ob_get_clean();
538
539 wp_send_json_success(array('output_quiz_row' => $output_quiz_row));
540 }
541
542 /**
543 * Load quiz Modal for edit quiz
544 *
545 * @since v.1.0.0
546 */
547 public function tutor_load_edit_quiz_modal(){
548 $quiz_id = sanitize_text_field($_POST['quiz_id']);
549
550 ob_start();
551 include tutor()->path.'views/modal/edit_quiz.php';
552 $output = ob_get_clean();
553
554 wp_send_json_success(array('output' => $output));
555 }
556
557 /**
558 * Load quiz question form for quiz
559 *
560 * @since v.1.0.0
561 */
562 public function tutor_quiz_builder_get_question_form(){
563 global $wpdb;
564 $quiz_id = sanitize_text_field($_POST['quiz_id']);
565 $question_id = sanitize_text_field(tutor_utils()->avalue_dot('question_id', $_POST));
566
567 if ( ! $question_id){
568 $next_question_id = tutor_utils()->quiz_next_question_id();
569 $next_question_order = tutor_utils()->quiz_next_question_order_id($quiz_id);
570
571 $new_question_data = array(
572 'quiz_id' => $quiz_id,
573 'question_title' => __('Question ').$next_question_id,
574 'question_description' => '',
575 'question_type' => 'true_false',
576 'question_mark' => 1,
577 'question_settings' => maybe_serialize(array()),
578 'question_order' => $next_question_order,
579 );
580
581 $wpdb->insert($wpdb->prefix.'tutor_quiz_questions', $new_question_data);
582 $question_id = $wpdb->insert_id;
583 }
584
585 $question = $wpdb->get_row("SELECT * FROM {$wpdb->prefix}tutor_quiz_questions where question_id = {$question_id} ");
586
587 ob_start();
588 include tutor()->path.'views/modal/question_form.php';
589 $output = ob_get_clean();
590
591 wp_send_json_success(array('output' => $output));
592 }
593
594 public function tutor_quiz_modal_update_question(){
595 global $wpdb;
596
597 $question_data = $_POST['tutor_quiz_question'];
598
599 foreach ($question_data as $question_id => $question){
600 $question_title = sanitize_text_field($question['question_title']);
601 $question_description = $question['question_description'];
602 $question_type = $question['question_type'];
603 $question_mark = $question['question_mark'];
604
605 unset($question['question_title']);
606 unset($question['question_description']);
607
608 $data = array(
609 'question_title' => $question_title,
610 'question_description' => $question_description,
611 'question_type' => $question_type,
612 'question_mark' => $question_mark,
613 'question_settings' => maybe_serialize($question),
614 );
615
616 $wpdb->update($wpdb->prefix.'tutor_quiz_questions', $data, array('question_id' => $question_id) );
617
618
619 /**
620 * Validation
621 */
622 if ($question_type === 'true_false' || $question_type === 'single_choice'){
623 $question_options = tutils()->get_answers_by_quiz_question($question_id);
624 if (tutils()->count($question_options)){
625 $required_validate = true;
626 foreach ($question_options as $question_option){
627 if ($question_option->is_correct){
628 $required_validate = false;
629 }
630 }
631 if ($required_validate){
632 $validation_msg = "<p class='tutor-error-msg'>".__('Please select the correct answer', 'tutor')."</p>";
633 wp_send_json_error(array('validation_msg' => $validation_msg ));
634 }
635 }else{
636 $validation_msg = "<p class='tutor-error-msg'>".__('Please make sure you have added more than one option and saved them', 'tutor')."</p>";
637 wp_send_json_error(array('validation_msg' => $validation_msg ));
638 }
639 }
640 }
641
642 wp_send_json_success();
643 }
644
645 public function tutor_quiz_builder_question_delete(){
646 global $wpdb;
647
648 $question_id = sanitize_text_field(tutor_utils()->avalue_dot('question_id', $_POST));
649 if ($question_id){
650 $wpdb->delete($wpdb->prefix.'tutor_quiz_questions', array('question_id' => $question_id));
651 }
652
653 wp_send_json_success();
654 }
655
656 /**
657 * Get answers options form for quiz question
658 *
659 * @since v.1.0.0
660 */
661 public function tutor_quiz_add_question_answers(){
662 $question_id = sanitize_text_field($_POST['question_id']);
663 $question = tutor_utils()->avalue_dot($question_id, $_POST['tutor_quiz_question']);
664 $question_type = $question['question_type'];
665
666 ob_start();
667 include tutor()->path.'views/modal/question_answer_form.php';
668 $output = ob_get_clean();
669
670 wp_send_json_success(array('output' => $output));
671 }
672
673 /**
674 * Edit Answer Form
675 *
676 * @since v.1.0.0
677 */
678 public function tutor_quiz_edit_question_answer(){
679 $answer_id = (int) sanitize_text_field($_POST['answer_id']);
680 $old_answer = tutor_utils()->get_answer_by_id($answer_id);
681 foreach ($old_answer as $old_answer);
682 $question_id = $old_answer->belongs_question_id;
683 $question_type = $old_answer->belongs_question_type;
684
685 ob_start();
686 include tutor()->path.'views/modal/question_answer_edit_form.php';
687 $output = ob_get_clean();
688
689 wp_send_json_success(array('output' => $output));
690 }
691
692 public function tutor_save_quiz_answer_options(){
693 global $wpdb;
694
695 $questions = $_POST['tutor_quiz_question'];
696 $answers = $_POST['quiz_answer'];
697
698 foreach ($answers as $question_id => $answer){
699 $question = tutor_utils()->avalue_dot($question_id, $questions);
700 $question_type = $question['question_type'];
701
702 //Getting next sorting order
703 $next_order_id = (int) $wpdb->get_var("SELECT MAX(answer_order) FROM {$wpdb->prefix}tutor_quiz_question_answers where belongs_question_id = {$question_id} AND belongs_question_type = '{$question_type}' ");
704 $next_order_id = $next_order_id + 1;
705
706 if ($question){
707 if ($question_type === 'true_false'){
708 $wpdb->delete($wpdb->prefix.'tutor_quiz_question_answers', array('belongs_question_id' => $question_id, 'belongs_question_type' => $question_type));
709 $data_true_false = array(
710 array(
711 'belongs_question_id' => $question_id,
712 'belongs_question_type' => $question_type,
713 'answer_title' => __('True', 'tutor'),
714 'is_correct' => $answer['true_false'] == 'true' ? 1 : 0,
715 'answer_two_gap_match' => 'true',
716 ),
717 array(
718 'belongs_question_id' => $question_id,
719 'belongs_question_type' => $question_type,
720 'answer_title' => __('False', 'tutor'),
721 'is_correct' => $answer['true_false'] == 'false' ? 1 : 0,
722 'answer_two_gap_match' => 'false',
723 ),
724 );
725
726 foreach ($data_true_false as $true_false_data){
727 $wpdb->insert($wpdb->prefix.'tutor_quiz_question_answers', $true_false_data);
728 }
729
730 }elseif($question_type === 'multiple_choice' || $question_type === 'single_choice' || $question_type === 'ordering' ||
731 $question_type === 'matching' || $question_type === 'image_matching' || $question_type === 'image_answering' ){
732
733 $answer_data = array(
734 'belongs_question_id' => $question_id,
735 'belongs_question_type' => $question_type,
736 'answer_title' => $answer['answer_title'],
737 'image_id' => isset($answer['image_id']) ? $answer['image_id'] : 0,
738 'answer_view_format' => isset($answer['answer_view_format']) ? $answer['answer_view_format'] : 0,
739 'answer_order' => $next_order_id,
740 );
741 if (isset($answer['matched_answer_title'])){
742 $answer_data['answer_two_gap_match'] = $answer['matched_answer_title'];
743 }
744
745 $wpdb->insert($wpdb->prefix.'tutor_quiz_question_answers', $answer_data);
746
747 }elseif($question_type === 'fill_in_the_blank'){
748 $wpdb->delete($wpdb->prefix.'tutor_quiz_question_answers', array('belongs_question_id' => $question_id, 'belongs_question_type' => $question_type));
749 $answer_data = array(
750 'belongs_question_id' => $question_id,
751 'belongs_question_type' => $question_type,
752 'answer_title' => $answer['answer_title'],
753 'answer_two_gap_match' => isset($answer['answer_two_gap_match']) ? strtolower(trim($answer['answer_two_gap_match'])) : null,
754 );
755 $wpdb->insert($wpdb->prefix.'tutor_quiz_question_answers', $answer_data);
756 }
757 }
758 }
759
760 wp_send_json_success();
761 }
762
763 /**
764 * Tutor Update Answer
765 *
766 * @since v.1.0.0
767 */
768 public function tutor_update_quiz_answer_options(){
769 global $wpdb;
770
771 $answer_id = (int) sanitize_text_field($_POST['tutor_quiz_answer_id']);
772 $questions = $_POST['tutor_quiz_question'];
773 $answers = $_POST['quiz_answer'];
774
775 foreach ($answers as $question_id => $answer){
776 $question = tutor_utils()->avalue_dot($question_id, $questions);
777 $question_type = $question['question_type'];
778
779 if ($question){
780 if($question_type === 'multiple_choice' || $question_type === 'single_choice' || $question_type === 'ordering' || $question_type === 'matching' || $question_type === 'image_matching' || $question_type === 'fill_in_the_blank' || $question_type === 'image_answering' ){
781
782 $answer_data = array(
783 'belongs_question_id' => $question_id,
784 'belongs_question_type' => $question_type,
785 'answer_title' => $answer['answer_title'],
786 'image_id' => isset($answer['image_id']) ? $answer['image_id'] : 0,
787 'answer_view_format' => isset($answer['answer_view_format']) ? $answer['answer_view_format'] : '',
788 );
789 if (isset($answer['matched_answer_title'])){
790 $answer_data['answer_two_gap_match'] = $answer['matched_answer_title'];
791 }
792
793 if ($question_type === 'fill_in_the_blank'){
794 $answer_data['answer_two_gap_match'] = isset($answer['answer_two_gap_match']) ? strtolower(trim($answer['answer_two_gap_match'])) : null;
795 }
796
797 $wpdb->update($wpdb->prefix.'tutor_quiz_question_answers', $answer_data, array('answer_id' => $answer_id));
798 }
799 }
800 }
801
802 //die(print_r($_POST));
803 wp_send_json_success();
804 }
805
806 public function tutor_quiz_builder_get_answers_by_question(){
807 global $wpdb;
808 $question_id = sanitize_text_field($_POST['question_id']);
809 $question_type = sanitize_text_field($_POST['question_type']);
810
811 $question = $wpdb->get_row("SELECT * FROM {$wpdb->prefix}tutor_quiz_questions WHERE question_id = {$question_id} ");
812 $answers = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}tutor_quiz_question_answers where belongs_question_id = {$question_id} AND belongs_question_type = '{$question_type}' order by answer_order asc ;");
813
814 ob_start();
815
816 /*
817 * @TODO: Should We remove this text?
818 * Screenshot: http://prntscr.com/ngl2mb
819 * Screenshot: http://prntscr.com/ngl2ak
820 */
821
822 switch ($question_type){
823 case 'true_false':
824 echo '<label>'.__('Answer options &amp; mark correct', 'tutor').'</label>';
825 break;
826 case 'ordering':
827 echo '<label>'.__('Make sure you’re saving the answers in the right order. Students will have to match this order exactly.', 'tutor').'</label>';
828 break;
829 }
830
831 if (is_array($answers) && count($answers)){
832 foreach ($answers as $answer){
833 ?>
834 <div class="tutor-quiz-answer-wrap" data-answer-id="<?php echo $answer->answer_id; ?>">
835 <div class="tutor-quiz-answer">
836 <span class="tutor-quiz-answer-title">
837 <?php
838 echo stripslashes($answer->answer_title);
839 if ($answer->belongs_question_type === 'fill_in_the_blank'){
840 echo ' ('.__('Answer', 'tutor').' : ';
841 echo "<strong>{$answer->answer_two_gap_match} </strong>)";
842 }
843 if ($answer->belongs_question_type === 'matching'){
844 echo " - {$answer->answer_two_gap_match}";
845 }
846 ?>
847 </span>
848
849 <?php
850 if ($answer->image_id){
851 echo '<span class="tutor-question-answer-image"><img src="'.wp_get_attachment_image_url($answer->image_id).'" /> </span>';
852 }
853 if ($question_type === 'true_false' || $question_type === 'single_choice'){
854 ?>
855 <span class="tutor-quiz-answers-mark-correct-wrap">
856 <input type="radio" name="mark_as_correct[<?php echo $answer->belongs_question_id; ?>]" value="<?php echo $answer->answer_id; ?>" title="<?php _e('Mark as correct', 'tutor'); ?>" <?php checked(1, $answer->is_correct); ?> >
857 </span>
858 <?php
859 }elseif ($question_type === 'multiple_choice'){
860 ?>
861 <span class="tutor-quiz-answers-mark-correct-wrap">
862 <input type="checkbox" name="mark_as_correct[<?php echo $answer->belongs_question_id; ?>]" value="<?php echo $answer->answer_id; ?>" title="<?php _e('Mark as correct', 'tutor'); ?>" <?php checked(1, $answer->is_correct); ?> >
863 </span>
864 <?php
865 }
866 ?>
867 <span class="tutor-quiz-answer-edit">
868 <a href="javascript:;"><i class="tutor-icon-pencil"></i> </a>
869 </span>
870 <span class="tutor-quiz-answer-sort-icon"><i class="tutor-icon-menu-2"></i> </span>
871 </div>
872
873 <div class="tutor-quiz-answer-trash-wrap">
874 <a href="javascript:;" class="answer-trash-btn" data-answer-id="<?php echo $answer->answer_id; ?>"><i class="tutor-icon-garbage"></i> </a>
875 </div>
876 </div>
877 <?php
878 }
879 }
880 $output = ob_get_clean();
881
882 wp_send_json_success(array('output' => $output));
883 }
884
885 public function tutor_quiz_builder_delete_answer(){
886 global $wpdb;
887 $answer_id = sanitize_text_field($_POST['answer_id']);
888
889 $wpdb->delete($wpdb->prefix.'tutor_quiz_question_answers', array('answer_id' => $answer_id));
890 wp_send_json_success();
891 }
892
893 /**
894 * Save quiz questions sorting
895 */
896 public function tutor_quiz_question_sorting(){
897 global $wpdb;
898
899 $question_ids = tutor_utils()->avalue_dot('sorted_question_ids', $_POST);
900 if (is_array($question_ids) && count($question_ids) ){
901 $i = 0;
902 foreach ($question_ids as $key => $question_id){
903 $i++;
904 $wpdb->update($wpdb->prefix.'tutor_quiz_questions', array('question_order' => $i), array('question_id' => $question_id));
905 }
906 }
907 }
908
909 /**
910 * Save sorting data for quiz answers
911 */
912 public function tutor_quiz_answer_sorting(){
913 global $wpdb;
914
915 if ( ! empty($_POST['sorted_answer_ids']) && is_array($_POST['sorted_answer_ids']) && count($_POST['sorted_answer_ids']) ){
916 $answer_ids = $_POST['sorted_answer_ids'];
917 $i = 0;
918 foreach ($answer_ids as $key => $answer_id){
919 $i++;
920 $wpdb->update($wpdb->prefix.'tutor_quiz_question_answers', array('answer_order' => $i), array('answer_id' => $answer_id));
921 }
922 }
923
924 }
925
926 /**
927 * Mark answer as correct
928 */
929
930 public function tutor_mark_answer_as_correct(){
931 global $wpdb;
932
933 $answer_id = sanitize_text_field($_POST['answer_id']);
934 $inputValue = sanitize_text_field($_POST['inputValue']);
935
936 $answer = $wpdb->get_row("SELECT * FROM {$wpdb->prefix}tutor_quiz_question_answers WHERE answer_id = {$answer_id} LIMIT 0,1 ;");
937 if ($answer->belongs_question_type === 'single_choice'){
938 $wpdb->update($wpdb->prefix.'tutor_quiz_question_answers', array('is_correct' => 0), array('belongs_question_id' => $answer->belongs_question_id));
939 }
940 $wpdb->update($wpdb->prefix.'tutor_quiz_question_answers', array('is_correct' => $inputValue), array('answer_id' => $answer_id));
941 }
942
943 /**
944 * Update quiz settings from modal
945 *
946 * @since : v.1.0.0
947 */
948 public function tutor_quiz_modal_update_settings(){
949 $quiz_id = sanitize_text_field($_POST['quiz_id']);
950
951 $quiz_option = tutor_utils()->sanitize_array($_POST['quiz_option']);
952 update_post_meta($quiz_id, 'tutor_quiz_option', $quiz_option);
953
954 do_action('tutor_quiz_settings_updated', $quiz_id);
955
956 wp_send_json_success();
957 }
958
959
960 //=========================//
961 // Front end stuffs
962 //=========================//
963
964 /**
965 * Rendering quiz for frontend
966 *
967 * @since v.1.0.0
968 */
969
970 public function tutor_render_quiz_content(){
971 $quiz_id = (int) sanitize_text_field(tutor_utils()->avalue_dot('quiz_id', $_POST));
972
973 ob_start();
974 global $post;
975
976 $post = get_post($quiz_id);
977 setup_postdata($post);
978 //tutor_lesson_content();
979
980 single_quiz_contents();
981
982 wp_reset_postdata();
983
984
985 $html = ob_get_clean();
986 wp_send_json_success(array('html' => $html));
987 }
988
989
990 }