PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 1.4.8
Tutor LMS – eLearning and online course solution v1.4.8
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
982 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 public function remove_quiz_from_post(){
83 global $wpdb;
84 $quiz_id = (int) tutor_utils()->avalue_dot('quiz_id', $_POST);
85 $wpdb->update($wpdb->posts, array('post_parent' => 0), array('ID' => $quiz_id) );
86 wp_send_json_success();
87 }
88
89 /**
90 *
91 * Start Quiz from here...
92 *
93 * @since v.1.0.0
94 */
95
96 public function start_the_quiz(){
97 if ( ! isset($_POST['tutor_action']) || $_POST['tutor_action'] !== 'tutor_start_quiz' ){
98 return;
99 }
100 //Checking nonce
101 tutor_utils()->checking_nonce();
102
103 if ( ! is_user_logged_in()){
104 //TODO: need to set a view in the next version
105 die('Please sign in to do this operation');
106 }
107
108 global $wpdb;
109
110 $user_id = get_current_user_id();
111 $user = get_userdata($user_id);
112
113 $quiz_id = (int) sanitize_text_field($_POST['quiz_id']);
114
115 $quiz = get_post($quiz_id);
116 $course = tutor_utils()->get_course_by_quiz($quiz_id);
117 if ( empty($course->ID)){
118 die('There is something went wrong with course, please check if quiz attached with a course');
119 }
120
121 $date = date("Y-m-d H:i:s", tutor_time());
122
123 $tutor_quiz_option = (array) maybe_unserialize(get_post_meta($quiz_id, 'tutor_quiz_option', true));
124 $attempts_allowed = tutor_utils()->get_quiz_option($quiz_id, 'attempts_allowed', 0);
125
126 $time_limit = tutor_utils()->get_quiz_option($quiz_id, 'time_limit.time_value');
127 $time_limit_seconds = 0;
128 $time_type = 'seconds';
129 if ($time_limit){
130 $time_type = tutor_utils()->get_quiz_option($quiz_id, 'time_limit.time_type');
131
132 switch ($time_type){
133 case 'seconds':
134 $time_limit_seconds = $time_limit;
135 break;
136 case 'minutes':
137 $time_limit_seconds = $time_limit * 60;
138 break;
139 case 'hours':
140 $time_limit_seconds = $time_limit * 60 * 60;
141 break;
142 case 'days':
143 $time_limit_seconds = $time_limit * 60 * 60 * 24;
144 break;
145 case 'weeks':
146 $time_limit_seconds = $time_limit * 60 * 60 * 24 * 7;
147 break;
148 }
149 }
150
151 $max_question_allowed = tutor_utils()->max_questions_for_take_quiz($quiz_id);
152 $tutor_quiz_option['time_limit']['time_limit_seconds'] = $time_limit_seconds;
153
154 $attempt_data = array(
155 'course_id' => $course->ID,
156 'quiz_id' => $quiz_id,
157 'user_id' => $user_id,
158 'total_questions' => $max_question_allowed,
159 'total_answered_questions' => 0,
160 'attempt_info' => maybe_serialize($tutor_quiz_option),
161 'attempt_status' => 'attempt_started',
162 'attempt_ip' => tutor_utils()->get_ip(),
163 'attempt_started_at' => $date,
164 );
165
166 $wpdb->insert($wpdb->prefix.'tutor_quiz_attempts', $attempt_data);
167 $attempt_id = (int) $wpdb->insert_id;
168
169 wp_redirect(get_permalink($quiz_id));
170 die();
171 }
172
173 public function answering_quiz(){
174 if ( tutils()->array_get('tutor_action', $_POST) !== 'tutor_answering_quiz_question' ){
175 return;
176 }
177 //Checking nonce
178 tutor_utils()->checking_nonce();
179
180 $attempt_id = (int) sanitize_text_field(tutor_utils()->avalue_dot('attempt_id', $_POST));
181 $attempt = tutor_utils()->get_attempt($attempt_id);
182
183 $attempt_answers = isset($_POST['attempt']) ? $_POST['attempt'] : false;
184 if ( ! is_user_logged_in()){
185 die('Please sign in to do this operation');
186 }
187
188 global $wpdb;
189 $user_id = get_current_user_id();
190
191 do_action('tutor_quiz/attempt_analysing/before', $attempt_id);
192
193 if ($attempt_answers && is_array($attempt_answers) && count($attempt_answers)){
194 foreach ($attempt_answers as $attempt_id => $attempt_answers){
195
196 /**
197 * Get total marks of all question comes
198 */
199 $question_ids = tutor_utils()->avalue_dot('quiz_question_ids', $attempt_answers);
200 if (is_array($question_ids) && count($question_ids)){
201 $question_ids_string = "'".implode("','", $question_ids)."'";
202 $total_question_marks = $wpdb->get_var("SELECT SUM(question_mark) FROM {$wpdb->prefix}tutor_quiz_questions WHERE question_id IN({$question_ids_string}) ;");
203 $wpdb->update($wpdb->prefix.'tutor_quiz_attempts', array('total_marks' =>$total_question_marks ), array('attempt_id' => $attempt_id ));
204 }
205
206 if ( ! $attempt || $user_id != $attempt->user_id){
207 die('Operation not allowed, attempt not found or permission denied');
208 }
209
210 $quiz_answers = tutor_utils()->avalue_dot('quiz_question', $attempt_answers);
211
212 $total_marks = 0;
213
214 if ( tutils()->count($quiz_answers)) {
215
216 foreach ( $quiz_answers as $question_id => $answers ) {
217 $question = tutor_utils()->get_quiz_question_by_id( $question_id );
218 $question_type = $question->question_type;
219
220 $is_answer_was_correct = false;
221 $given_answer = '';
222
223 if ( $question_type === 'true_false' || $question_type === 'single_choice' ) {
224
225 $given_answer = $answers;
226 $is_answer_was_correct = (bool) $wpdb->get_var( "SELECT is_correct FROM {$wpdb->prefix}tutor_quiz_question_answers WHERE answer_id = {$answers} " );
227
228 } elseif ( $question_type === 'multiple_choice' ) {
229
230 $given_answer = maybe_serialize( $answers );
231 $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 ;" );
232 if ( maybe_serialize( $get_original_answers ) == $given_answer ) {
233 $is_answer_was_correct = true;
234 }
235
236 } elseif ( $question_type === 'fill_in_the_blank' ) {
237
238 $given_answer = (array) array_map( 'sanitize_text_field', $answers );
239 $given_answer = maybe_serialize( $given_answer );
240
241 $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}' ;" );
242 $gap_answer = (array) explode( '|', $get_original_answer->answer_two_gap_match );
243
244 $gap_answer = array_map( 'sanitize_text_field', $gap_answer );
245 if ( $given_answer == maybe_serialize( $gap_answer ) ) {
246 $is_answer_was_correct = true;
247 }
248
249 } elseif ( $question_type === 'open_ended' || $question_type === 'short_answer' ) {
250
251 $given_answer = wp_kses_post( $answers );
252
253 } elseif ( $question_type === 'ordering' || $question_type === 'matching' || $question_type === 'image_matching' ) {
254
255 $given_answer = (array) array_map( 'sanitize_text_field', tutor_utils()->avalue_dot( 'answers', $answers ) );
256 $given_answer = maybe_serialize( $given_answer );
257
258 $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 ;" );
259 $get_original_answers = array_map( 'sanitize_text_field', $get_original_answers );
260
261 if ( $given_answer == maybe_serialize( $get_original_answers ) ) {
262 $is_answer_was_correct = true;
263 }
264
265 } elseif ( $question_type === 'image_answering' ) {
266 echo '<pre>';
267
268 $image_inputs = tutor_utils()->avalue_dot( 'answer_id', $answers );
269 $image_inputs = (array) array_map( 'sanitize_text_field', $image_inputs );
270 $given_answer = maybe_serialize( $image_inputs );
271 $is_answer_was_correct = false;
272
273 $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 =
274 'image_answering' ORDER BY answer_order asc ;" );
275
276 if ( is_array( $db_answer ) && count( $db_answer ) ) {
277 $is_answer_was_correct = ( strtolower( maybe_serialize( array_values( $image_inputs ) ) ) == strtolower( maybe_serialize( $db_answer ) ) );
278 }
279 }
280
281 $question_mark = $is_answer_was_correct ? $question->question_mark : 0;
282 $total_marks += $question_mark;
283
284 $answers_data = array(
285 'user_id' => $user_id,
286 'quiz_id' => $attempt->quiz_id,
287 'question_id' => $question_id,
288 'quiz_attempt_id' => $attempt_id,
289 'given_answer' => $given_answer,
290 'question_mark' => $question->question_mark,
291 'achieved_mark' => $question_mark,
292 'minus_mark' => 0,
293 'is_correct' => $is_answer_was_correct ? 1 : 0,
294 );
295 $wpdb->insert( $wpdb->prefix . 'tutor_quiz_attempt_answers', $answers_data );
296 }
297 }
298
299 $attempt_info = array(
300 'total_answered_questions' => tutils()->count($quiz_answers),
301 'earned_marks' => $total_marks,
302 'attempt_status' => 'attempt_ended',
303 'attempt_ended_at' => date("Y-m-d H:i:s", tutor_time()),
304 );
305 $wpdb->update($wpdb->prefix.'tutor_quiz_attempts', $attempt_info, array('attempt_id' => $attempt_id));
306 }
307
308 do_action('tutor_quiz/attempt_ended', $attempt_id);
309 }
310
311 wp_redirect(get_the_permalink($attempt->quiz_id));
312 die();
313 }
314
315
316 /**
317 * Quiz attempt will be finish here
318 *
319 */
320
321 public function finishing_quiz_attempt(){
322 if ( ! isset($_POST['tutor_action']) || $_POST['tutor_action'] !== 'tutor_finish_quiz_attempt' ){
323 return;
324 }
325 //Checking nonce
326 tutor_utils()->checking_nonce();
327
328 if ( ! is_user_logged_in()){
329 die('Please sign in to do this operation');
330 }
331
332 global $wpdb;
333
334 $quiz_id = (int) sanitize_text_field($_POST['quiz_id']);
335 $attempt = tutor_utils()->is_started_quiz($quiz_id);
336 $attempt_id = $attempt->attempt_id;
337
338 $attempt_info = array(
339 'total_answered_questions' => 0,
340 'earned_marks' => 0,
341 'attempt_status' => 'attempt_ended',
342 'attempt_ended_at' => date("Y-m-d H:i:s", tutor_time()),
343 );
344
345 do_action('tutor_quiz_before_finish', $attempt_id, $quiz_id, $attempt->user_id);
346 $wpdb->update($wpdb->prefix.'tutor_quiz_attempts', $attempt_info, array('attempt_id' => $attempt_id));
347 do_action('tutor_quiz_finished', $attempt_id, $quiz_id, $attempt->user_id);
348
349 wp_redirect(tutor_utils()->input_old('_wp_http_referer'));
350 }
351
352 /**
353 * Quiz timeout by ajax
354 */
355 public function tutor_quiz_timeout(){
356 global $wpdb;
357
358 $quiz_id = (int) sanitize_text_field($_POST['quiz_id']);
359 $attempt = tutor_utils()->is_started_quiz($quiz_id);
360
361 if ($attempt) {
362 $attempt_id = $attempt->attempt_id;
363
364 $data = array(
365 'attempt_status' => 'attempt_timeout',
366 'attempt_ended_at' => date("Y-m-d H:i:s", tutor_time()),
367 );
368 $wpdb->update($wpdb->prefix.'tutor_quiz_attempts', $data, array('attempt_id' => $attempt->attempt_id));
369
370 do_action('tutor_quiz_timeout', $attempt_id, $quiz_id, $attempt->user_id);
371
372 wp_send_json_success();
373 }
374
375 wp_send_json_error(__('Quiz has been timeout already', 'tutor'));
376 }
377
378 /**
379 * Review the answer and change individual answer result
380 */
381
382 public function review_quiz_answer(){
383 global $wpdb;
384 $attempt_id = (int) sanitize_text_field($_GET['attempt_id']);
385 $attempt_answer_id = (int) sanitize_text_field($_GET['attempt_answer_id']);
386 $mark_as = sanitize_text_field($_GET['mark_as']);
387
388 $attempt_answer = $wpdb->get_row("SELECT * FROM {$wpdb->prefix}tutor_quiz_attempt_answers WHERE attempt_answer_id = {$attempt_answer_id} ");
389 $attempt = tutor_utils()->get_attempt($attempt_id);
390
391 $is_correct = (int) $attempt_answer->is_correct;
392
393 do_action('tutor_quiz_review_answer_before', $attempt_answer_id, $attempt_id, $mark_as);
394
395 if ($mark_as === 'correct' && ! $is_correct){
396
397 $answer_update_data = array(
398 'achieved_mark' => $attempt_answer->question_mark,
399 'is_correct' => 1,
400 );
401 $wpdb->update($wpdb->prefix.'tutor_quiz_attempt_answers', $answer_update_data, array('attempt_answer_id' => $attempt_answer_id ));
402
403 $attempt_update_data = array(
404 'earned_marks' => $attempt->earned_marks + $attempt_answer->question_mark,
405 'is_manually_reviewed' => 1,
406 'manually_reviewed_at' => date("Y-m-d H:i:s", tutor_time()),
407 );
408
409 $wpdb->update($wpdb->prefix.'tutor_quiz_attempts', $attempt_update_data, array('attempt_id' => $attempt_id ));
410
411 }elseif($mark_as === 'incorrect' && $is_correct){
412
413 $answer_update_data = array(
414 'achieved_mark' => '0.00',
415 'is_correct' => 0,
416 );
417 $wpdb->update($wpdb->prefix.'tutor_quiz_attempt_answers', $answer_update_data, array('attempt_answer_id' => $attempt_answer_id ));
418
419 $attempt_update_data = array(
420 'earned_marks' => $attempt->earned_marks - $attempt_answer->question_mark,
421 'is_manually_reviewed' => 1,
422 'manually_reviewed_at' => date("Y-m-d H:i:s", tutor_time()),
423 );
424
425 $wpdb->update($wpdb->prefix.'tutor_quiz_attempts', $attempt_update_data, array('attempt_id' => $attempt_id ));
426 }
427 do_action('tutor_quiz_review_answer_after', $attempt_answer_id, $attempt_id, $mark_as);
428
429 if (wp_doing_ajax()){
430 wp_send_json_success();
431 }else{
432 wp_redirect(admin_url("admin.php?page=tutor_quiz_attempts&sub_page=view_attempt&attempt_id=".$attempt_id));
433 }
434
435 die();
436 }
437
438
439 /**
440 * New Design Quiz
441 */
442 public function tutor_create_quiz_and_load_modal(){
443 $topic_id = sanitize_text_field($_POST['topic_id']);
444 $quiz_title = sanitize_text_field($_POST['quiz_title']);
445 $quiz_description = sanitize_text_field($_POST['quiz_description']);
446 $next_order_id = tutor_utils()->get_next_course_content_order_id($topic_id);
447
448 $post_arr = array(
449 'post_type' => 'tutor_quiz',
450 'post_title' => $quiz_title,
451 'post_content' => $quiz_description,
452 'post_status' => 'publish',
453 'post_author' => get_current_user_id(),
454 'post_parent' => $topic_id,
455 'menu_order' => $next_order_id,
456 );
457 $quiz_id = wp_insert_post( $post_arr );
458 do_action('tutor_initial_quiz_created', $quiz_id);
459
460 ob_start();
461 include tutor()->path.'views/modal/edit_quiz.php';
462 $output = ob_get_clean();
463
464 ob_start();
465 ?>
466 <div id="tutor-quiz-<?php echo $quiz_id; ?>" class="course-content-item tutor-quiz tutor-quiz-<?php echo $quiz_id; ?>">
467 <div class="tutor-lesson-top">
468 <i class="tutor-icon-move"></i>
469 <a href="javascript:;" class="open-tutor-quiz-modal" data-quiz-id="<?php echo $quiz_id; ?>" data-topic-id="<?php echo $topic_id;
470 ?>"> <i class=" tutor-icon-doubt"></i>[QUIZ] <?php echo $quiz_title; ?> </a>
471 <a href="javascript:;" class="tutor-delete-quiz-btn" data-quiz-id="<?php echo $quiz_id; ?>"><i class="tutor-icon-garbage"></i></a>
472 </div>
473 </div>
474 <?php
475 $output_quiz_row = ob_get_clean();
476
477 wp_send_json_success(array('output' => $output, 'output_quiz_row' => $output_quiz_row));
478 }
479
480 public function tutor_delete_quiz_by_id(){
481 global $wpdb;
482
483 $quiz_id = (int) sanitize_text_field($_POST['quiz_id']);
484 $post = get_post($quiz_id);
485
486 if ( $post->post_type === 'tutor_quiz'){
487 do_action('tutor_delete_quiz_before', $quiz_id);
488
489 $wpdb->delete($wpdb->prefix.'tutor_quiz_attempts', array('quiz_id' => $quiz_id));
490 $wpdb->delete($wpdb->prefix.'tutor_quiz_attempt_answers', array('quiz_id' => $quiz_id));
491
492 $questions_ids = $wpdb->get_col("SELECT question_id FROM {$wpdb->prefix}tutor_quiz_questions WHERE quiz_id = {$quiz_id} ");
493 if (is_array($questions_ids) && count($questions_ids)){
494 $in_question_ids = "'".implode("','", $questions_ids)."'";
495 $wpdb->query("DELETE FROM {$wpdb->prefix}tutor_quiz_question_answers WHERE belongs_question_id IN({$in_question_ids}) ");
496 }
497 $wpdb->delete($wpdb->prefix.'tutor_quiz_questions', array('quiz_id' => $quiz_id));
498
499 wp_delete_post($quiz_id, true);
500 delete_post_meta($quiz_id, '_tutor_course_id_for_lesson');
501
502 do_action('tutor_delete_quiz_after', $quiz_id);
503
504
505 wp_send_json_success();
506 }
507
508 wp_send_json_error();
509 }
510
511 /**
512 * Update Quiz from quiz builder modal
513 *
514 * @since v.1.0.0
515 */
516 public function tutor_quiz_builder_quiz_update(){
517 $quiz_id = sanitize_text_field($_POST['quiz_id']);
518 $topic_id = sanitize_text_field($_POST['topic_id']);
519 $quiz_title = sanitize_text_field($_POST['quiz_title']);
520 $quiz_description = sanitize_text_field($_POST['quiz_description']);
521
522 $post_arr = array(
523 'ID' => $quiz_id,
524 'post_title' => $quiz_title,
525 'post_content' => $quiz_description,
526
527 );
528 $quiz_id = wp_update_post( $post_arr );
529
530 do_action('tutor_quiz_updated', $quiz_id);
531
532 ob_start();
533 ?>
534 <div class="tutor-lesson-top">
535 <i class="tutor-icon-move"></i>
536 <a href="javascript:;" class="open-tutor-quiz-modal" data-quiz-id="<?php echo $quiz_id; ?>" data-topic-id="<?php echo $topic_id;
537 ?>"> <i class=" tutor-icon-doubt"></i>[QUIZ] <?php echo $quiz_title; ?> </a>
538 <a href="javascript:;" class="tutor-delete-quiz-btn" data-quiz-id="<?php echo $quiz_id; ?>"><i class="tutor-icon-garbage"></i></a>
539 </div>
540 <?php
541 $output_quiz_row = ob_get_clean();
542
543 wp_send_json_success(array('output_quiz_row' => $output_quiz_row));
544 }
545
546 /**
547 * Load quiz Modal for edit quiz
548 *
549 * @since v.1.0.0
550 */
551 public function tutor_load_edit_quiz_modal(){
552 $quiz_id = sanitize_text_field($_POST['quiz_id']);
553
554 ob_start();
555 include tutor()->path.'views/modal/edit_quiz.php';
556 $output = ob_get_clean();
557
558 wp_send_json_success(array('output' => $output));
559 }
560
561 /**
562 * Load quiz question form for quiz
563 *
564 * @since v.1.0.0
565 */
566 public function tutor_quiz_builder_get_question_form(){
567 global $wpdb;
568 $quiz_id = sanitize_text_field($_POST['quiz_id']);
569 $question_id = sanitize_text_field(tutor_utils()->avalue_dot('question_id', $_POST));
570
571 if ( ! $question_id){
572 $next_question_id = tutor_utils()->quiz_next_question_id();
573 $next_question_order = tutor_utils()->quiz_next_question_order_id($quiz_id);
574
575 $new_question_data = array(
576 'quiz_id' => $quiz_id,
577 'question_title' => __('Question ').$next_question_id,
578 'question_description' => '',
579 'question_type' => 'true_false',
580 'question_mark' => 1,
581 'question_settings' => maybe_serialize(array()),
582 'question_order' => $next_question_order,
583 );
584
585 $wpdb->insert($wpdb->prefix.'tutor_quiz_questions', $new_question_data);
586 $question_id = $wpdb->insert_id;
587 }
588
589 $question = $wpdb->get_row("SELECT * FROM {$wpdb->prefix}tutor_quiz_questions where question_id = {$question_id} ");
590
591 ob_start();
592 include tutor()->path.'views/modal/question_form.php';
593 $output = ob_get_clean();
594
595 wp_send_json_success(array('output' => $output));
596 }
597
598 public function tutor_quiz_modal_update_question(){
599 global $wpdb;
600
601 $question_data = $_POST['tutor_quiz_question'];
602
603 foreach ($question_data as $question_id => $question){
604 $question_title = sanitize_text_field($question['question_title']);
605 $question_description = $question['question_description'];
606 $question_type = $question['question_type'];
607 $question_mark = $question['question_mark'];
608
609 unset($question['question_title']);
610 unset($question['question_description']);
611
612 $data = array(
613 'question_title' => $question_title,
614 'question_description' => $question_description,
615 'question_type' => $question_type,
616 'question_mark' => $question_mark,
617 'question_settings' => maybe_serialize($question),
618 );
619
620 $wpdb->update($wpdb->prefix.'tutor_quiz_questions', $data, array('question_id' => $question_id) );
621
622
623 /**
624 * Validation
625 */
626 if ($question_type === 'true_false' || $question_type === 'single_choice'){
627 $question_options = tutils()->get_answers_by_quiz_question($question_id);
628 if (tutils()->count($question_options)){
629 $required_validate = true;
630 foreach ($question_options as $question_option){
631 if ($question_option->is_correct){
632 $required_validate = false;
633 }
634 }
635 if ($required_validate){
636 $validation_msg = "<p class='tutor-error-msg'>".__('Please select the correct answer', 'tutor')."</p>";
637 wp_send_json_error(array('validation_msg' => $validation_msg ));
638 }
639 }else{
640 $validation_msg = "<p class='tutor-error-msg'>".__('Please make sure you have added more than one option and saved them', 'tutor')."</p>";
641 wp_send_json_error(array('validation_msg' => $validation_msg ));
642 }
643 }
644 }
645
646 wp_send_json_success();
647 }
648
649 public function tutor_quiz_builder_question_delete(){
650 global $wpdb;
651
652 $question_id = sanitize_text_field(tutor_utils()->avalue_dot('question_id', $_POST));
653 if ($question_id){
654 $wpdb->delete($wpdb->prefix.'tutor_quiz_questions', array('question_id' => $question_id));
655 }
656
657 wp_send_json_success();
658 }
659
660 /**
661 * Get answers options form for quiz question
662 *
663 * @since v.1.0.0
664 */
665 public function tutor_quiz_add_question_answers(){
666 $question_id = sanitize_text_field($_POST['question_id']);
667 $question = tutor_utils()->avalue_dot($question_id, $_POST['tutor_quiz_question']);
668 $question_type = $question['question_type'];
669
670 ob_start();
671 include tutor()->path.'views/modal/question_answer_form.php';
672 $output = ob_get_clean();
673
674 wp_send_json_success(array('output' => $output));
675 }
676
677 /**
678 * Edit Answer Form
679 *
680 * @since v.1.0.0
681 */
682 public function tutor_quiz_edit_question_answer(){
683 $answer_id = (int) sanitize_text_field($_POST['answer_id']);
684 $old_answer = tutor_utils()->get_answer_by_id($answer_id);
685 foreach ($old_answer as $old_answer);
686 $question_id = $old_answer->belongs_question_id;
687 $question_type = $old_answer->belongs_question_type;
688
689 ob_start();
690 include tutor()->path.'views/modal/question_answer_edit_form.php';
691 $output = ob_get_clean();
692
693 wp_send_json_success(array('output' => $output));
694 }
695
696 public function tutor_save_quiz_answer_options(){
697 global $wpdb;
698
699 $questions = $_POST['tutor_quiz_question'];
700 $answers = $_POST['quiz_answer'];
701
702 foreach ($answers as $question_id => $answer){
703 $question = tutor_utils()->avalue_dot($question_id, $questions);
704 $question_type = $question['question_type'];
705
706 //Getting next sorting order
707 $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}' ");
708 $next_order_id = $next_order_id + 1;
709
710 if ($question){
711 if ($question_type === 'true_false'){
712 $wpdb->delete($wpdb->prefix.'tutor_quiz_question_answers', array('belongs_question_id' => $question_id, 'belongs_question_type' => $question_type));
713 $data_true_false = array(
714 array(
715 'belongs_question_id' => $question_id,
716 'belongs_question_type' => $question_type,
717 'answer_title' => __('True', 'tutor'),
718 'is_correct' => $answer['true_false'] == 'true' ? 1 : 0,
719 'answer_two_gap_match' => 'true',
720 ),
721 array(
722 'belongs_question_id' => $question_id,
723 'belongs_question_type' => $question_type,
724 'answer_title' => __('False', 'tutor'),
725 'is_correct' => $answer['true_false'] == 'false' ? 1 : 0,
726 'answer_two_gap_match' => 'false',
727 ),
728 );
729
730 foreach ($data_true_false as $true_false_data){
731 $wpdb->insert($wpdb->prefix.'tutor_quiz_question_answers', $true_false_data);
732 }
733
734 }elseif($question_type === 'multiple_choice' || $question_type === 'single_choice' || $question_type === 'ordering' ||
735 $question_type === 'matching' || $question_type === 'image_matching' || $question_type === 'image_answering' ){
736
737 $answer_data = array(
738 'belongs_question_id' => $question_id,
739 'belongs_question_type' => $question_type,
740 'answer_title' => $answer['answer_title'],
741 'image_id' => isset($answer['image_id']) ? $answer['image_id'] : 0,
742 'answer_view_format' => isset($answer['answer_view_format']) ? $answer['answer_view_format'] : 0,
743 'answer_order' => $next_order_id,
744 );
745 if (isset($answer['matched_answer_title'])){
746 $answer_data['answer_two_gap_match'] = $answer['matched_answer_title'];
747 }
748
749 $wpdb->insert($wpdb->prefix.'tutor_quiz_question_answers', $answer_data);
750
751 }elseif($question_type === 'fill_in_the_blank'){
752 $wpdb->delete($wpdb->prefix.'tutor_quiz_question_answers', array('belongs_question_id' => $question_id, 'belongs_question_type' => $question_type));
753 $answer_data = array(
754 'belongs_question_id' => $question_id,
755 'belongs_question_type' => $question_type,
756 'answer_title' => $answer['answer_title'],
757 'answer_two_gap_match' => isset($answer['answer_two_gap_match']) ? strtolower(trim($answer['answer_two_gap_match'])) : null,
758 );
759 $wpdb->insert($wpdb->prefix.'tutor_quiz_question_answers', $answer_data);
760 }
761 }
762 }
763
764 wp_send_json_success();
765 }
766
767 /**
768 * Tutor Update Answer
769 *
770 * @since v.1.0.0
771 */
772 public function tutor_update_quiz_answer_options(){
773 global $wpdb;
774
775 $answer_id = (int) sanitize_text_field($_POST['tutor_quiz_answer_id']);
776 $questions = $_POST['tutor_quiz_question'];
777 $answers = $_POST['quiz_answer'];
778
779 foreach ($answers as $question_id => $answer){
780 $question = tutor_utils()->avalue_dot($question_id, $questions);
781 $question_type = $question['question_type'];
782
783 if ($question){
784 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' ){
785
786 $answer_data = array(
787 'belongs_question_id' => $question_id,
788 'belongs_question_type' => $question_type,
789 'answer_title' => $answer['answer_title'],
790 'image_id' => isset($answer['image_id']) ? $answer['image_id'] : 0,
791 'answer_view_format' => isset($answer['answer_view_format']) ? $answer['answer_view_format'] : '',
792 );
793 if (isset($answer['matched_answer_title'])){
794 $answer_data['answer_two_gap_match'] = $answer['matched_answer_title'];
795 }
796
797 if ($question_type === 'fill_in_the_blank'){
798 $answer_data['answer_two_gap_match'] = isset($answer['answer_two_gap_match']) ? strtolower(trim($answer['answer_two_gap_match'])) : null;
799 }
800
801 $wpdb->update($wpdb->prefix.'tutor_quiz_question_answers', $answer_data, array('answer_id' => $answer_id));
802 }
803 }
804 }
805
806 //die(print_r($_POST));
807 wp_send_json_success();
808 }
809
810 public function tutor_quiz_builder_get_answers_by_question(){
811 global $wpdb;
812 $question_id = sanitize_text_field($_POST['question_id']);
813 $question_type = sanitize_text_field($_POST['question_type']);
814
815 $question = $wpdb->get_row("SELECT * FROM {$wpdb->prefix}tutor_quiz_questions WHERE question_id = {$question_id} ");
816 $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 ;");
817
818 ob_start();
819
820 switch ($question_type){
821 case 'true_false':
822 echo '<label>'.__('Answer options &amp; mark correct', 'tutor').'</label>';
823 break;
824 case 'ordering':
825 echo '<label>'.__('Make sure you’re saving the answers in the right order. Students will have to match this order exactly.', 'tutor').'</label>';
826 break;
827 }
828
829 if (is_array($answers) && count($answers)){
830 foreach ($answers as $answer){
831 ?>
832 <div class="tutor-quiz-answer-wrap" data-answer-id="<?php echo $answer->answer_id; ?>">
833 <div class="tutor-quiz-answer">
834 <span class="tutor-quiz-answer-title">
835 <?php
836 echo stripslashes($answer->answer_title);
837 if ($answer->belongs_question_type === 'fill_in_the_blank'){
838 echo ' ('.__('Answer', 'tutor').' : ';
839 echo "<strong>{$answer->answer_two_gap_match} </strong>)";
840 }
841 if ($answer->belongs_question_type === 'matching'){
842 echo " - {$answer->answer_two_gap_match}";
843 }
844 ?>
845 </span>
846
847 <?php
848 if ($answer->image_id){
849 echo '<span class="tutor-question-answer-image"><img src="'.wp_get_attachment_image_url($answer->image_id).'" /> </span>';
850 }
851 if ($question_type === 'true_false' || $question_type === 'single_choice'){
852 ?>
853 <span class="tutor-quiz-answers-mark-correct-wrap">
854 <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); ?> >
855 </span>
856 <?php
857 }elseif ($question_type === 'multiple_choice'){
858 ?>
859 <span class="tutor-quiz-answers-mark-correct-wrap">
860 <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); ?> >
861 </span>
862 <?php
863 }
864 ?>
865 <span class="tutor-quiz-answer-edit">
866 <a href="javascript:;"><i class="tutor-icon-pencil"></i> </a>
867 </span>
868 <span class="tutor-quiz-answer-sort-icon"><i class="tutor-icon-menu-2"></i> </span>
869 </div>
870
871 <div class="tutor-quiz-answer-trash-wrap">
872 <a href="javascript:;" class="answer-trash-btn" data-answer-id="<?php echo $answer->answer_id; ?>"><i class="tutor-icon-garbage"></i> </a>
873 </div>
874 </div>
875 <?php
876 }
877 }
878 $output = ob_get_clean();
879
880 wp_send_json_success(array('output' => $output));
881 }
882
883 public function tutor_quiz_builder_delete_answer(){
884 global $wpdb;
885 $answer_id = sanitize_text_field($_POST['answer_id']);
886
887 $wpdb->delete($wpdb->prefix.'tutor_quiz_question_answers', array('answer_id' => $answer_id));
888 wp_send_json_success();
889 }
890
891 /**
892 * Save quiz questions sorting
893 */
894 public function tutor_quiz_question_sorting(){
895 global $wpdb;
896
897 $question_ids = tutor_utils()->avalue_dot('sorted_question_ids', $_POST);
898 if (is_array($question_ids) && count($question_ids) ){
899 $i = 0;
900 foreach ($question_ids as $key => $question_id){
901 $i++;
902 $wpdb->update($wpdb->prefix.'tutor_quiz_questions', array('question_order' => $i), array('question_id' => $question_id));
903 }
904 }
905 }
906
907 /**
908 * Save sorting data for quiz answers
909 */
910 public function tutor_quiz_answer_sorting(){
911 global $wpdb;
912
913 if ( ! empty($_POST['sorted_answer_ids']) && is_array($_POST['sorted_answer_ids']) && count($_POST['sorted_answer_ids']) ){
914 $answer_ids = $_POST['sorted_answer_ids'];
915 $i = 0;
916 foreach ($answer_ids as $key => $answer_id){
917 $i++;
918 $wpdb->update($wpdb->prefix.'tutor_quiz_question_answers', array('answer_order' => $i), array('answer_id' => $answer_id));
919 }
920 }
921 }
922
923 /**
924 * Mark answer as correct
925 */
926
927 public function tutor_mark_answer_as_correct(){
928 global $wpdb;
929
930 $answer_id = sanitize_text_field($_POST['answer_id']);
931 $inputValue = sanitize_text_field($_POST['inputValue']);
932
933 $answer = $wpdb->get_row("SELECT * FROM {$wpdb->prefix}tutor_quiz_question_answers WHERE answer_id = {$answer_id} LIMIT 0,1 ;");
934 if ($answer->belongs_question_type === 'single_choice'){
935 $wpdb->update($wpdb->prefix.'tutor_quiz_question_answers', array('is_correct' => 0), array('belongs_question_id' => $answer->belongs_question_id));
936 }
937 $wpdb->update($wpdb->prefix.'tutor_quiz_question_answers', array('is_correct' => $inputValue), array('answer_id' => $answer_id));
938 }
939
940 /**
941 * Update quiz settings from modal
942 *
943 * @since : v.1.0.0
944 */
945 public function tutor_quiz_modal_update_settings(){
946 $quiz_id = sanitize_text_field($_POST['quiz_id']);
947 $quiz_option = tutor_utils()->sanitize_array($_POST['quiz_option']);
948
949 update_post_meta($quiz_id, 'tutor_quiz_option', $quiz_option);
950 do_action('tutor_quiz_settings_updated', $quiz_id);
951 wp_send_json_success();
952 }
953
954
955 //=========================//
956 // Front end stuffs
957 //=========================//
958
959 /**
960 * Rendering quiz for frontend
961 *
962 * @since v.1.0.0
963 */
964
965 public function tutor_render_quiz_content(){
966 $quiz_id = (int) sanitize_text_field(tutor_utils()->avalue_dot('quiz_id', $_POST));
967
968 ob_start();
969 global $post;
970
971 $post = get_post($quiz_id);
972 setup_postdata($post);
973 //tutor_lesson_content();
974
975 single_quiz_contents();
976 wp_reset_postdata();
977
978 $html = ob_get_clean();
979 wp_send_json_success(array('html' => $html));
980 }
981
982 }