PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 1.8.2
Tutor LMS – eLearning and online course solution v1.8.2
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 5 years ago Admin.php 5 years ago Ajax.php 5 years ago Assets.php 5 years ago Course.php 5 years ago Course_Filter.php 5 years ago Course_Settings_Tabs.php 5 years ago Course_Widget.php 5 years ago Custom_Validation.php 5 years ago Dashboard.php 5 years ago Email.php 5 years ago FormHandler.php 5 years ago Frontend.php 5 years ago Gutenberg.php 5 years ago Instructor.php 5 years ago Instructors_List.php 5 years ago Lesson.php 5 years ago Options.php 5 years ago Post_types.php 5 years ago Private_Course_Access.php 5 years ago Q_and_A.php 5 years ago Question_Answers_List.php 5 years ago Quiz.php 5 years ago Quiz_Attempts_List.php 5 years ago RestAPI.php 5 years ago Rewrite_Rules.php 5 years ago Shortcode.php 5 years ago Student.php 5 years ago Students_List.php 5 years ago Taxonomies.php 5 years ago Template.php 5 years ago Theme_Compatibility.php 5 years ago Tools.php 5 years ago Tutor.php 5 years ago TutorEDD.php 5 years ago Tutor_Base.php 5 years ago Tutor_List_Table.php 5 years ago Tutor_Setup.php 5 years ago Upgrader.php 5 years ago User.php 5 years ago Utils.php 5 years ago Video_Stream.php 5 years ago Withdraw.php 5 years ago Withdraw_Requests_List.php 5 years ago WooCommerce.php 5 years ago
Quiz.php
1248 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 private $allowed_attributes = array(
20 'src' => array(),
21 'style' => array(),
22 'class' => array(),
23 'id' => array(),
24 'href' => array(),
25 'alt' => array(),
26 'title' => array(),
27 'type' => array(),
28 'controls' => array(),
29 'muted' => array(),
30 'loop' => array(),
31 'poster' => array(),
32 'preload' => array(),
33 'autoplay' => array(),
34 'width' => array(),
35 'height' => array()
36 );
37
38 private $allowed_html = array( 'img', 'b', 'i', 'br', 'a', 'audio', 'video', 'source' );
39
40 public function __construct() {
41
42 add_action('save_post_tutor_quiz', array($this, 'save_quiz_meta'));
43
44 add_action('wp_ajax_tutor_load_quiz_builder_modal', array($this, 'tutor_load_quiz_builder_modal'));
45 add_action('wp_ajax_remove_quiz_from_post', array($this, 'remove_quiz_from_post'));
46
47 add_action('wp_ajax_tutor_quiz_timeout', array($this, 'tutor_quiz_timeout'));
48
49 //User take the quiz
50 add_action('template_redirect', array($this, 'start_the_quiz'));
51 add_action('template_redirect', array($this, 'answering_quiz'));
52 add_action('template_redirect', array($this, 'finishing_quiz_attempt'));
53
54 add_action('admin_action_review_quiz_answer', array($this, 'review_quiz_answer'));
55 add_action('wp_ajax_review_quiz_answer', array($this, 'review_quiz_answer'));
56 add_action('wp_ajax_tutor_instructor_feedback', array($this, 'tutor_instructor_feedback')); // Instructor Feedback Action
57
58 /**
59 * New Design Quiz
60 */
61
62 add_action('wp_ajax_tutor_create_quiz_and_load_modal', array($this, 'tutor_create_quiz_and_load_modal'));
63 add_action('wp_ajax_tutor_delete_quiz_by_id', array($this, 'tutor_delete_quiz_by_id'));
64 add_action('wp_ajax_tutor_quiz_builder_quiz_update', array($this, 'tutor_quiz_builder_quiz_update'));
65 add_action('wp_ajax_tutor_load_edit_quiz_modal', array($this, 'tutor_load_edit_quiz_modal'));
66 add_action('wp_ajax_tutor_quiz_builder_get_question_form', array($this, 'tutor_quiz_builder_get_question_form'));
67 add_action('wp_ajax_tutor_quiz_modal_update_question', array($this, 'tutor_quiz_modal_update_question'));
68 add_action('wp_ajax_tutor_quiz_builder_question_delete', array($this, 'tutor_quiz_builder_question_delete'));
69 add_action('wp_ajax_tutor_quiz_add_question_answers', array($this, 'tutor_quiz_add_question_answers'));
70 add_action('wp_ajax_tutor_quiz_edit_question_answer', array($this, 'tutor_quiz_edit_question_answer'));
71 add_action('wp_ajax_tutor_save_quiz_answer_options', array($this, 'tutor_save_quiz_answer_options'));
72 add_action('wp_ajax_tutor_update_quiz_answer_options', array($this, 'tutor_update_quiz_answer_options'));
73 add_action('wp_ajax_tutor_quiz_builder_get_answers_by_question', array($this, 'tutor_quiz_builder_get_answers_by_question'));
74 add_action('wp_ajax_tutor_quiz_builder_delete_answer', array($this, 'tutor_quiz_builder_delete_answer'));
75 add_action('wp_ajax_tutor_quiz_question_sorting', array($this, 'tutor_quiz_question_sorting'));
76 add_action('wp_ajax_tutor_quiz_answer_sorting', array($this, 'tutor_quiz_answer_sorting'));
77 add_action('wp_ajax_tutor_mark_answer_as_correct', array($this, 'tutor_mark_answer_as_correct'));
78 add_action('wp_ajax_tutor_quiz_modal_update_settings', array($this, 'tutor_quiz_modal_update_settings'));
79
80 /**
81 * Frontend Stuff
82 */
83 add_action('wp_ajax_tutor_render_quiz_content', array($this, 'tutor_render_quiz_content'));
84
85 $this->prepare_allowed_html();
86 }
87
88 private function prepare_allowed_html() {
89
90 $allowed = array();
91
92 foreach($this->allowed_html as $tag) {
93 $allowed[$tag] = $this->allowed_attributes;
94 }
95
96 $this->allowed_html = $allowed;
97 }
98
99 public function tutor_instructor_feedback(){
100 tutils()->checking_nonce();
101
102 $feedback = sanitize_text_field($_POST['feedback']);
103 $attempt_id = (int) tutor_utils()->avalue_dot('attempts_id', $_POST);
104
105 if ($attempt_id && tutils()->can_user_manage('attempt', $attempt_id)) {
106 update_post_meta($attempt_id, 'instructor_feedback', $feedback);
107 do_action('tutor_quiz/attempt/submitted/feedback', $attempt_id);
108
109 wp_send_json_success( );
110 }
111 }
112
113 public function save_quiz_meta($post_ID){
114 if (isset($_POST['quiz_option'])){
115 $quiz_option = tutor_utils()->sanitize_array($_POST['quiz_option']);
116 update_post_meta($post_ID, 'tutor_quiz_option', $quiz_option);
117 }
118 }
119
120 /**
121 * Tutor Quiz Builder Modal
122 */
123 public function tutor_load_quiz_builder_modal(){
124 tutils()->checking_nonce();
125
126 ob_start();
127 include tutor()->path.'views/modal/add_quiz.php';
128 $output = ob_get_clean();
129
130 wp_send_json_success(array('output' => $output));
131 }
132
133 public function remove_quiz_from_post(){
134 tutils()->checking_nonce();
135
136 global $wpdb;
137 $quiz_id = (int) tutor_utils()->avalue_dot('quiz_id', $_POST);
138
139 if(!tutils()->can_user_manage('quiz', $quiz_id)) {
140 wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
141 }
142
143 $wpdb->update($wpdb->posts, array('post_parent' => 0), array('ID' => $quiz_id) );
144 wp_send_json_success();
145 }
146
147 /**
148 *
149 * Start Quiz from here...
150 *
151 * @since v.1.0.0
152 */
153
154 public function start_the_quiz(){
155 if ( ! isset($_POST['tutor_action']) || $_POST['tutor_action'] !== 'tutor_start_quiz' ){
156 return;
157 }
158 //Checking nonce
159 tutor_utils()->checking_nonce();
160
161 if ( ! is_user_logged_in()){
162 //TODO: need to set a view in the next version
163 die('Please sign in to do this operation');
164 }
165
166 global $wpdb;
167
168 $user_id = get_current_user_id();
169 $user = get_userdata($user_id);
170
171 $quiz_id = (int) sanitize_text_field($_POST['quiz_id']);
172
173 $quiz = get_post($quiz_id);
174 $course = tutor_utils()->get_course_by_quiz($quiz_id);
175 if ( empty($course->ID)){
176 die('There is something went wrong with course, please check if quiz attached with a course');
177 }
178
179 do_action('tutor_quiz/start/before', $quiz_id, $user_id);
180
181 $date = date("Y-m-d H:i:s", tutor_time());
182
183 $tutor_quiz_option = (array) maybe_unserialize(get_post_meta($quiz_id, 'tutor_quiz_option', true));
184 $attempts_allowed = tutor_utils()->get_quiz_option($quiz_id, 'attempts_allowed', 0);
185
186 $time_limit = tutor_utils()->get_quiz_option($quiz_id, 'time_limit.time_value');
187 $time_limit_seconds = 0;
188 $time_type = 'seconds';
189 if ($time_limit){
190 $time_type = tutor_utils()->get_quiz_option($quiz_id, 'time_limit.time_type');
191
192 switch ($time_type){
193 case 'seconds':
194 $time_limit_seconds = $time_limit;
195 break;
196 case 'minutes':
197 $time_limit_seconds = $time_limit * 60;
198 break;
199 case 'hours':
200 $time_limit_seconds = $time_limit * 60 * 60;
201 break;
202 case 'days':
203 $time_limit_seconds = $time_limit * 60 * 60 * 24;
204 break;
205 case 'weeks':
206 $time_limit_seconds = $time_limit * 60 * 60 * 24 * 7;
207 break;
208 }
209 }
210
211 $max_question_allowed = tutor_utils()->max_questions_for_take_quiz($quiz_id);
212 $tutor_quiz_option['time_limit']['time_limit_seconds'] = $time_limit_seconds;
213
214 $attempt_data = array(
215 'course_id' => $course->ID,
216 'quiz_id' => $quiz_id,
217 'user_id' => $user_id,
218 'total_questions' => $max_question_allowed,
219 'total_answered_questions' => 0,
220 'attempt_info' => maybe_serialize($tutor_quiz_option),
221 'attempt_status' => 'attempt_started',
222 'attempt_ip' => tutor_utils()->get_ip(),
223 'attempt_started_at' => $date,
224 );
225
226 $wpdb->insert($wpdb->prefix.'tutor_quiz_attempts', $attempt_data);
227 $attempt_id = (int) $wpdb->insert_id;
228
229 do_action('tutor_quiz/start/after', $quiz_id, $user_id, $attempt_id);
230
231 wp_redirect(get_permalink($quiz_id));
232 die();
233 }
234
235 public function answering_quiz(){
236
237 if ( tutils()->array_get('tutor_action', $_POST) !== 'tutor_answering_quiz_question' ){
238 return;
239 }
240 //Checking nonce
241 tutor_utils()->checking_nonce();
242
243 $attempt_id = (int) sanitize_text_field(tutor_utils()->avalue_dot('attempt_id', $_POST));
244 $attempt = tutor_utils()->get_attempt($attempt_id);
245
246 $attempt_answers = isset($_POST['attempt']) ? $_POST['attempt'] : false;
247 if ( ! is_user_logged_in()){
248 die('Please sign in to do this operation');
249 }
250
251 global $wpdb;
252 $user_id = get_current_user_id();
253
254 do_action('tutor_quiz/attempt_analysing/before', $attempt_id);
255
256 if ($attempt_answers && is_array($attempt_answers) && count($attempt_answers)){
257 foreach ($attempt_answers as $attempt_id => $attempt_answer){
258
259 /**
260 * Get total marks of all question comes
261 */
262 $question_ids = tutor_utils()->avalue_dot('quiz_question_ids', $attempt_answer);
263 if (is_array($question_ids) && count($question_ids)){
264 $question_ids_string = "'".implode("','", $question_ids)."'";
265 $total_question_marks = $wpdb->get_var("SELECT SUM(question_mark) FROM {$wpdb->prefix}tutor_quiz_questions WHERE question_id IN({$question_ids_string}) ;");
266 $wpdb->update($wpdb->prefix.'tutor_quiz_attempts', array('total_marks' =>$total_question_marks ), array('attempt_id' => $attempt_id ));
267 }
268
269 if ( ! $attempt || $user_id != $attempt->user_id){
270 die('Operation not allowed, attempt not found or permission denied');
271 }
272
273 $quiz_answers = tutor_utils()->avalue_dot('quiz_question', $attempt_answer);
274
275 $total_marks = 0;
276 $review_required = false;
277
278 if ( tutils()->count($quiz_answers)) {
279
280 foreach ( $quiz_answers as $question_id => $answers ) {
281 $question = tutor_utils()->get_quiz_question_by_id( $question_id );
282 $question_type = $question->question_type;
283
284 $is_answer_was_correct = false;
285 $given_answer = '';
286
287 if ( $question_type === 'true_false' || $question_type === 'single_choice' ) {
288
289 if(!is_numeric($answers) || !$answers) {
290 wp_send_json_error();
291 exit;
292 }
293
294 $given_answer = $answers;
295 $is_answer_was_correct = (bool) $wpdb->get_var( $wpdb->prepare( "SELECT is_correct FROM {$wpdb->prefix}tutor_quiz_question_answers WHERE answer_id = %d ", $answers ) );
296
297 } elseif ( $question_type === 'multiple_choice' ) {
298
299 $given_answer = (array) ( $answers );
300
301 $given_answer = array_filter( $given_answer, function($id) {
302 return is_numeric($id) && $id>0;
303 } );
304
305 $get_original_answers = (array) $wpdb->get_col($wpdb->prepare(
306 "SELECT
307 answer_id
308 FROM
309 {$wpdb->prefix}tutor_quiz_question_answers
310 WHERE
311 belongs_question_id = %d
312 AND belongs_question_type = %s
313 AND is_correct = 1 ;
314 ",
315 $question->question_id,
316 $question_type
317 ) );
318
319
320 if (count(array_diff($get_original_answers, $given_answer)) === 0 && count($get_original_answers) === count($given_answer)) {
321 $is_answer_was_correct = true;
322 }
323 $given_answer = maybe_serialize( $answers );
324
325 } elseif ( $question_type === 'fill_in_the_blank' ) {
326
327 $given_answer = (array) array_map( 'sanitize_text_field', $answers );
328 $given_answer = maybe_serialize( $given_answer );
329
330 $get_original_answer = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}tutor_quiz_question_answers WHERE belongs_question_id = %d AND belongs_question_type = %s ;", $question->question_id, $question_type ) );
331 $gap_answer = (array) explode( '|', $get_original_answer->answer_two_gap_match );
332
333 $gap_answer = array_map( 'sanitize_text_field', $gap_answer );
334 if ( strtolower($given_answer) == strtolower(maybe_serialize( $gap_answer )) ) {
335 $is_answer_was_correct = true;
336 }
337 } elseif ( $question_type === 'open_ended' || $question_type === 'short_answer' ) {
338 $review_required = true;
339 $given_answer = wp_kses_post( $answers );
340
341 } elseif ( $question_type === 'ordering' || $question_type === 'matching' || $question_type === 'image_matching' ) {
342
343 $given_answer = (array) array_map( 'sanitize_text_field', tutor_utils()->avalue_dot( 'answers', $answers ) );
344 $given_answer = maybe_serialize( $given_answer );
345
346 $get_original_answers = (array) $wpdb->get_col($wpdb->prepare(
347 "SELECT answer_id
348 FROM {$wpdb->prefix}tutor_quiz_question_answers
349 WHERE belongs_question_id = %d AND belongs_question_type = %s ORDER BY answer_order ASC ;", $question->question_id, $question_type));
350
351 $get_original_answers = array_map( 'sanitize_text_field', $get_original_answers );
352
353 if ( $given_answer == maybe_serialize( $get_original_answers ) ) {
354 $is_answer_was_correct = true;
355 }
356
357 } elseif ( $question_type === 'image_answering' ) {
358 $image_inputs = tutor_utils()->avalue_dot( 'answer_id', $answers );
359 $image_inputs = (array) array_map( 'sanitize_text_field', $image_inputs );
360 $given_answer = maybe_serialize( $image_inputs );
361 $is_answer_was_correct = false;
362
363 $db_answer = $wpdb->get_col($wpdb->prepare(
364 "SELECT answer_title
365 FROM {$wpdb->prefix}tutor_quiz_question_answers
366 WHERE belongs_question_id = %d AND belongs_question_type = 'image_answering' ORDER BY answer_order asc ;", $question_id));
367
368 if ( is_array( $db_answer ) && count( $db_answer ) ) {
369 $is_answer_was_correct = ( strtolower( maybe_serialize( array_values( $image_inputs ) ) ) == strtolower( maybe_serialize( $db_answer ) ) );
370 }
371 }
372
373 $question_mark = $is_answer_was_correct ? $question->question_mark : 0;
374 $total_marks += $question_mark;
375
376 $answers_data = array(
377 'user_id' => $user_id,
378 'quiz_id' => $attempt->quiz_id,
379 'question_id' => $question_id,
380 'quiz_attempt_id' => $attempt_id,
381 'given_answer' => $given_answer,
382 'question_mark' => $question->question_mark,
383 'achieved_mark' => $question_mark,
384 'minus_mark' => 0,
385 'is_correct' => $is_answer_was_correct ? 1 : 0,
386 );
387
388 /*
389 check if question_type open ended or short ans the set is_correct default value null before saving
390 */
391 if($question_type==="open_ended" || $question_type ==="short_answer")
392 {
393 $answers_data['is_correct'] = NULL;
394 }
395
396 $wpdb->insert( $wpdb->prefix . 'tutor_quiz_attempt_answers', $answers_data );
397 }
398 }
399
400 $attempt_info = array(
401 'total_answered_questions' => tutils()->count($quiz_answers),
402 'earned_marks' => $total_marks,
403 'attempt_status' => 'attempt_ended',
404 'attempt_ended_at' => date("Y-m-d H:i:s", tutor_time()),
405 );
406
407 if ($review_required){
408 $attempt_info['attempt_status'] = 'review_required';
409 }
410
411 $wpdb->update($wpdb->prefix.'tutor_quiz_attempts', $attempt_info, array('attempt_id' => $attempt_id));
412 }
413
414 do_action('tutor_quiz/attempt_ended', $attempt_id);
415 }
416
417 wp_redirect(get_the_permalink($attempt->quiz_id));
418 die();
419 }
420
421
422 /**
423 * Quiz attempt will be finish here
424 *
425 */
426
427 public function finishing_quiz_attempt(){
428
429 if ( ! isset($_POST['tutor_action']) || $_POST['tutor_action'] !== 'tutor_finish_quiz_attempt' ){
430 return;
431 }
432 //Checking nonce
433 tutor_utils()->checking_nonce();
434
435 if ( ! is_user_logged_in()){
436 die('Please sign in to do this operation');
437 }
438
439 global $wpdb;
440
441 $quiz_id = (int) sanitize_text_field($_POST['quiz_id']);
442 $attempt = tutor_utils()->is_started_quiz($quiz_id);
443 $attempt_id = $attempt->attempt_id;
444
445 $attempt_info = array(
446 'total_answered_questions' => 0,
447 'earned_marks' => 0,
448 'attempt_status' => 'attempt_ended',
449 'attempt_ended_at' => date("Y-m-d H:i:s", tutor_time()),
450 );
451
452 do_action('tutor_quiz_before_finish', $attempt_id, $quiz_id, $attempt->user_id);
453 $wpdb->update($wpdb->prefix.'tutor_quiz_attempts', $attempt_info, array('attempt_id' => $attempt_id));
454 do_action('tutor_quiz_finished', $attempt_id, $quiz_id, $attempt->user_id);
455
456 wp_redirect(tutor_utils()->input_old('_wp_http_referer'));
457 }
458
459 /**
460 * Quiz timeout by ajax
461 */
462 public function tutor_quiz_timeout(){
463 tutils()->checking_nonce();
464
465 global $wpdb;
466
467 $quiz_id = (int) sanitize_text_field($_POST['quiz_id']);
468
469 if(!tutils()->can_user_manage('quiz', $quiz_id)) {
470 wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
471 }
472
473 $attempt = tutor_utils()->is_started_quiz($quiz_id);
474
475 if ($attempt) {
476 $attempt_id = $attempt->attempt_id;
477
478 $data = array(
479 'attempt_status' => 'attempt_timeout',
480 'attempt_ended_at' => date("Y-m-d H:i:s", tutor_time()),
481 );
482 $wpdb->update($wpdb->prefix.'tutor_quiz_attempts', $data, array('attempt_id' => $attempt->attempt_id));
483
484 do_action('tutor_quiz_timeout', $attempt_id, $quiz_id, $attempt->user_id);
485
486 wp_send_json_success();
487 }
488
489 wp_send_json_error(__('Quiz has been timeout already', 'tutor'));
490 }
491
492 /**
493 * Review the answer and change individual answer result
494 */
495
496 public function review_quiz_answer() {
497
498 tutils()->checking_nonce(strtolower($_SERVER['REQUEST_METHOD']));
499
500 global $wpdb;
501
502 $attempt_id = (int) sanitize_text_field($_GET['attempt_id']);
503 $attempt_answer_id = (int) sanitize_text_field($_GET['attempt_answer_id']);
504 $mark_as = sanitize_text_field($_GET['mark_as']);
505
506 if(!tutils()->can_user_manage('attempt', $attempt_id) || !tutils()->can_user_manage('attempt_answer', $attempt_answer_id)) {
507 wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
508 }
509
510 $attempt_answer = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}tutor_quiz_attempt_answers WHERE attempt_answer_id = %d ", $attempt_answer_id));
511
512 $attempt = tutor_utils()->get_attempt($attempt_id);
513 $question = tutils()->get_quiz_question_by_id($attempt_answer->question_id);
514
515 $previous_ans = $attempt_answer->is_correct;
516
517 do_action('tutor_quiz_review_answer_before', $attempt_answer_id, $attempt_id, $mark_as);
518
519 if ($mark_as === 'correct'){
520
521 $answer_update_data = array(
522 'achieved_mark' => $attempt_answer->question_mark,
523 'is_correct' => 1,
524 );
525 $wpdb->update($wpdb->prefix.'tutor_quiz_attempt_answers', $answer_update_data, array('attempt_answer_id' => $attempt_answer_id ));
526 if($previous_ans ==0 OR $previous_ans ==null)
527 {
528
529 //if previous answer was wrong or in review then add point as correct
530 $attempt_update_data = array(
531 'earned_marks' => $attempt->earned_marks + $attempt_answer->question_mark,
532 'is_manually_reviewed' => 1,
533 'manually_reviewed_at' => date("Y-m-d H:i:s", tutor_time()),
534 );
535
536
537 }
538
539 if ($question->question_type === 'open_ended' || $question->question_type === 'short_answer' ){
540 $attempt_update_data['attempt_status'] = 'attempt_ended';
541 }
542 $wpdb->update($wpdb->prefix.'tutor_quiz_attempts', $attempt_update_data, array('attempt_id' => $attempt_id ));
543 }
544 elseif($mark_as === 'incorrect')
545 {
546
547 $answer_update_data = array(
548 'achieved_mark' => '0.00',
549 'is_correct' => 0,
550 );
551 $wpdb->update($wpdb->prefix.'tutor_quiz_attempt_answers', $answer_update_data, array('attempt_answer_id' => $attempt_answer_id ));
552
553
554 if($previous_ans ==1)
555 {
556
557 //if previous ans was right then mynus
558 $attempt_update_data = array(
559 'earned_marks' => $attempt->earned_marks - $attempt_answer->question_mark,
560 'is_manually_reviewed' => 1,
561 'manually_reviewed_at' => date("Y-m-d H:i:s", tutor_time()),
562 );
563
564 }
565 if ($question->question_type === 'open_ended' || $question->question_type === 'short_answer' ){
566 $attempt_update_data['attempt_status'] = 'attempt_ended';
567 }
568
569 $wpdb->update($wpdb->prefix.'tutor_quiz_attempts', $attempt_update_data, array('attempt_id' => $attempt_id ));
570 }
571 do_action('tutor_quiz_review_answer_after', $attempt_answer_id, $attempt_id, $mark_as);
572
573 if (wp_doing_ajax())
574 {
575 wp_send_json_success();
576 }
577 else{
578 wp_redirect(admin_url("admin.php?page=tutor_quiz_attempts&sub_page=view_attempt&attempt_id=".$attempt_id));
579 }
580
581 die();
582 }
583
584
585 /**
586 * New Design Quiz
587 */
588 public function tutor_create_quiz_and_load_modal(){
589 tutils()->checking_nonce();
590
591 $topic_id = sanitize_text_field($_POST['topic_id']);
592 $quiz_title = sanitize_text_field($_POST['quiz_title']);
593 $quiz_description = wp_kses( $_POST['quiz_description'], $this->allowed_html );
594 $next_order_id = tutor_utils()->get_next_course_content_order_id($topic_id);
595
596 if(!tutils()->can_user_manage('topic', $topic_id)) {
597 wp_send_json_error( array('message'=>__('Access Denied', 'tutor'), 'data'=>$_POST) );
598 }
599
600 $post_arr = array(
601 'post_type' => 'tutor_quiz',
602 'post_title' => $quiz_title,
603 'post_content' => $quiz_description,
604 'post_status' => 'publish',
605 'post_author' => get_current_user_id(),
606 'post_parent' => $topic_id,
607 'menu_order' => $next_order_id,
608 );
609 $quiz_id = wp_insert_post( $post_arr );
610 do_action('tutor_initial_quiz_created', $quiz_id);
611
612 ob_start();
613 include tutor()->path.'views/modal/edit_quiz.php';
614 $output = ob_get_clean();
615
616 ob_start();
617 ?>
618 <div id="tutor-quiz-<?php echo $quiz_id; ?>" class="course-content-item tutor-quiz tutor-quiz-<?php echo $quiz_id; ?>">
619 <div class="tutor-lesson-top">
620 <i class="tutor-icon-move"></i>
621 <a href="javascript:;" class="open-tutor-quiz-modal" data-quiz-id="<?php echo $quiz_id; ?>" data-topic-id="<?php echo $topic_id;
622 ?>"> <i class=" tutor-icon-doubt"></i>[<?php _e('QUIZ', 'tutor'); ?>] <?php echo stripslashes($quiz_title); ?> </a>
623 <?php do_action('tutor_course_builder_before_quiz_btn_action', $quiz_id); ?>
624 <a href="javascript:;" class="tutor-delete-quiz-btn" data-quiz-id="<?php echo $quiz_id; ?>"><i class="tutor-icon-garbage"></i></a>
625 </div>
626 </div>
627 <?php
628 $output_quiz_row = ob_get_clean();
629
630 wp_send_json_success(array('output' => $output, 'output_quiz_row' => $output_quiz_row));
631 }
632
633 public function tutor_delete_quiz_by_id(){
634 tutils()->checking_nonce();
635
636 global $wpdb;
637
638 $quiz_id = (int) sanitize_text_field($_POST['quiz_id']);
639 $post = get_post($quiz_id);
640
641
642 if(!tutils()->can_user_manage('quiz', $quiz_id)) {
643 wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
644 }
645
646 if ( $post->post_type === 'tutor_quiz'){
647 do_action('tutor_delete_quiz_before', $quiz_id);
648
649 $wpdb->delete($wpdb->prefix.'tutor_quiz_attempts', array('quiz_id' => $quiz_id));
650 $wpdb->delete($wpdb->prefix.'tutor_quiz_attempt_answers', array('quiz_id' => $quiz_id));
651
652 $questions_ids = $wpdb->get_col($wpdb->prepare("SELECT question_id FROM {$wpdb->prefix}tutor_quiz_questions WHERE quiz_id = %d ", $quiz_id));
653
654 if (is_array($questions_ids) && count($questions_ids)){
655 $in_question_ids = "'".implode("','", $questions_ids)."'";
656 $wpdb->query("DELETE FROM {$wpdb->prefix}tutor_quiz_question_answers WHERE belongs_question_id IN({$in_question_ids}) ");
657 }
658
659 $wpdb->delete($wpdb->prefix.'tutor_quiz_questions', array('quiz_id' => $quiz_id));
660
661 wp_delete_post($quiz_id, true);
662 delete_post_meta($quiz_id, '_tutor_course_id_for_lesson');
663
664 do_action('tutor_delete_quiz_after', $quiz_id);
665
666
667 wp_send_json_success();
668 }
669
670 wp_send_json_error();
671 }
672
673 /**
674 * Update Quiz from quiz builder modal
675 *
676 * @since v.1.0.0
677 */
678 public function tutor_quiz_builder_quiz_update(){
679 tutils()->checking_nonce();
680
681 $quiz_id = sanitize_text_field($_POST['quiz_id']);
682 $topic_id = sanitize_text_field($_POST['topic_id']);
683 $quiz_title = sanitize_text_field($_POST['quiz_title']);
684 $quiz_description = wp_kses( $_POST['quiz_description'], $this->allowed_html );
685
686 if(!tutils()->can_user_manage('quiz', $quiz_id)) {
687 wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
688 }
689
690 $post_arr = array(
691 'ID' => $quiz_id,
692 'post_title' => $quiz_title,
693 'post_content' => $quiz_description,
694
695 );
696 $quiz_id = wp_update_post( $post_arr );
697
698 do_action('tutor_quiz_updated', $quiz_id);
699
700 ob_start();
701 ?>
702 <div class="tutor-lesson-top">
703 <i class="tutor-icon-move"></i>
704 <a href="javascript:;" class="open-tutor-quiz-modal" data-quiz-id="<?php echo $quiz_id; ?>" data-topic-id="<?php echo $topic_id;
705 ?>"> <i class=" tutor-icon-doubt"></i>[<?php _e('QUIZ', 'tutor'); ?>] <?php echo stripslashes($quiz_title); ?> </a>
706 <?php do_action('tutor_course_builder_before_quiz_btn_action', $quiz_id); ?>
707 <a href="javascript:;" class="tutor-delete-quiz-btn" data-quiz-id="<?php echo $quiz_id; ?>"><i class="tutor-icon-garbage"></i></a>
708 </div>
709 <?php
710 $output_quiz_row = ob_get_clean();
711
712 wp_send_json_success(array('output_quiz_row' => $output_quiz_row));
713 }
714
715 /**
716 * Load quiz Modal for edit quiz
717 *
718 * @since v.1.0.0
719 */
720 public function tutor_load_edit_quiz_modal(){
721 tutils()->checking_nonce();
722
723 $quiz_id = sanitize_text_field($_POST['quiz_id']);
724
725 if(!tutils()->can_user_manage('quiz', $quiz_id)) {
726 wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
727 }
728
729 ob_start();
730 include tutor()->path.'views/modal/edit_quiz.php';
731 $output = ob_get_clean();
732
733 wp_send_json_success(array('output' => $output));
734 }
735
736 /**
737 * Load quiz question form for quiz
738 *
739 * @since v.1.0.0
740 */
741 public function tutor_quiz_builder_get_question_form(){
742 tutils()->checking_nonce();
743
744 global $wpdb;
745 $quiz_id = sanitize_text_field($_POST['quiz_id']);
746 $question_id = sanitize_text_field(tutor_utils()->avalue_dot('question_id', $_POST));
747
748 if(!tutils()->can_user_manage('quiz', $quiz_id)) {
749 wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
750 }
751
752 if ( ! $question_id){
753 $next_question_id = tutor_utils()->quiz_next_question_id();
754 $next_question_order = tutor_utils()->quiz_next_question_order_id($quiz_id);
755
756 $new_question_data = array(
757 'quiz_id' => $quiz_id,
758 'question_title' => __('Question', 'tutor').' '.$next_question_id,
759 'question_description' => '',
760 'question_type' => 'true_false',
761 'question_mark' => 1,
762 'question_settings' => maybe_serialize(array()),
763 'question_order' => esc_sql( $next_question_order ) ,
764 );
765
766 $wpdb->insert($wpdb->prefix.'tutor_quiz_questions', $new_question_data);
767 $question_id = $wpdb->insert_id;
768 }
769
770 $question = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}tutor_quiz_questions where question_id = %d ", $question_id));
771
772 ob_start();
773 include tutor()->path.'views/modal/question_form.php';
774 $output = ob_get_clean();
775
776 wp_send_json_success(array('output' => $output));
777 }
778
779 public function tutor_quiz_modal_update_question(){
780 tutils()->checking_nonce();
781
782 global $wpdb;
783
784 $question_data = $_POST['tutor_quiz_question'];
785
786 foreach ($question_data as $question_id => $question) {
787
788 if(!tutils()->can_user_manage('question', $question_id)) {
789 continue;
790 }
791
792 $question_title = sanitize_text_field($question['question_title']);
793 $question_description = wp_kses( $question['question_description'], $this->allowed_html ); // sanitize_text_field($question['question_description']);
794 $question_type = sanitize_text_field($question['question_type']);
795 $question_mark = sanitize_text_field($question['question_mark']);
796
797 unset($question['question_title']);
798 unset($question['question_description']);
799
800 $data = array(
801 'question_title' => $question_title,
802 'question_description' => $question_description,
803 'question_type' => $question_type,
804 'question_mark' => $question_mark,
805 'question_settings' => maybe_serialize($question),
806 );
807
808 $wpdb->update($wpdb->prefix.'tutor_quiz_questions', $data, array('question_id' => $question_id) );
809
810
811 /**
812 * Validation
813 */
814 if ($question_type === 'true_false' || $question_type === 'single_choice'){
815 $question_options = tutils()->get_answers_by_quiz_question($question_id);
816 if (tutils()->count($question_options)){
817 $required_validate = true;
818 foreach ($question_options as $question_option){
819 if ($question_option->is_correct){
820 $required_validate = false;
821 }
822 }
823 if ($required_validate){
824 $validation_msg = "<p class='tutor-error-msg'>".__('Please select the correct answer', 'tutor')."</p>";
825 wp_send_json_error(array('validation_msg' => $validation_msg ));
826 }
827 }else{
828 $validation_msg = "<p class='tutor-error-msg'>".__('Please make sure you have added more than one option and saved them', 'tutor')."</p>";
829 wp_send_json_error(array('validation_msg' => $validation_msg ));
830 }
831 }
832 }
833
834 wp_send_json_success();
835 }
836
837 public function tutor_quiz_builder_question_delete(){
838 tutils()->checking_nonce();
839
840 global $wpdb;
841
842 $question_id = sanitize_text_field(tutor_utils()->avalue_dot('question_id', $_POST));
843
844 if(!tutils()->can_user_manage('question', $question_id)) {
845 wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
846 }
847
848 if ($question_id){
849 $wpdb->delete($wpdb->prefix.'tutor_quiz_questions', array('question_id' => esc_sql( $question_id ) ));
850 }
851
852 wp_send_json_success();
853 }
854
855 /**
856 * Get answers options form for quiz question
857 *
858 * @since v.1.0.0
859 */
860 public function tutor_quiz_add_question_answers(){
861 tutils()->checking_nonce();
862
863 $question_id = sanitize_text_field($_POST['question_id']);
864 $question = tutor_utils()->avalue_dot($question_id, $_POST['tutor_quiz_question']);
865 $question_type = $question['question_type'];
866
867 if(!tutils()->can_user_manage('question', $question_id)) {
868 wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
869 }
870
871 ob_start();
872 include tutor()->path.'views/modal/question_answer_form.php';
873 $output = ob_get_clean();
874
875 wp_send_json_success(array('output' => $output));
876 }
877
878 /**
879 * Edit Answer Form
880 *
881 * @since v.1.0.0
882 */
883 public function tutor_quiz_edit_question_answer(){
884 tutils()->checking_nonce();
885
886 $answer_id = (int) sanitize_text_field($_POST['answer_id']);
887
888 if(!tutils()->can_user_manage('quiz_answer', $answer_id)) {
889 wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
890 }
891
892 $old_answer = tutor_utils()->get_answer_by_id($answer_id);
893 foreach ($old_answer as $old_answer);
894 $question_id = $old_answer->belongs_question_id;
895 $question_type = $old_answer->belongs_question_type;
896
897 ob_start();
898 include tutor()->path.'views/modal/question_answer_edit_form.php';
899 $output = ob_get_clean();
900
901 wp_send_json_success(array('output' => $output));
902 }
903
904 public function tutor_save_quiz_answer_options(){
905 tutils()->checking_nonce();
906
907 global $wpdb;
908
909 $questions = $_POST['tutor_quiz_question'];
910 $answers = $_POST['quiz_answer'];
911
912 foreach ($answers as $question_id => $answer){
913
914 if(!tutils()->can_user_manage('question', $question_id)) {
915 continue;
916 }
917
918 $question = tutor_utils()->avalue_dot($question_id, $questions);
919 $question_type = $question['question_type'];
920
921 //Getting next sorting order
922 $next_order_id = (int) $wpdb->get_var($wpdb->prepare(
923 "SELECT MAX(answer_order)
924 FROM {$wpdb->prefix}tutor_quiz_question_answers
925 where belongs_question_id = %d
926 AND belongs_question_type = %s ", $question_id, esc_sql( $question_type )));
927
928 $next_order_id = $next_order_id + 1;
929
930 if ($question){
931 if ($question_type === 'true_false'){
932 $wpdb->delete($wpdb->prefix.'tutor_quiz_question_answers', array('belongs_question_id' => $question_id, 'belongs_question_type' => $question_type));
933 $data_true_false = array(
934 array(
935 'belongs_question_id' => esc_sql( $question_id ) ,
936 'belongs_question_type' => $question_type,
937 'answer_title' => __('True', 'tutor'),
938 'is_correct' => $answer['true_false'] == 'true' ? 1 : 0,
939 'answer_two_gap_match' => 'true',
940 ),
941 array(
942 'belongs_question_id' => esc_sql( $question_id ) ,
943 'belongs_question_type' => $question_type,
944 'answer_title' => __('False', 'tutor'),
945 'is_correct' => $answer['true_false'] == 'false' ? 1 : 0,
946 'answer_two_gap_match' => 'false',
947 ),
948 );
949
950 foreach ($data_true_false as $true_false_data){
951 $wpdb->insert($wpdb->prefix.'tutor_quiz_question_answers', $true_false_data);
952 }
953
954 }elseif($question_type === 'multiple_choice' || $question_type === 'single_choice' || $question_type === 'ordering' ||
955 $question_type === 'matching' || $question_type === 'image_matching' || $question_type === 'image_answering' ){
956
957 $answer_data = array(
958 'belongs_question_id' => sanitize_text_field( $question_id ),
959 'belongs_question_type' => $question_type,
960 'answer_title' => sanitize_text_field( $answer['answer_title'] ),
961 'image_id' => isset($answer['image_id']) ? $answer['image_id'] : 0,
962 'answer_view_format' => isset($answer['answer_view_format']) ? $answer['answer_view_format'] : 0,
963 'answer_order' => $next_order_id,
964 );
965 if (isset($answer['matched_answer_title'])){
966 $answer_data['answer_two_gap_match'] = sanitize_text_field( $answer['matched_answer_title'] );
967 }
968
969 $wpdb->insert($wpdb->prefix.'tutor_quiz_question_answers', $answer_data);
970
971 }elseif($question_type === 'fill_in_the_blank'){
972 $wpdb->delete($wpdb->prefix.'tutor_quiz_question_answers', array('belongs_question_id' => $question_id, 'belongs_question_type' => $question_type));
973 $answer_data = array(
974 'belongs_question_id' => sanitize_text_field( $question_id ) ,
975 'belongs_question_type' => $question_type,
976 'answer_title' => sanitize_text_field( $answer['answer_title'] ),
977 'answer_two_gap_match' => isset($answer['answer_two_gap_match']) ? sanitize_text_field( trim($answer['answer_two_gap_match']) ) : null,
978 );
979 $wpdb->insert($wpdb->prefix.'tutor_quiz_question_answers', $answer_data);
980 }
981 }
982 }
983
984 wp_send_json_success();
985 }
986
987 /**
988 * Tutor Update Answer
989 *
990 * @since v.1.0.0
991 */
992 public function tutor_update_quiz_answer_options(){
993 tutils()->checking_nonce();
994
995 global $wpdb;
996
997 $answer_id = (int) sanitize_text_field($_POST['tutor_quiz_answer_id']);
998
999 if(!tutils()->can_user_manage('quiz_answer', $answer_id)) {
1000 wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
1001 }
1002
1003 $questions = $_POST['tutor_quiz_question'];
1004 $answers = $_POST['quiz_answer'];
1005
1006 foreach ($answers as $question_id => $answer){
1007 $question = tutor_utils()->avalue_dot($question_id, $questions);
1008 $question_type = $question['question_type'];
1009
1010 if ($question){
1011 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' ){
1012
1013 $answer_data = array(
1014 'belongs_question_id' => $question_id,
1015 'belongs_question_type' => $question_type,
1016 'answer_title' => sanitize_text_field( $answer['answer_title'] ) ,
1017 'image_id' => isset($answer['image_id']) ? $answer['image_id'] : 0,
1018 'answer_view_format' => isset($answer['answer_view_format']) ? sanitize_text_field( $answer['answer_view_format'] ) : '',
1019 );
1020 if (isset($answer['matched_answer_title'])){
1021 $answer_data['answer_two_gap_match'] = sanitize_text_field( $answer['matched_answer_title'] ) ;
1022 }
1023
1024 if ($question_type === 'fill_in_the_blank'){
1025 $answer_data['answer_two_gap_match'] = isset($answer['answer_two_gap_match']) ? sanitize_text_field(trim($answer['answer_two_gap_match'])) : null;
1026 }
1027
1028 $wpdb->update($wpdb->prefix.'tutor_quiz_question_answers', $answer_data, array('answer_id' => $answer_id));
1029 }
1030 }
1031 }
1032
1033 //die(print_r($_POST));
1034 wp_send_json_success();
1035 }
1036
1037 public function tutor_quiz_builder_get_answers_by_question(){
1038 tutils()->checking_nonce();
1039
1040 global $wpdb;
1041 $question_id = sanitize_text_field($_POST['question_id']);
1042 $question_type = sanitize_text_field($_POST['question_type']);
1043
1044 if(!tutils()->can_user_manage('question', $question_id)) {
1045 wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
1046 }
1047
1048 $question = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}tutor_quiz_questions WHERE question_id = %d ", $question_id));
1049 $answers = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$wpdb->prefix}tutor_quiz_question_answers where belongs_question_id = %d AND belongs_question_type = %s order by answer_order asc ;", $question_id, esc_sql( $question_type ) ));
1050
1051 ob_start();
1052
1053 switch ($question_type){
1054 case 'true_false':
1055 echo '<label>'.__('Answer options &amp; mark correct', 'tutor').'</label>';
1056 break;
1057 case 'ordering':
1058 echo '<label>'.__('Make sure you’re saving the answers in the right order. Students will have to match this order exactly.', 'tutor').'</label>';
1059 break;
1060 }
1061
1062 if (is_array($answers) && count($answers)){
1063 foreach ($answers as $answer){
1064 ?>
1065 <div class="tutor-quiz-answer-wrap" data-answer-id="<?php echo $answer->answer_id; ?>">
1066 <div class="tutor-quiz-answer">
1067 <span class="tutor-quiz-answer-title">
1068 <?php
1069 echo stripslashes($answer->answer_title);
1070 if ($answer->belongs_question_type === 'fill_in_the_blank'){
1071 echo ' ('.__('Answer', 'tutor').' : ';
1072 echo '<strong>'. stripslashes($answer->answer_two_gap_match). '</strong>)';
1073 }
1074 if ($answer->belongs_question_type === 'matching'){
1075 echo ' - '.stripslashes($answer->answer_two_gap_match);
1076 }
1077 ?>
1078 </span>
1079
1080 <?php
1081 if ($answer->image_id){
1082 echo '<span class="tutor-question-answer-image"><img src="'.wp_get_attachment_image_url($answer->image_id).'" /> </span>';
1083 }
1084 if ($question_type === 'true_false' || $question_type === 'single_choice'){
1085 ?>
1086 <span class="tutor-quiz-answers-mark-correct-wrap">
1087 <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); ?> >
1088 </span>
1089 <?php
1090 }elseif ($question_type === 'multiple_choice'){
1091 ?>
1092 <span class="tutor-quiz-answers-mark-correct-wrap">
1093 <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); ?> >
1094 </span>
1095 <?php
1096 }
1097 ?>
1098 <span class="tutor-quiz-answer-edit">
1099 <a href="javascript:;"><i class="tutor-icon-pencil"></i> </a>
1100 </span>
1101 <span class="tutor-quiz-answer-sort-icon"><i class="tutor-icon-menu-2"></i> </span>
1102 </div>
1103
1104 <div class="tutor-quiz-answer-trash-wrap">
1105 <a href="javascript:;" class="answer-trash-btn" data-answer-id="<?php echo $answer->answer_id; ?>"><i class="tutor-icon-garbage"></i> </a>
1106 </div>
1107 </div>
1108 <?php
1109 }
1110 }
1111 $output = ob_get_clean();
1112
1113 wp_send_json_success(array('output' => $output));
1114 }
1115
1116 public function tutor_quiz_builder_delete_answer(){
1117 tutils()->checking_nonce();
1118
1119 global $wpdb;
1120 $answer_id = sanitize_text_field($_POST['answer_id']);
1121
1122 if(!tutils()->can_user_manage('quiz_answer', $answer_id)) {
1123 wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
1124 }
1125
1126 $wpdb->delete($wpdb->prefix.'tutor_quiz_question_answers', array('answer_id' => esc_sql( $answer_id ) ));
1127 wp_send_json_success();
1128 }
1129
1130 /**
1131 * Save quiz questions sorting
1132 */
1133 public function tutor_quiz_question_sorting(){
1134 tutils()->checking_nonce();
1135
1136 global $wpdb;
1137
1138 $question_ids = tutor_utils()->avalue_dot('sorted_question_ids', $_POST);
1139 if (is_array($question_ids) && count($question_ids) ){
1140 $i = 0;
1141 foreach ($question_ids as $key => $question_id){
1142 if(tutils()->can_user_manage('question', $question_id)) {
1143 $i++;
1144 $wpdb->update($wpdb->prefix.'tutor_quiz_questions', array('question_order' => $i), array('question_id' => $question_id));
1145 }
1146 }
1147 }
1148 }
1149
1150 /**
1151 * Save sorting data for quiz answers
1152 */
1153 public function tutor_quiz_answer_sorting(){
1154 tutils()->checking_nonce();
1155
1156 global $wpdb;
1157
1158 if ( ! empty($_POST['sorted_answer_ids']) && is_array($_POST['sorted_answer_ids']) && count($_POST['sorted_answer_ids']) ){
1159 $answer_ids = $_POST['sorted_answer_ids'];
1160 $i = 0;
1161 foreach ($answer_ids as $key => $answer_id){
1162 if(tutils()->can_user_manage('quiz_answer', $answer_id)) {
1163 $i++;
1164 $wpdb->update($wpdb->prefix.'tutor_quiz_question_answers', array('answer_order' => $i), array('answer_id' => $answer_id));
1165 }
1166 }
1167 }
1168 }
1169
1170 /**
1171 * Mark answer as correct
1172 */
1173
1174 public function tutor_mark_answer_as_correct(){
1175 tutils()->checking_nonce();
1176
1177 global $wpdb;
1178
1179 $answer_id = sanitize_text_field($_POST['answer_id']);
1180 $inputValue = sanitize_text_field($_POST['inputValue']);
1181
1182 if(!tutils()->can_user_manage('quiz_answer', $answer_id)) {
1183 wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
1184 }
1185
1186 $answer = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}tutor_quiz_question_answers WHERE answer_id = %d LIMIT 0,1 ;", $answer_id));
1187 if ($answer->belongs_question_type === 'single_choice') {
1188 $wpdb->update($wpdb->prefix.'tutor_quiz_question_answers', array('is_correct' => 0), array('belongs_question_id' => esc_sql( $answer->belongs_question_id ) ));
1189 }
1190 $wpdb->update($wpdb->prefix.'tutor_quiz_question_answers', array('is_correct' => esc_sql( $inputValue ) ), array('answer_id' => esc_sql( $answer_id ) ));
1191 }
1192
1193 /**
1194 * Update quiz settings from modal
1195 *
1196 * @since : v.1.0.0
1197 */
1198 public function tutor_quiz_modal_update_settings(){
1199 tutils()->checking_nonce();
1200
1201 $quiz_id = sanitize_text_field($_POST['quiz_id']);
1202 $quiz_option = tutor_utils()->sanitize_array($_POST['quiz_option']);
1203
1204 if(!tutils()->can_user_manage('quiz', $quiz_id)) {
1205 wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
1206 }
1207
1208 update_post_meta($quiz_id, 'tutor_quiz_option', $quiz_option);
1209 do_action('tutor_quiz_settings_updated', $quiz_id);
1210 wp_send_json_success();
1211 }
1212
1213
1214 //=========================//
1215 // Front end stuffs
1216 //=========================//
1217
1218 /**
1219 * Rendering quiz for frontend
1220 *
1221 * @since v.1.0.0
1222 */
1223
1224 public function tutor_render_quiz_content(){
1225
1226 tutils()->checking_nonce();
1227
1228 $quiz_id = (int) sanitize_text_field(tutor_utils()->avalue_dot('quiz_id', $_POST));
1229
1230 if(!tutils()->has_enrolled_content_access('quiz', $quiz_id)) {
1231 wp_send_json_error( array('message'=>__('Access Denied.', 'tutor')) );
1232 }
1233
1234 ob_start();
1235 global $post;
1236
1237 $post = get_post($quiz_id);
1238 setup_postdata($post);
1239 //tutor_lesson_content();
1240
1241 single_quiz_contents();
1242 wp_reset_postdata();
1243
1244 $html = ob_get_clean();
1245 wp_send_json_success(array('html' => $html));
1246 }
1247
1248 }