PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.6
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.6
4.4.8 4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.9.1 4.3.9 4.3.8 4.3.7 4.1.6.9 4.1.6.9.1 4.1.6.9.2 4.1.6.9.3 4.1.6.9.4 4.1.7 4.1.7.1 4.1.7.2 4.1.7.3 4.1.7.3.1 4.1.7.3.2 4.2.0 All 139 releases
learnpress / inc / user-item / class-lp-user-item-quiz.php

class-lp-user-item-quiz.php in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.4.6, at inc/user-item/class-lp-user-item-quiz.php

907 lines 23.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Class LP_User_Item_Quiz
5 */
6 class LP_User_Item_Quiz extends LP_User_Item {
7 public $_item_type = LP_QUIZ_CPT;
8 public $_ref_type = LP_COURSE_CPT;
9 /**
10 * @var array
11 */
12 protected $_answers = array();
13
14 /**
15 * LP_User_Item_Quiz constructor.
16 *
17 * @param array $data
18 */
19 public function __construct( $data ) {
20 $this->_curd = new LP_Quiz_CURD();
21
22 parent::__construct( $data );
23 $this->_parse_answers();
24 }
25
26 /**
27 *
28 */
29 protected function _parse_answers() {
30 foreach ( array( '_question_answers', 'question_answers' ) as $k ) {
31 $answers = learn_press_get_user_item_meta( $this->get_user_item_id(), $k, true );
32
33 if ( $answers ) {
34 $this->_answers = $answers;
35 break;
36 }
37 }
38 }
39
40 /**
41 * Add user answer to DB.
42 *
43 * @param int|array $id
44 * @param mixed $values
45 *
46 * @return array|bool|LP_Quiz_Results|mixed
47 * @throws Exception
48 * @editor tungnx
49 * @modify 4.1.4.1 - comment - not use
50 */
51 /*
52 public function add_question_answer( $id, $values = null ) {
53 $results = $this->get_results( '' );
54
55 if ( ! $results ) {
56 return false;
57 }
58
59 $questions = $results->get( 'questions', array() );
60
61 if ( is_numeric( $id ) ) {
62 $values = array( $id => $values );
63 } else {
64 $values = (array) $id;
65 }
66
67 foreach ( $values as $id => $answer ) {
68 if ( ! $this->has_checked_question( $id ) ) {
69 if ( ! empty( $questions[ $id ] ) ) {
70 $questions[ $id ]['answered'] = $answer;
71 } else {
72 $questions[ $id ] = array( 'answered' => $answer );
73 }
74 }
75 }
76
77 $results['questions'] = $questions;
78
79 //LP_User_Items_Result_DB::instance()->update( $this->get_user_item_id(), wp_json_encode( $results->get() ) );
80
81 $this->calculate_results();
82
83 $cache_key = sprintf( 'quiz-%d-%d-%d', $this->get_user_id(), $this->get_course_id(), $this->get_item_id() );
84
85 LP_Object_Cache::set( $cache_key, false, 'learn-press/quiz-result' );
86
87 return $this->get_results( '' );
88 }*/
89
90 public function get_question_answer( $id ) {
91 $results = $this->get_results( '' );
92
93 if ( ! $results ) {
94 return false;
95 }
96
97 $questions = $results->get( 'questions', false );
98
99 if ( $questions && is_array( $questions[ $id ] ) ) {
100 return $questions[ $id ]['answered'];
101 }
102
103 return false;
104 }
105
106 /**
107 * Update data to database
108 *
109 * @param bool $force
110 * @param bool $wp_error
111 *
112 * @return bool|mixed
113 */
114 /*
115 public function update( $force = false, $wp_error = false ) {
116 $return = parent::update( $force, $wp_error );
117 $this->calculate_results();
118
119 return $return;
120 }*/
121
122 /**
123 * Get list of data to update to database
124 *
125 * @since 3.1.0
126 *
127 * @return array
128 */
129 public function get_mysql_data() {
130 $columns = parent::get_mysql_data();
131
132 return apply_filters( 'learn-press/update-user-item-quiz-data', $columns, $this->get_item_id(), $this->get_course_id(), $this->get_user_id() );
133 }
134
135 /**
136 * @return bool|LP_Quiz
137 */
138 public function get_quiz() {
139 return learn_press_get_quiz( $this->get_item_id() );
140 }
141
142 public function get_status_label( $status = '' ) {
143 $statuses = array(
144 'started' => __( 'In Progress', 'learnpress' ),
145 'in-progress' => __( 'In Progress', 'learnpress' ),
146 'completed' => __( 'Completed', 'learnpress' ),
147 'passed' => __( 'Passed', 'learnpress' ),
148 'failed' => __( 'Failed', 'learnpress' ),
149 );
150
151 if ( ! $status ) {
152 $status = $this->get_status();
153 }
154
155 return ! empty( $statuses[ $status ] ) ? $statuses[ $status ] : __( 'Not Started', 'learnpress' );
156 }
157
158 /**
159 * Get ID of the course that this item assigned to.
160 *
161 * @return array|mixed
162 */
163 public function get_course_id() {
164 return $this->get_data( 'ref_id' );
165 }
166
167 /**
168 * Get result
169 *
170 * @param string $prop
171 *
172 * @return array|bool|mixed
173 */
174 public function get_result( $prop = '' ) {
175 $result = $this->calculate_quiz_result();
176
177 // Fix temporary for case call 'grade' - addons called
178 if ( 'grade' === $prop ) {
179 if ( $result['pass'] ) {
180 $result['grade'] = 'passed';
181 } else {
182 $result['grade'] = 'failed';
183 }
184 }
185
186 return $prop && $result && array_key_exists( $prop, $result ) ? $result[ $prop ] : $result;
187 }
188
189 /**
190 * Calculate result of quiz.
191 *
192 * @param string $prop
193 * @param bool $force - Optional. Force to refresh cache.
194 *
195 * Clear cache on
196 * @see LP_REST_Users_Controller::start_quiz() | retake quiz
197 *
198 * @return LP_Quiz_Results|bool|mixed
199 * @throws Exception
200 * @editor tungnx
201 * @modify 4.1.3
202 * @version 4.0.1
203 */
204 public function get_results( string $prop = 'result', bool $force = false ) {
205 if ( ! $this->get_status() ) {
206 return false;
207 }
208
209 $lp_quiz_cache = LP_Quiz_Cache::instance();
210
211 $key_cache = sprintf( '%d/user/%d/course/%d', $this->get_item_id(), $this->get_user_id(), $this->get_course_id() );
212 $result = $lp_quiz_cache->get_cache( $key_cache );
213
214 if ( false === $result || $force ) {
215 // $result = $this->_get_results();
216
217 // if ( false === $result ) {
218 $result = $this->calculate_results();
219 // }
220
221 $lp_quiz_cache->set_cache( $key_cache, $result );
222 }
223
224 $result['user_item_id'] = $this->get_user_item_id();
225 $result['interval'] = array( $this->get_start_time(), $this->get_end_time() );
226 $result['graduation'] = $this->get_graduation();
227 $result['graduationText'] = $this->get_graduation_text();
228
229 return $prop ? $result[ $prop ] : new LP_Quiz_Results( $result );
230 }
231
232 /**
233 * Get user quiz graduation text for displaying purpose. [Passed, Failed, null]
234 *
235 * @since 4.0.0
236 *
237 * @return mixed
238 */
239 public function get_graduation_text() {
240 $graduation = $this->get_graduation();
241
242 return apply_filters( 'learn-press/user-quiz-graduation-text', learn_press_get_graduation_text( $graduation ) );
243 }
244
245 /**
246 * Get Timestamp remaining when user doing quiz
247 *
248 * @author tungnx
249 * @version 1.0.1
250 * @sicne 4.1.4.1
251 * @return int
252 */
253 public function get_timestamp_remaining(): int {
254 $timestamp_remaining = - 1;
255 $quiz = false;
256 $user_quiz = false;
257
258 try {
259 $quiz = learn_press_get_quiz( $this->get_item_id() );
260 if ( ! $quiz || LP_ITEM_STARTED != $this->get_status() ) {
261 return $timestamp_remaining;
262 }
263
264 $parent_id = $this->get_parent_id();
265 $duration = $quiz->get_duration()->get() . ' second';
266
267 $filter = new LP_User_Items_Filter();
268 $filter->parent_id = $parent_id;
269 $filter->item_id = $this->get_item_id();
270 $filter->user_id = get_current_user_id();
271 $user_quiz = LP_User_Items_DB::getInstance()->get_user_course_item( $filter, true );
272 $course_start_time = $user_quiz->start_time;
273 $timestamp_expire = strtotime( $course_start_time . ' +' . $duration );
274 $timestamp_current = time();
275 $timestamp_remaining = $timestamp_expire - $timestamp_current;
276
277 if ( $timestamp_remaining < 0 ) {
278 $timestamp_remaining = 0;
279 }
280 } catch ( Throwable $e ) {
281
282 }
283
284 return apply_filters( 'learn-press/user-course-quiz/timestamp_remaining', $timestamp_remaining, $user_quiz, $quiz );
285 }
286
287 /**
288 * Get all attempts of a quiz.
289 *
290 * @param string $args
291 *
292 * @return array
293 */
294 public function get_attempts( $limit = 3 ) {
295 $limit = $limit ?? 3;
296
297 $limit = absint( apply_filters( 'lp/quiz/get-attempts/limit', $limit ) );
298
299 $results = LP_User_Items_Result_DB::instance()->get_results( $this->get_user_item_id(), $limit, true );
300 $output = array();
301
302 if ( ! empty( $results ) ) {
303 foreach ( $results as $result ) {
304 if ( $result && is_string( $result ) ) {
305 $result = json_decode( $result );
306
307 unset( $result->questions );
308
309 $output[] = $result;
310 }
311 }
312 }
313
314 return $output;
315 }
316
317 /**
318 * Get question ids user has started inside quiz.
319 *
320 * @since 4.0.0
321 *
322 * @return bool|array
323 */
324 public function get_questions() {
325 $quiz = learn_press_get_quiz( $this->get_item_id() );
326 $ids = $quiz->get_question_ids();
327
328 return apply_filters( 'learn-press/user-item-quiz-questions', $ids, $this->get_user_id(), $this );
329 }
330
331 /**
332 * Calculate results of quiz.
333 *
334 * @return array
335 * @throws Exception
336 * @version 4.0.0
337 */
338 public function calculate_results(): array {
339 $quiz = learn_press_get_quiz( $this->get_item_id() );
340 $last_results = LP_User_Items_Result_DB::instance()->get_result( $this->get_user_item_id() );
341
342 if ( ! $last_results ) {
343 $last_results = array();
344 }
345
346 $questions = $last_results['questions'] ?? array_fill_keys( $quiz->get_question_ids(), array() );
347
348 $result = array(
349 'questions' => array(),
350 'mark' => $quiz->get_mark(),
351 'user_mark' => 0,
352 'question_count' => 0,
353 'question_empty' => 0,
354 'question_answered' => 0,
355 'question_wrong' => 0,
356 'question_correct' => 0,
357 'status' => $this->get_status(),
358 'result' => 0,
359 'time_spend' => $this->get_time_interval( 'display' ),
360 'passing_grade' => $quiz->get_passing_grade(),
361 );
362
363 if ( $questions ) {
364 foreach ( $questions as $question_id => $last_checked ) {
365 $question = LP_Question::get_question( $question_id );
366 if ( ! $question ) {
367 continue;
368 }
369
370 $answered = array_key_exists( 'answered', $last_checked ) ? $last_checked['answered'] : '';
371 $check = apply_filters( 'learn-press/quiz/check-question-result', $question->check( $answered ), $question_id, $this );
372 $check['answered'] = $answered;
373
374 if ( $check['answered'] && $check['correct'] ) {
375 $result['question_correct'] ++;
376 $result['user_mark'] += array_key_exists( 'mark', $check ) ? floatval( $check['mark'] ) : $question->get_mark();
377 } else {
378 $negative_marking = apply_filters( 'learn-press/get-negative-marking-value', floatval( $question->get_mark() ), $question_id, $quiz->get_id() );
379
380 // If answered is empty consider user has skipped question
381 if ( ! $check['answered'] ) {
382 if ( $quiz->get_negative_marking() && $quiz->get_minus_skip_questions() ) {
383 $result['user_mark'] -= $negative_marking;
384 }
385 $result['question_empty'] ++;
386 } else {
387 if ( $quiz->get_negative_marking() ) {
388 $result['user_mark'] -= $negative_marking;
389 }
390 $result['question_wrong'] ++;
391 }
392 }
393
394 $result['questions'][ $question_id ] = apply_filters( 'learn-press/question-results-data', $last_checked ? array_merge( $last_checked, $check ) : $check, $question_id, $quiz->get_id() );
395
396 if ( $check['answered'] ) {
397 $result['question_answered'] ++;
398 }
399 }
400
401 $result['user_mark'] = ( $result['user_mark'] >= 0 ) ? $result['user_mark'] : 0;
402
403 $percent = $result['mark'] ? ( $result['user_mark'] / $result['mark'] ) * 100 : 0;
404 $result['result'] = $percent;
405 $grade = '';
406
407 if ( $this->get_status() === 'completed' ) {
408 $grade = $percent >= $this->get_quiz()->get_data( 'passing_grade' ) ? 'passed' : 'failed';
409 $this->_set_data( 'graduation', $grade );
410 }
411
412 $result['question_count'] = count( $questions );
413
414 if ( $grade ) {
415 learn_press_update_user_item_field(
416 array(
417 'graduation' => $grade,
418 ),
419 array(
420 'user_item_id' => $this->get_user_item_id(),
421 )
422 );
423 }
424 }
425
426 return $result;
427 }
428
429 /**
430 * Calculate result of quiz.
431 *
432 * @param array $answered [question_id => answered, 'instant_check' => 0]
433 *
434 * @return array
435 * @version 1.0.1
436 * @author tungnx
437 * @since 4.1.4.1
438 */
439 public function calculate_quiz_result( array $answered = array() ): array {
440 $result = array(
441 'questions' => array(),
442 'mark' => 0,
443 'user_mark' => 0,
444 'minus_point' => 0,
445 'question_count' => 0,
446 'question_empty' => 0,
447 'question_answered' => 0,
448 'question_wrong' => 0,
449 'question_correct' => 0,
450 'status' => '',
451 'result' => 0,
452 'time_spend' => '',
453 'passing_grade' => '',
454 'pass' => 0,
455 );
456
457 try {
458 if ( LP_ITEM_COMPLETED === $this->get_status() ) {
459 $result_tmp = LP_User_Items_Result_DB::instance()->get_result( $this->get_user_item_id() );
460
461 if ( $result_tmp ) {
462 if ( isset( $result_tmp['user_mark'] ) && $result_tmp['user_mark'] < 0 ) {
463 $result_tmp['user_mark'] = 0;
464 }
465
466 $result = $result_tmp;
467 }
468
469 return $result;
470 }
471
472 $quiz = learn_press_get_quiz( $this->get_item_id() );
473
474 if ( ! $quiz ) {
475 throw new Exception();
476 }
477
478 $question_ids = $quiz->get_question_ids();
479 $result['mark'] = $quiz->get_mark();
480 $result['question_count'] = $quiz->count_questions();
481 $result['time_spend'] = $this->get_time_interval( 'display' );
482 $result['passing_grade'] = $quiz->get_passing_grade();
483 $checked_questions = $this->get_checked_questions();
484
485 foreach ( $question_ids as $question_id ) {
486 $question = LP_Question::get_question( $question_id );
487 $point = floatval( $question->get_mark() );
488
489 $result['questions'][ $question_id ] = array();
490 $result['questions'][ $question_id ]['answered'] = $answered[ $question_id ] ?? '';
491
492 if ( isset( $answered[ $question_id ] ) ) { // User's answer
493 $result['question_answered']++;
494
495 $check = $question->check( $answered[ $question_id ] );
496 $point = apply_filters( 'learn-press/user/calculate-quiz-result/point', $point, $question, $check );
497 if ( $check['correct'] ) {
498 $result['question_correct']++;
499 $result['user_mark'] += $point;
500
501 $result['questions'][ $question_id ]['correct'] = true;
502 $result['questions'][ $question_id ]['mark'] = $point;
503 } else {
504 if ( $quiz->get_negative_marking() ) {
505 $result['user_mark'] -= $point;
506 $result['minus_point'] += $point;
507 }
508 $result['question_wrong']++;
509
510 $result['questions'][ $question_id ]['correct'] = false;
511 $result['questions'][ $question_id ]['mark'] = 0;
512 }
513 } elseif ( ! array_key_exists( 'instant_check', $answered ) ) { // User skip question
514 if ( $quiz->get_minus_skip_questions() ) {
515 $result['user_mark'] -= $point;
516 $result['minus_point'] += $point;
517 }
518 $result['question_empty']++;
519
520 $result['questions'][ $question_id ]['correct'] = false;
521 $result['questions'][ $question_id ]['mark'] = 0;
522 }
523
524 $can_review_quiz = get_post_meta( $quiz->get_id(), '_lp_review', true ) === 'yes';
525 if ( $can_review_quiz && ! array_key_exists( 'instant_check', $answered ) ) {
526
527 $result['questions'][ $question_id ]['explanation'] = $question->get_explanation();
528 $result['questions'][ $question_id ]['options'] = learn_press_get_question_options_for_js(
529 $question,
530 array(
531 'include_is_true' => in_array( $question_id, $checked_questions ) || get_post_meta( $quiz->get_id(), '_lp_show_correct_review', true ) === 'yes',
532 'answer' => $answered[ $question_id ] ?? '',
533 )
534 );
535 }
536 }
537
538 if ( $result['user_mark'] < 0 ) {
539 $result['user_mark'] = 0;
540 }
541
542 if ( $result['user_mark'] > 0 && $result['mark'] > 0 ) {
543 $result['result'] = round( $result['user_mark'] * 100 / $result['mark'], 2, PHP_ROUND_HALF_DOWN );
544 }
545
546 $passing_grade = $quiz->get_data( 'passing_grade', 0 );
547 if ( $result['result'] >= $passing_grade ) {
548 $result['pass'] = 1;
549 } else {
550 $result['pass'] = 0;
551 }
552 } catch ( Throwable $e ) {
553
554 }
555
556 return $result;
557 }
558
559 public function get_option_answer() {
560
561 }
562
563 protected function _get_results() {
564 return LP_User_Items_Result_DB::instance()->get_result( $this->get_user_item_id() );
565 }
566
567 public function get_percent_result( $decimal = 2 ) {
568 return apply_filters( 'learn-press/user/quiz-percent-result', sprintf( '%s%%', round( $this->get_result( 'result' ), $decimal ) ), $this->get_user_id(), $this->get_item_id() );
569 }
570
571 public function get_time_interval( $context = '' ) {
572 $interval = parent::get_time_interval();
573
574 if ( $context == 'display' ) {
575 $quiz = $this->get_quiz();
576
577 if ( $quiz && $interval && $quiz->get_duration() ) {
578 $interval = new LP_Duration( $interval );
579 $interval = $interval->to_timer();
580 } else {
581 $interval = '--:--';
582 }
583 }
584
585 return $interval;
586 }
587
588 /**
589 * Return TRUE if user has pressed SKIP on this question
590 *
591 * @param int $question_id
592 *
593 * @return bool
594 */
595 public function is_skipped( $question_id ) {
596 return $this->get_question_answer( $question_id ) === '__SKIPPED__';
597 }
598
599 public function is_answered( $question_id ) {
600 $result = $this->get_results();
601
602 if ( ! empty( $result['questions'][ $question_id ] ) ) {
603 return $result['questions'][ $question_id ]['answered'];
604 }
605
606 return false;
607 }
608
609 public function is_answered_true( $question_id ) {
610 $result = $this->get_results( false );
611
612 if ( ! empty( $result['questions'][ $question_id ] ) ) {
613 return $result['questions'][ $question_id ]['correct'];
614 }
615
616 return false;
617 }
618
619 /**
620 * Get questions user has answered.
621 *
622 * @param bool $percent - Optional. TRUE will return by percentage with total questions.
623 *
624 * @return float|int|mixed
625 */
626 public function get_questions_answered( $percent = false ) {
627 $result = $this->get_results( '' );
628
629 if ( $percent ) {
630 if ( $result['question_count'] ) {
631 $return = 0;
632 } else {
633 $return = $result['question_answered'] ? ( $result['question_answered'] / $result['question_count'] ) * 100 : 0;
634 }
635 } else {
636 $return = $result['question_answered'];
637 }
638
639 return $return;
640 }
641
642 /**
643 * Get total mark user achieved.
644 *
645 * @param bool $percent - Optional. TRUE will return by percentage with total mark.
646 *
647 * @return float|int|mixed
648 */
649 public function get_mark( $percent = false ) {
650 $result = $this->get_results();
651
652 if ( $percent ) {
653 $return = $result['mark'] ? ( $result['user_mark'] / $result['mark'] ) * 100 : 0;
654 } else {
655 $return = $result['user_mark'];
656 }
657
658 return $return;
659 }
660
661 /**
662 * @deprecated 4.2.0
663 */
664 public function get_total_questions() {
665 _deprecated_function( __METHOD__, '4.2.0' );
666 $quiz = learn_press_get_quiz( $this->get_item_id() );
667 $questions = $quiz->get_question_ids();
668
669 return sizeof( $questions );
670 }
671
672 public function get_quiz_mark() {
673 $result = $this->get_results();
674
675 return $result['mark'];
676 }
677
678 /**
679 * Return time remaining.
680 *
681 * @param string $return - Optional.
682 *
683 * @return LP_Duration
684 * @deprecated 4.1.7.3
685 */
686 public function get_time_remaining( $return = 'object' ) {
687 _deprecated_function( __METHOD__, '4.1.7.3' );
688 /*$time = parent::get_time_remaining( $return );
689
690 return apply_filters( 'learn-press/quiz/time-remaining', $time, $this->get_item_id(), $this->get_course_id(), $this->get_user_id() );*/
691 }
692
693 /**
694 * Get all questions user has already used "Check"
695 *
696 * @return array
697 */
698 public function get_checked_questions(): array {
699 $value = $this->get_meta( '_lp_question_checked', true );
700
701 if ( $value ) {
702 $value = (array) $value;
703 } else {
704 $value = array();
705 }
706
707 return $value;
708 }
709
710 public function add_checked_question( $id ) {
711 settype( $id, 'array' );
712 $checked = $this->get_checked_questions();
713 $checked = array_merge( $checked, $id );
714
715 $this->update_meta( '_lp_question_checked', $checked );
716
717 return $checked;
718 }
719
720 /**
721 * Return true if user has already checked a question.
722 *
723 * @param int $question_id
724 *
725 * @return bool
726 */
727 public function has_checked_question( $question_id ) {
728 return in_array( $question_id, $this->get_checked_questions() );
729 }
730
731 /**
732 * Instant check question
733 *
734 * @param int $question_id
735 * @param mixed $answered
736 *
737 * @return array
738 * @throws Exception
739 */
740 public function instant_check_question( int $question_id, $answered = null ): array {
741 $question = learn_press_get_question( $question_id );
742 if ( ! $question ) {
743 throw new Exception( __( 'The question is invalid!', 'learnpress' ) );
744 }
745
746 $can_check = $this->can_check_answer( $question_id );
747 if ( ! $can_check ) {
748 throw new Exception( __( 'Cannot check the answer to the question.', 'learnpress' ) );
749 }
750
751 $answered_check = array(
752 'instant_check' => 1,
753 $question_id => $answered,
754 );
755
756 // For case save result when check instant answer
757 $result_instant_check = LP_User_Items_Result_DB::instance()->get_result( $this->get_user_item_id() );
758 if ( $result_instant_check ) {
759 foreach ( $result_instant_check['questions'] as $question_answer_id => $question_answer ) {
760 if ( ! empty( $question_answer['answered'] ) ) {
761 $answered_check[ $question_answer_id ] = $question_answer['answered'];
762 }
763 }
764 }
765
766 $result_answer = $this->calculate_quiz_result( $answered_check );
767
768 LP_User_Items_Result_DB::instance()->update( $this->get_user_item_id(), json_encode( $result_answer ) );
769 $this->add_checked_question( $question_id );
770
771 $checked['answered'] = $answered;
772 $checked['mark'] = $result_answer['questions'][ $question_id ]['mark'];
773 $checked['correct'] = $result_answer['questions'][ $question_id ]['correct'];
774
775 return $checked;
776 }
777
778 /**
779 * @param int $question_id
780 *
781 * @return int
782 * @deprecated 4.2.5
783 */
784 public function hint( $question_id ) {
785 _deprecated_function( __METHOD__, '4.2.5' );
786 return false;
787 $remain = $this->can_hint_answer();
788
789 if ( $remain ) {
790 if ( ! $this->has_hinted_question( $question_id ) ) {
791 $checked = $this->get_hint_questions();
792 $checked[] = $question_id;
793 $this->set_meta( '_lp_question_hint', $checked );
794 }
795
796 $count = $this->get_count_hint();
797 $this->update_meta();
798 $remain --;
799 } else {
800 return false;
801 }
802
803 return $remain;
804 }
805
806 /**
807 * Return true if user has already checked a question.
808 *
809 * @param int $question_id
810 *
811 * @return bool
812 */
813 public function has_hinted_question( $question_id ) {
814 return in_array( $question_id, $this->get_hint_questions() );
815 }
816
817 public function get_check_answer_count() {
818 return count( $this->get_checked_questions() );
819 }
820
821 /**
822 * @param int $question_id - Added since 3.3.0
823 *
824 * @return bool
825 */
826 public function can_check_answer( int $question_id = 0 ) : bool {
827 $can = false;
828 $quiz = learn_press_get_quiz( $this->get_item_id() );
829
830 if ( ! $quiz ) {
831 return $can;
832 }
833
834 if ( $quiz->get_instant_check() && $this->get_status() === 'started' ) {
835 $can = ! $this->has_checked_question( $question_id );
836 }
837
838 return apply_filters( 'learn-press/can-instant-check-question', $can, $question_id, $this->get_item_id(), $this->get_course_id() );
839 }
840
841 /**
842 * Get number retaken count.
843 *
844 * @return integer
845 */
846 public function get_retaken_count(): int {
847 return absint( learn_press_get_user_item_meta( $this->get_user_item_id(), '_lp_retaken_count' ) );
848 }
849
850 /**
851 * Update learnpress_user_itemmeta retaken
852 *
853 * @return void
854 */
855 public function update_retake_count() {
856 $count = $this->get_retaken_count();
857 $count ++;
858
859 return $this->update_meta( '_lp_retaken_count', $count );
860 }
861
862 /**
863 * Get all questions user has already used "Check"
864 *
865 * @return array
866 * @deprecated 4.2.5
867 */
868 public function get_hint_questions() {
869 return [];
870 _deprecated_function( __METHOD__, '4.2.5' );
871 $value = $this->get_meta( '_lp_question_hint', true );
872
873 if ( $value ) {
874 $value = (array) $value;
875 } else {
876 $value = array();
877 }
878
879 return $value;
880 }
881
882 /**
883 * @deprecated 4.2.5
884 */
885 public function get_count_hint() {
886 _deprecated_function( __METHOD__, '4.2.5' );
887 return 0;
888 return count( $this->get_hint_questions() );
889 }
890
891 /**
892 * Return true if check answer is enabled.
893 *
894 * @return bool
895 */
896 public function can_hint_answer() {
897 return apply_filters( 'learn-press/user-quiz/can-hint-answer', true, $this->get_id(), $this->get_course_id() );
898 }
899
900 /**
901 * @return bool
902 */
903 public function is_review_questions(): bool {
904 return LP_Global::quiz_question() && ( $this->get_status() === 'completed' );
905 }
906 }
907