PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.9
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.9
4.4.9 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 All 140 releases
← All changes | inc/quiz/class-lp-quiz.php +1090 -1090 4.3.9.1 → 4.4.9 View file →
@@ -1,1090 +1,1090 @@
1 -<?php
2 -/**
3 - * Class LP_Quiz.
4 - *
5 - * @author ThimPress
6 - * @package LearnPress/Classes
7 - * @version 3.0.0
8 - */
9 -
10 -defined( 'ABSPATH' ) || exit();
11 -
12 -if ( ! class_exists( 'LP_Quiz' ) ) {
13 -
14 - /**
15 - * Class LP_Quiz
16 - */
17 - class LP_Quiz extends LP_Course_Item {
18 -
19 -
20 - /**
21 - * @var array
22 - *
23 - * @deprecated
24 - */
25 - protected static $_meta = array();
26 -
27 - /**
28 - * @var string
29 - */
30 - protected $_item_type = LP_QUIZ_CPT;
31 -
32 - /**
33 - * @var array
34 - */
35 - protected $_questions = array();
36 -
37 - /**
38 - * @var array
39 - */
40 - protected $_data = array(
41 - // 'show_result' => 'no',
42 - 'passing_grade_type' => '',
43 - 'passing_grade' => 0,
44 - // 'show_check_answer' => 'no',
45 - // 'count_check_answer' => 0,
46 - // 'show_hint' => 'no',
47 - // 'count_hint' => 0,
48 - // 'archive_history' => 'no',
49 - // 'show_hide_question' => 'yes',
50 - // 'preview' => 'no',
51 - // 'minus_points' => 0,
52 - 'minus_skip_questions' => 'no',
53 -
54 - 'negative_marking' => 'no',
55 - 'instant_check' => 'no',
56 - 'retake_count' => 0,
57 - 'show_correct_review' => 'yes',
58 - );
59 -
60 - /**
61 - * @var int
62 - */
63 - protected static $_loaded = 0;
64 -
65 - /**
66 - * Constructor gets the post object and sets the ID for the loaded course.
67 - *
68 - * @param mixed $the_quiz
69 - * @param mixed $args
70 - */
71 - public function __construct( $the_quiz, $args = array() ) {
72 - $this->_curd = new LP_Quiz_CURD();
73 -
74 - if ( is_numeric( $the_quiz ) && $the_quiz > 0 ) {
75 - $this->set_id( $the_quiz );
76 - } elseif ( $the_quiz instanceof self ) {
77 - $this->set_id( absint( $the_quiz->get_id() ) );
78 - } elseif ( ! empty( $the_quiz->ID ) ) {
79 - $this->set_id( absint( $the_quiz->ID ) );
80 - }
81 - if ( $this->get_id() > 0 ) {
82 - $this->load();
83 - }
84 -
85 - self::$_loaded ++;
86 - if ( self::$_loaded == 1 ) {
87 - add_filter( 'debug_data', array( __CLASS__, 'log' ) );
88 - }
89 - }
90 -
91 - /**
92 - * Log debug data.
93 - *
94 - * @since 3.0.0
95 - *
96 - * @param $data
97 - *
98 - * @return array
99 - */
100 - public static function log( $data ) {
101 - $data[] = __CLASS__ . '( ' . self::$_loaded . ' )';
102 -
103 - return $data;
104 - }
105 -
106 - /**
107 - * @param string $context
108 - *
109 - * @return string
110 - */
111 - public function get_heading_title( $context = '' ) {
112 - return $this->get_title( $context );
113 - }
114 -
115 - /**
116 - * Load quiz data
117 - */
118 - public function load() {
119 - $this->_curd->load( $this );
120 - }
121 -
122 - /**
123 - * Get default quiz meta.
124 - *
125 - * @since 3.0.0
126 - *
127 - * @return mixed
128 - */
129 - public static function get_default_meta() {
130 - $meta = array(
131 - 'review' => 'no',
132 - 'duration' => '10 minute',
133 - 'passing_grade' => 80,
134 - 'negative_marking' => 'no',
135 - 'instant_check' => 'no',
136 - 'retake_count' => '0',
137 - 'pagination' => 1,
138 - 'show_correct_review' => 'yes',
139 - );
140 -
141 - return apply_filters( 'learn-press/quiz/default-meta', $meta );
142 - }
143 -
144 - /**
145 - * Save quiz data.
146 - *
147 - * @return mixed
148 - *
149 - * @throws Exception
150 - */
151 - public function save() {
152 - if ( $this->get_id() ) {
153 - $return = $this->_curd->update( $this );
154 - } else {
155 - $return = $this->_curd->create( $this );
156 - }
157 -
158 - return $return;
159 - }
160 -
161 - public function get_negative_marking() {
162 - return $this->get_data( 'negative_marking' ) === 'yes';
163 - }
164 -
165 - public function set_negative_marking( $set ) {
166 - $this->_set_data( 'negative_marking', ! learn_press_is_negative_value( $set ) ? 'yes' : 'no' );
167 - }
168 -
169 - public function get_show_correct_review() {
170 - return $this->get_data( 'show_correct_review' ) === 'yes';
171 - }
172 -
173 - public function set_show_correct_review( $set ) {
174 - $this->_set_data( 'show_correct_review', $set );
175 - }
176 -
177 - public function get_instant_check() {
178 - return $this->get_data( 'instant_check' ) === 'yes';
179 - }
180 -
181 - public function set_instant_check( $set ) {
182 - $this->_set_data( 'instant_check', ! learn_press_is_negative_value( $set ) ? 'yes' : 'no' );
183 - }
184 -
185 - public function set_retake_count( $count ) {
186 - $this->_set_data( 'retake_count', $count );
187 - }
188 -
189 - public function get_retake_count() {
190 - return $this->get_data( 'retake_count' );
191 - }
192 -
193 - public function get_pagination() {
194 - return ( $n = $this->get_data( 'pagination' ) ) > 1 ? $n : 0;
195 - }
196 -
197 - public function set_pagination( $set ) {
198 - $this->_set_data( 'pagination', absint( $set ) );
199 - }
200 -
201 - /**
202 - * @deprecated
203 - *
204 - * @param $show_result
205 - */
206 - public function set_show_result( $show_result ) {
207 - _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.0.0' );
208 -
209 - $this->_set_data( 'show_result', $show_result );
210 - }
211 -
212 - /**
213 - * @deprecated
214 - *
215 - * @return array|mixed
216 - */
217 - public function get_show_result() {
218 -
219 - _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.0.0' );
220 -
221 - return $this->get_data( 'show_result' ) === 'yes';
222 - }
223 -
224 - /**
225 - *
226 - * @param $review_questions
227 - */
228 - public function set_review_questions( $review_questions ) {
229 -
230 - $this->_set_data( 'review_questions', $review_questions );
231 - }
232 -
233 - /**
234 - * Enable review quiz
235 - *
236 - * @return bool
237 - */
238 - public function get_review_questions(): bool {
239 - return 'yes' === $this->get_data( 'review_questions', 'yes' );
240 - }
241 -
242 - /**
243 - * @param $type
244 - */
245 - public function set_passing_grade_type( $type ) {
246 - $this->_set_data( 'passing_grade_type', $type );
247 - }
248 -
249 - /**
250 - * @return array|mixed
251 - */
252 - public function get_passing_grade_type() {
253 - return $this->get_data( 'passing_grade_type', 'percentage' );
254 - }
255 -
256 - /**
257 - * @param $value
258 - */
259 - public function set_passing_grade( $value ) {
260 - $this->_set_data( 'passing_grade', $value );
261 - }
262 -
263 - /**
264 - * @return array|mixed
265 - */
266 - public function get_passing_grade() {
267 - $type = $this->get_passing_grade_type();
268 - $value = get_post_meta( $this->get_id(), '_lp_passing_grade', true );
269 - if ( empty( $value ) ) {
270 - $value = 80;
271 - }
272 -
273 - switch ( $type ) {
274 - case 'point':
275 - break;
276 - case 'percentage':
277 - default:
278 - $value = "{$value}%";
279 - break;
280 - }
281 -
282 - return $value;
283 - }
284 -
285 - /**
286 - * @deprecated
287 - *
288 - * @param $value
289 - */
290 - public function set_show_check_answer( $value ) {
291 - _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.0.0' );
292 -
293 - $this->_set_data( 'show_check_answer', $value );
294 - }
295 -
296 - /**
297 - * @deprecated
298 - *
299 - * @return int|bool
300 - */
301 - public function get_show_check_answer() {
302 - _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.0.0' );
303 -
304 - return intval( $this->get_data( 'show_check_answer' ) );
305 - }
306 -
307 - /**
308 - * @deprecated
309 - *
310 - * @param $count
311 - */
312 - public function set_count_check_answer( $count ) {
313 - _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.0.0' );
314 -
315 - $this->_set_data( 'count_check_answer', $count );
316 - }
317 -
318 - /**
319 - * @deprecated
320 - *
321 - * @return int
322 - */
323 - public function get_check_answer_count() {
324 - _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.0.0' );
325 -
326 - return intval( $this->get_data( 'check_answer_count' ) );
327 - }
328 -
329 - /**
330 - * @deprecated
331 - *
332 - * @param $value
333 - */
334 - public function set_show_hint( $value ) {
335 - _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.0.0' );
336 -
337 - $this->_set_data( 'show_hint', $value );
338 - }
339 -
340 - /**
341 - * @deprecated
342 - *
343 - * @return int
344 - */
345 - public function get_show_hint() {
346 - _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.0.0' );
347 -
348 - return intval( $this->get_data( 'show_hint' ) );
349 - }
350 -
351 - /**
352 - * @deprecated
353 - *
354 - * @param $count
355 - */
356 - public function set_count_hint( $count ) {
357 - _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.0.0' );
358 -
359 - $this->_set_data( 'count_hint', $count );
360 - }
361 -
362 - /**
363 - * Return true if hint answer is enabled.
364 - *
365 - * @deprecated
366 - *
367 - * @return bool
368 - */
369 - public function enable_show_hint() {
370 - _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.0.0' );
371 -
372 - return apply_filters( 'learn-press/quiz/enable-show-hint', $this->get_data( 'show_hint' ) == 'yes', $this->get_id() );
373 - }
374 -
375 - /**
376 - * @deprecated
377 - *
378 - * @param $value
379 - */
380 - public function set_archive_history( $value ) {
381 - _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.0.0' );
382 -
383 - $this->_set_data( 'archive_history', $value );
384 - }
385 -
386 - /**
387 - * Return true if archive history is enabled.
388 - *
389 - * @deprecated
390 - *
391 - * @return bool
392 - */
393 - public function enable_archive_history() {
394 - _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.0.0' );
395 -
396 - return apply_filters( 'learn-press/quiz/enable-archive-history', $this->get_data( 'archive_history' ) == 'yes', $this->get_id() );
397 - }
398 -
399 - /**
400 - * Return total mark of quiz by calculating total mark of all questions.
401 - *
402 - * @return int
403 - */
404 - public function get_mark() {
405 - $mark = $this->get_data( 'mark', false );
406 - if ( false === $mark || '' === $mark ) {
407 - $questions = $this->get_question_ids();
408 - $mark = 0;
409 -
410 - foreach ( $questions as $question_id ) {
411 - $question = LP_Question::get_question( $question_id );
412 - if ( $question ) {
413 - $mark += $question->get_mark();
414 - }
415 - }
416 -
417 - $this->_set_data( 'mark', $mark );
418 - }
419 -
420 - return apply_filters( 'learn-press/quiz-mark', $mark, $this->get_id() );
421 - }
422 -
423 - /**
424 - * Get duration of quiz
425 - *
426 - * @return LP_Duration
427 - */
428 - public function get_duration() {
429 - $duration = parent::get_duration();
430 -
431 - return apply_filters( 'learn-press/quiz-duration', $duration, $this->get_id() );
432 - }
433 -
434 - /**
435 - * Get quiz questions.
436 - *
437 - * @param string $context
438 - *
439 - * @return mixed
440 - * @editor tungnx
441 - * @since 3.x.x
442 - * @version 1.0.1
443 - * @deprecated 4.2.0
444 - */
445 - public function get_questions( $context = 'display' ) {
446 - _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.2.0' );
447 - $questions = array();
448 - $ids = $this->_curd->read_question_ids( $this->get_id() );
449 -
450 - if ( $ids ) {
451 - foreach ( $ids as $id ) {
452 - $questions[ $id ] = $id;
453 - }
454 - }
455 -
456 - return apply_filters( 'learn-press/quiz/questions', $questions, $this->get_id(), $this->get_course_id(), $context );
457 - }
458 -
459 - /**
460 - * Quiz editor get questions.
461 - *
462 - * @return mixed
463 - */
464 - public function quiz_editor_get_questions() {
465 - // list questions
466 - $questions = $this->get_question_ids( 'edit' );
467 - // order questions in quiz
468 - $question_order = learn_press_quiz_get_questions_order( $questions );
469 -
470 - $result = array();
471 -
472 - foreach ( $questions as $id ) {
473 - $question = LP_Question::get_question( $id );
474 -
475 - $answers = array();
476 - // handle question answer
477 - if ( is_array( $question->get_data( 'answer_options' ) ) ) {
478 - foreach ( $question->get_data( 'answer_options' ) as $answer ) {
479 - $answers[] = $answer;
480 - }
481 - }
482 -
483 - $post = get_post( $id );
484 - $result[] = apply_filters(
485 - 'learn-press/quiz-editor/question-data',
486 - array(
487 - 'id' => $id,
488 - 'open' => false,
489 - 'title' => $post->post_title,
490 - 'type' => array(
491 - 'key' => $question->get_type(),
492 - 'label' => $question->get_type_label(),
493 - ),
494 - 'answers' => apply_filters( 'learn-press/quiz-editor/question-answers-data', $answers, $id, $this->get_id() ),
495 - 'settings' => array(
496 - 'content' => $post->post_content,
497 - 'mark' => get_post_meta( $id, '_lp_mark', true ),
498 - 'explanation' => get_post_meta( $id, '_lp_explanation', true ),
499 - 'hint' => get_post_meta( $id, '_lp_hint', true ),
500 - ),
501 - 'order' => $question_order[ $id ],
502 - ),
503 - $id,
504 - $this->get_id()
505 - );
506 - }
507 -
508 - return apply_filters( 'learn-press/quiz/quiz_editor_questions', $result, $this->get_id() );
509 - }
510 -
511 - /**
512 - * Get quiz duration html.
513 - *
514 - * @return mixed
515 - */
516 - public function get_duration_html() {
517 - $duration = $this->get_duration();
518 - if ( $duration ) {
519 - $duration = learn_press_seconds_to_time( $duration->get_seconds() );
520 - } else {
521 - $duration = __( 'Unlimited', 'learnpress' );
522 - }
523 -
524 - return apply_filters( 'learn_press_quiz_duration_html', $duration, $this );
525 - }
526 -
527 - /**
528 - * Get number questions in quiz.
529 - *
530 - * @return int
531 - */
532 - public function count_questions(): int {
533 - $size = 0;
534 - $questions = $this->get_question_ids();
535 -
536 - if ( $questions ) {
537 - $size = sizeof( $questions );
538 - }
539 -
540 - return (int) apply_filters( 'learn-press/quiz/count-questions', $size, $this->get_id() );
541 - }
542 -
543 - /**
544 - * Get all question's ids of the quiz.
545 - *
546 - * @param string $context
547 - *
548 - * @return int[]
549 - * @editor tungnx
550 - * @version 1.0.1
551 - * @since 3.2.0
552 - */
553 - public function get_question_ids( string $context = 'display' ): array {
554 - $question_ids = $this->_curd->read_question_ids( $this->get_id(), $context );
555 - $question_ids = apply_filters( 'learn-press/quiz/get-question-ids', $question_ids, $this->get_id(), $this->get_course_id(), $context );
556 - if ( ! is_array( $question_ids ) ) {
557 - $question_ids = array();
558 - }
559 -
560 - return $question_ids;
561 - }
562 -
563 - /**
564 - * Get number questions for user do it.
565 - *
566 - * @return mixed|null
567 - */
568 - public function get_number_questions_to_do() {
569 - return apply_filters( 'learn-press/quiz/number-questions-show', $this->count_questions(), $this );
570 - }
571 -
572 - /**
573 - * This quiz has any question?
574 - *
575 - * @return bool
576 - */
577 - public function has_questions() {
578 - return $this->count_questions() > 0;
579 - }
580 -
581 - /**
582 - * Get js localize script in frontend. [NOT USED]
583 - *
584 - * @return mixed
585 - */
586 - public function get_localize() {
587 - $localize = array(
588 - 'confirm_finish_quiz' => array(
589 - 'title' => __( 'Finish quiz', 'learnpress' ),
590 - 'message' => __( 'Are you sure you want to finish this quiz?', 'learnpress' ),
591 - ),
592 - 'confirm_retake_quiz' => array(
593 - 'title' => __( 'Retake quiz', 'learnpress' ),
594 - 'message' => __( 'Are you sure you want to retake this quiz?', 'learnpress' ),
595 - ),
596 - 'quiz_time_is_over' => array(
597 - 'title' => __( 'Time\'s up!', 'learnpress' ),
598 - 'message' => __( 'The time is up! Your quiz will automatically come to an end', 'learnpress' ),
599 - ),
600 - 'finished_quiz' => __( 'Congrats! You have finished this quiz', 'learnpress' ),
601 - 'retaken_quiz' => __( 'Congrats! You have re-taken this quiz. Please wait a moment and the page will reload', 'learnpress' ),
602 - );
603 -
604 - return apply_filters( 'learn_press_single_quiz_localize', $localize, $this );
605 - }
606 -
607 - /**
608 - * __isset function.
609 - *
610 - * @param mixed $key
611 - *
612 - * @return bool
613 - */
614 - public function __isset( $key ) {
615 - return metadata_exists( 'post', $this->get_id(), '_' . $key );
616 - }
617 -
618 - /**
619 - * __get function.
620 - *
621 - * @param string $key
622 - *
623 - * @return mixed
624 - * @deprecated 4.0.8
625 - */
626 - public function __get( $key ) {
627 - _deprecated_function( __METHOD__, '4.0.8' );
628 - /*echo '@deprecated[' . $key . ']';
629 - learn_press_debug( debug_backtrace() );
630 -
631 - return false;*/
632 - }
633 -
634 - /**
635 - * @param $feature
636 - *
637 - * @return mixed
638 - * @throws Exception
639 - * @deprecated 3.0.8
640 - */
641 - public function has( $feature ) {
642 - _deprecated_function( __FUNCTION__, '3.0.8' );
643 -
644 - $args = func_get_args();
645 - unset( $args[0] );
646 - $method = 'has_' . preg_replace( '!-!', '_', $feature );
647 - $callback = array( $this, $method );
648 - if ( is_callable( $callback ) ) {
649 - return call_user_func_array( $callback, $args );
650 - } else {
651 - throw new Exception( sprintf( __( 'The function %s doesn\'t exist', 'learnpress' ), $feature ) );
652 - }
653 - }
654 -
655 - /**
656 - * Return TRUE if quiz contain a question.
657 - *
658 - * @param int $question_id
659 - *
660 - * @return bool
661 - */
662 - public function has_question( $question_id ) {
663 - $questions = $this->get_question_ids();
664 -
665 - return apply_filters( 'learn-press/quiz/has-question', in_array( $question_id, $questions ), $question_id, $this->get_id() );
666 - }
667 -
668 - /**
669 - * Get question permalink from it's ID.
670 - * If permalink option is turn on, add name of question
671 - * into quiz permalink. Otherwise, add it's ID into
672 - * query var.
673 - *
674 - * @param int $question_id
675 - *
676 - * @return string
677 - * @deprecated 4.2.0
678 - */
679 - public function get_question_link( $question_id = null ) {
680 - _deprecated_function( __METHOD__, '4.2.0' );
681 - /*$course = learn_press_get_course();
682 - if ( ! $course ) {
683 - return '';
684 - }
685 -
686 - $permalink = $course->get_item_link( $this->get_id() );
687 - if ( '' != get_option( 'permalink_structure' ) && get_post_status( $this->get_id() ) != 'draft' ) {
688 - if ( get_post_type( $question_id ) === LP_QUESTION_CPT ) {
689 - $question_name = get_post_field( 'post_name', $question_id );
690 - preg_match( '/\?/i', $permalink, $result );
691 - if ( empty( $result ) ) {
692 - $permalink = $permalink . $question_name;
693 - } else {
694 - $permalink = preg_replace( '/\?/i', '/' . $question_name . '/?', $permalink );
695 - }
696 - }
697 - } else {
698 - $permalink = esc_url_raw( add_query_arg( array( 'question', $question_id ), $permalink ) );
699 - }
700 -
701 - // @deprecated
702 - $permalink = apply_filters( 'learn_press_quiz_question_permalink', $permalink, $question_id, $this );
703 -
704 - return apply_filters( 'learn-press/quiz/question-permalink', $permalink, $question_id, $this->get_id() );*/
705 - }
706 -
707 - /**
708 - * @param int $at
709 - *
710 - * @return bool
711 - * @deprecated 4.1.6.9
712 - */
713 - /*public function get_question_at( $at = 0 ) {
714 - $questions = $this->get_questions();
715 -
716 - if ( $questions ) {
717 - $questions = array_values( $questions );
718 -
719 - return @$questions[ $at ];
720 - }
721 -
722 - return false;
723 - }*/
724 -
725 - /**
726 - * Get prev question from a question.
727 - *
728 - * @param int $id
729 - *
730 - * @return bool
731 - * @deprecated 4.1.6.9
732 - */
733 - /*public function get_prev_question( $id ) {
734 - $prev = false;
735 - $questions = $this->get_questions();
736 -
737 - if ( $questions ) {
738 - $questions = array_values( $questions );
739 - $at = array_search( $id, $questions );
740 -
741 - if ( 0 < $at ) {
742 - $prev = $questions[ $at - 1 ];
743 - }
744 - }
745 -
746 - return apply_filters( 'learn-press/quiz/prev-question-id', $prev, $this->get_id() );
747 - }*/
748 -
749 - /**
750 - * Get next question from a question.
751 - *
752 - * @param int $id
753 - *
754 - * @return bool
755 - * @deprecated 4.1.6.9
756 - */
757 - /*public function get_next_question( $id ) {
758 - $next = false;
759 - $questions = $this->get_questions();
760 -
761 - if ( $questions ) {
762 - $questions = array_values( $questions );
763 - $at = array_search( $id, $questions );
764 -
765 - if ( sizeof( $questions ) - 1 > $at ) {
766 - $next = $questions[ $at + 1 ];
767 - }
768 - }
769 -
770 - return apply_filters( 'learn-press/quiz/next-question-id', $next, $this->get_id() );
771 - }*/
772 -
773 - /**
774 - * Get index number of a question.
775 - *
776 - * @param int $id
777 - * @param int $start
778 - *
779 - * @return bool|mixed
780 - * @deprecated 4.1.6.9
781 - */
782 - /*public function get_question_index( $id, $start = 0 ) {
783 - $index = 0;
784 - $questions = $this->get_questions();
785 -
786 - if ( $questions ) {
787 - $questions = array_values( $questions );
788 - $index = array_search( $id, $questions );
789 - }
790 -
791 - return apply_filters( 'learn-press/quiz/question-index', intval( $start ) + $index, $this->get_id() );
792 - }*/
793 -
794 - /**
795 - * Check question.
796 - *
797 - * @param $question_id
798 - * @param $user_id
799 - *
800 - * @return bool
801 - * @deprecated 4.2.0
802 - */
803 - public function check_question( $question_id, $user_id ) {
804 - _deprecated_function( __METHOD__, '4.2.0' );
805 - /*$question = LP_Question::get_question( $question_id );
806 -
807 - if ( ! $question ) {
808 - return false;
809 - }
810 -
811 - $user = learn_press_get_user( $user_id );
812 -
813 - $history = $user->get_quiz_results( $this->get_id() );
814 -
815 - if ( ! $history ) {
816 - return false;
817 - }
818 -
819 - $checked = array();
820 - $checked = array_filter( $checked );
821 -
822 - if ( ! in_array( $question_id, $checked ) ) {
823 - $checked[] = $question_id;
824 - }
825 -
826 - return true;*/
827 -
828 - }
829 -
830 - /**
831 - * Get question position in quiz.
832 - *
833 - * @param $question
834 - * @param int $user_id
835 - *
836 - * @return false|int|string
837 - * @deprecated 4.2.0
838 - */
839 - public function get_question_position( $question, $user_id = 0 ) {
840 - _deprecated_function( __METHOD__, '4.2.0' );
841 - /*if ( ! $user_id ) {
842 - $user_id = learn_press_get_current_user_id();
843 - }
844 -
845 - $user = learn_press_get_user( $user_id );
846 - $results = $user->get_quiz_results( $this->get_id(), '', '' );
847 -
848 - if ( $user && $results ) {
849 - $questions = (array) $results->questions;
850 -
851 - } else {
852 - $questions = $this->get_question_ids();
853 - }
854 -
855 - $position = array_search( $question, $questions );
856 -
857 - return $position;*/
858 - }
859 -
860 - /**
861 - * @param int $user_id
862 - * @param int $course_id
863 - *
864 - * @return bool|LP_Question
865 - * @deprecated 4.0.0
866 - */
867 - public function get_current_question( $user_id = 0, $course_id = 0 ) {
868 - _deprecated_function( sprintf( '%s::%s', __CLASS__, __FUNCTION__ ), '4.0.0' );
869 -
870 - /*$user = learn_press_get_user( $user_id );
871 - $id = $user->get_current_quiz_question( $this->get_id(), $course_id );
872 -
873 - return LP_Question::get_question( $id );*/
874 - }
875 -
876 - /**
877 - * @param string $return
878 - *
879 - * @return LP_Question|int
880 - */
881 - public function get_viewing_question( $return = '' ) {
882 - global $lp_quiz_question;
883 -
884 - return $return !== 'id' ? $lp_quiz_question : ( $lp_quiz_question ? $lp_quiz_question->get_id() : 0 );
885 - }
886 -
887 - /**
888 - * @param mixed $the_quiz
889 - * @param array $args
890 - *
891 - * @return LP_Quiz|bool
892 - */
893 - public static function get_quiz( $the_quiz = false, $args = array() ) {
894 - if ( is_numeric( $the_quiz ) && isset( LP_Global::$quizzes[ $the_quiz ] ) ) {
895 - return LP_Global::$quizzes[ $the_quiz ];
896 - }
897 -
898 - $the_quiz = self::get_quiz_object( $the_quiz );
899 -
900 - if ( ! $the_quiz ) {
901 - return false;
902 - }
903 -
904 - if ( isset( LP_Global::$quizzes[ $the_quiz->ID ] ) ) {
905 - return LP_Global::$quizzes[ $the_quiz->ID ];
906 - }
907 -
908 - if ( ! empty( $args['force'] ) ) {
909 - $force = ! ! $args['force'];
910 - unset( $args['force'] );
911 - } else {
912 - $force = false;
913 - }
914 - $key_args = wp_parse_args(
915 - $args,
916 - array(
917 - 'id' => $the_quiz->ID,
918 - 'type' => $the_quiz->post_type,
919 - )
920 - );
921 -
922 - $key = LP_Helper::array_to_md5( $key_args );
923 -
924 - if ( $force ) {
925 - LP_Global::$quizzes[ $key ] = false;
926 - LP_Global::$quizzes[ $the_quiz->ID ] = false;
927 - }
928 -
929 - if ( empty( LP_Global::$quizzes[ $key ] ) ) {
930 - $class_name = self::get_quiz_class( $the_quiz, $args );
931 - if ( is_string( $class_name ) && class_exists( $class_name ) ) {
932 - $quiz = new $class_name( $the_quiz->ID, $args );
933 - } elseif ( $class_name instanceof LP_Course_Item ) {
934 - $quiz = $class_name;
935 - } else {
936 - $quiz = new self( $the_quiz->ID, $args );
937 - }
938 - LP_Global::$quizzes[ $key ] = $quiz;
939 - LP_Global::$quizzes[ $the_quiz->ID ] = $quiz;
940 - }
941 -
942 - return LP_Global::$quizzes[ $key ];
943 - }
944 -
945 - /**
946 - * @param string $quiz_type
947 - *
948 - * @return string|false
949 - */
950 - private static function get_class_name_from_quiz_type( $quiz_type ) {
951 - return LP_QUIZ_CPT === $quiz_type ? __CLASS__ : 'LP_Quiz_' . implode( '_', array_map( 'ucfirst', explode( '-', $quiz_type ) ) );
952 - }
953 -
954 - /**
955 - * Get the lesson class name
956 - *
957 - * @param WP_Post $the_quiz
958 - * @param array $args (default: array())
959 - *
960 - * @return string
961 - */
962 - private static function get_quiz_class( $the_quiz, $args = array() ) {
963 - $quiz_id = absint( $the_quiz->ID );
964 - $type = $the_quiz->post_type;
965 -
966 - $class_name = self::get_class_name_from_quiz_type( $type );
967 -
968 - // Filter class name so that the class can be overridden if extended.
969 - return apply_filters( 'learn-press/quiz/object-class', $class_name, $type, $quiz_id );
970 - }
971 -
972 - /**
973 - * Get the quiz object
974 - *
975 - * @param mixed $the_quiz
976 - *
977 - * @uses WP_Post
978 - * @return WP_Post|bool false on failure
979 - */
980 - private static function get_quiz_object( $the_quiz ) {
981 - if ( false === $the_quiz ) {
982 - $the_quiz = get_post_type() === LP_QUIZ_CPT ? $GLOBALS['post'] : false;
983 - } elseif ( is_numeric( $the_quiz ) ) {
984 - $the_quiz = get_post( $the_quiz );
985 - } elseif ( $the_quiz instanceof LP_Course_Item ) {
986 - $the_quiz = get_post( $the_quiz->get_id() );
987 - } elseif ( ! ( $the_quiz instanceof WP_Post ) ) {
988 - $the_quiz = false;
989 - }
990 -
991 - return apply_filters( 'learn-press/quiz/post-object', $the_quiz );
992 - }
993 -
994 - public function set_show_hide_question( $show_or_hide ) {
995 - $this->_set_data( 'show_hide_question', $show_or_hide );
996 - }
997 -
998 - /**
999 - * Set quiz is preview or not.
1000 - * using
1001 - */
1002 - public function set_preview( $preview ) {
1003 - $this->_set_data( 'preview', $preview );
1004 - }
1005 -
1006 - /**
1007 - * @deprecated
1008 - *
1009 - * @param $skip
1010 - */
1011 - public function set_minus_skip_questions( $skip ) {
1012 - $this->_set_data( 'minus_skip_questions', $skip );
1013 - }
1014 -
1015 - /**
1016 - * Get quiz is preview or not.
1017 - * using
1018 - */
1019 - public function get_preview() {
1020 - return 'yes' === $this->get_data( 'preview' );
1021 - }
1022 -
1023 - // public function get_minus_points() {
1024 - // return $this->get_data( 'minus_points' );
1025 - // }
1026 -
1027 - /**
1028 - * Get option skip question will be minus points
1029 - *
1030 - * @return bool
1031 - */
1032 - public function get_minus_skip_questions(): bool {
1033 - return 'yes' === $this->get_data( 'minus_skip_questions', 'no' );
1034 - }
1035 -
1036 - /**
1037 - * Get css classes of question displays in a list.
1038 - *
1039 - * @param int $question_id
1040 - * @param null $position
1041 - *
1042 - * @return array
1043 - * @deprecated 4.1.6.9
1044 - */
1045 - /*public function get_question_number_class( $question_id, $position = null ) {
1046 - if ( null === $position ) {
1047 - $position = $this->get_question_index( $question_id );
1048 - }
1049 -
1050 - $class = array( 'question-' . $position );
1051 -
1052 - if ( $this->is_viewing_question( $question_id ) ) {
1053 - $class[] = 'current';
1054 - }
1055 -
1056 - $user = learn_press_get_current_user();
1057 - $quiz_data = $user->get_quiz_data( $this->get_id() );
1058 -
1059 - if ( $quiz_data ) {
1060 - if ( $quiz_data->is_skipped( $question_id ) ) {
1061 - $class[] = 'skipped';
1062 - }
1063 - }
1064 -
1065 - return $class;
1066 - }*/
1067 -
1068 - /**
1069 - * @param mixed $offset
1070 - *
1071 - * @return bool|mixed
1072 - * @deprecated 4.2.0
1073 - */
1074 - public function offsetGet( $offset ) {
1075 - _deprecated_function( __CLASS__ . '::' . __METHOD__, '4.2.0' );
1076 - return $this->offsetExists( $offset ) ? $this->_questions[ $offset ] : false;
1077 - }
1078 -
1079 - /**
1080 - * @param mixed $offset
1081 - *
1082 - * @return bool
1083 - * @deprecated 4.2.0
1084 - */
1085 - public function offsetExists( $offset ) {
1086 - _deprecated_function( __CLASS__ . '::' . __METHOD__, '4.2.0' );
1087 - /*return array_key_exists( $offset, $this->_questions );*/
1088 - }
1089 - }
1090 -}
1 +<?php
2 +/**
3 + * Class LP_Quiz.
4 + *
5 + * @author ThimPress
6 + * @package LearnPress/Classes
7 + * @version 3.0.0
8 + */
9 +
10 +defined( 'ABSPATH' ) || exit();
11 +
12 +if ( ! class_exists( 'LP_Quiz' ) ) {
13 +
14 + /**
15 + * Class LP_Quiz
16 + */
17 + class LP_Quiz extends LP_Course_Item {
18 +
19 +
20 + /**
21 + * @var array
22 + *
23 + * @deprecated
24 + */
25 + protected static $_meta = array();
26 +
27 + /**
28 + * @var string
29 + */
30 + protected $_item_type = LP_QUIZ_CPT;
31 +
32 + /**
33 + * @var array
34 + */
35 + protected $_questions = array();
36 +
37 + /**
38 + * @var array
39 + */
40 + protected $_data = array(
41 + // 'show_result' => 'no',
42 + 'passing_grade_type' => '',
43 + 'passing_grade' => 0,
44 + // 'show_check_answer' => 'no',
45 + // 'count_check_answer' => 0,
46 + // 'show_hint' => 'no',
47 + // 'count_hint' => 0,
48 + // 'archive_history' => 'no',
49 + // 'show_hide_question' => 'yes',
50 + // 'preview' => 'no',
51 + // 'minus_points' => 0,
52 + 'minus_skip_questions' => 'no',
53 +
54 + 'negative_marking' => 'no',
55 + 'instant_check' => 'no',
56 + 'retake_count' => 0,
57 + 'show_correct_review' => 'yes',
58 + );
59 +
60 + /**
61 + * @var int
62 + */
63 + protected static $_loaded = 0;
64 +
65 + /**
66 + * Constructor gets the post object and sets the ID for the loaded course.
67 + *
68 + * @param mixed $the_quiz
69 + * @param mixed $args
70 + */
71 + public function __construct( $the_quiz, $args = array() ) {
72 + $this->_curd = new LP_Quiz_CURD();
73 +
74 + if ( is_numeric( $the_quiz ) && $the_quiz > 0 ) {
75 + $this->set_id( $the_quiz );
76 + } elseif ( $the_quiz instanceof self ) {
77 + $this->set_id( absint( $the_quiz->get_id() ) );
78 + } elseif ( ! empty( $the_quiz->ID ) ) {
79 + $this->set_id( absint( $the_quiz->ID ) );
80 + }
81 + if ( $this->get_id() > 0 ) {
82 + $this->load();
83 + }
84 +
85 + self::$_loaded ++;
86 + if ( self::$_loaded == 1 ) {
87 + add_filter( 'debug_data', array( __CLASS__, 'log' ) );
88 + }
89 + }
90 +
91 + /**
92 + * Log debug data.
93 + *
94 + * @since 3.0.0
95 + *
96 + * @param $data
97 + *
98 + * @return array
99 + */
100 + public static function log( $data ) {
101 + $data[] = __CLASS__ . '( ' . self::$_loaded . ' )';
102 +
103 + return $data;
104 + }
105 +
106 + /**
107 + * @param string $context
108 + *
109 + * @return string
110 + */
111 + public function get_heading_title( $context = '' ) {
112 + return $this->get_title( $context );
113 + }
114 +
115 + /**
116 + * Load quiz data
117 + */
118 + public function load() {
119 + $this->_curd->load( $this );
120 + }
121 +
122 + /**
123 + * Get default quiz meta.
124 + *
125 + * @since 3.0.0
126 + *
127 + * @return mixed
128 + */
129 + public static function get_default_meta() {
130 + $meta = array(
131 + 'review' => 'no',
132 + 'duration' => '10 minute',
133 + 'passing_grade' => 80,
134 + 'negative_marking' => 'no',
135 + 'instant_check' => 'no',
136 + 'retake_count' => '0',
137 + 'pagination' => 1,
138 + 'show_correct_review' => 'yes',
139 + );
140 +
141 + return apply_filters( 'learn-press/quiz/default-meta', $meta );
142 + }
143 +
144 + /**
145 + * Save quiz data.
146 + *
147 + * @return mixed
148 + *
149 + * @throws Exception
150 + */
151 + public function save() {
152 + if ( $this->get_id() ) {
153 + $return = $this->_curd->update( $this );
154 + } else {
155 + $return = $this->_curd->create( $this );
156 + }
157 +
158 + return $return;
159 + }
160 +
161 + public function get_negative_marking() {
162 + return $this->get_data( 'negative_marking' ) === 'yes';
163 + }
164 +
165 + public function set_negative_marking( $set ) {
166 + $this->_set_data( 'negative_marking', ! learn_press_is_negative_value( $set ) ? 'yes' : 'no' );
167 + }
168 +
169 + public function get_show_correct_review() {
170 + return $this->get_data( 'show_correct_review' ) === 'yes';
171 + }
172 +
173 + public function set_show_correct_review( $set ) {
174 + $this->_set_data( 'show_correct_review', $set );
175 + }
176 +
177 + public function get_instant_check() {
178 + return $this->get_data( 'instant_check' ) === 'yes';
179 + }
180 +
181 + public function set_instant_check( $set ) {
182 + $this->_set_data( 'instant_check', ! learn_press_is_negative_value( $set ) ? 'yes' : 'no' );
183 + }
184 +
185 + public function set_retake_count( $count ) {
186 + $this->_set_data( 'retake_count', $count );
187 + }
188 +
189 + public function get_retake_count() {
190 + return $this->get_data( 'retake_count' );
191 + }
192 +
193 + public function get_pagination() {
194 + return ( $n = $this->get_data( 'pagination' ) ) > 1 ? $n : 0;
195 + }
196 +
197 + public function set_pagination( $set ) {
198 + $this->_set_data( 'pagination', absint( $set ) );
199 + }
200 +
201 + /**
202 + * @deprecated
203 + *
204 + * @param $show_result
205 + */
206 + public function set_show_result( $show_result ) {
207 + _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.0.0' );
208 +
209 + $this->_set_data( 'show_result', $show_result );
210 + }
211 +
212 + /**
213 + * @deprecated
214 + *
215 + * @return array|mixed
216 + */
217 + public function get_show_result() {
218 +
219 + _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.0.0' );
220 +
221 + return $this->get_data( 'show_result' ) === 'yes';
222 + }
223 +
224 + /**
225 + *
226 + * @param $review_questions
227 + */
228 + public function set_review_questions( $review_questions ) {
229 +
230 + $this->_set_data( 'review_questions', $review_questions );
231 + }
232 +
233 + /**
234 + * Enable review quiz
235 + *
236 + * @return bool
237 + */
238 + public function get_review_questions(): bool {
239 + return 'yes' === $this->get_data( 'review_questions', 'yes' );
240 + }
241 +
242 + /**
243 + * @param $type
244 + */
245 + public function set_passing_grade_type( $type ) {
246 + $this->_set_data( 'passing_grade_type', $type );
247 + }
248 +
249 + /**
250 + * @return array|mixed
251 + */
252 + public function get_passing_grade_type() {
253 + return $this->get_data( 'passing_grade_type', 'percentage' );
254 + }
255 +
256 + /**
257 + * @param $value
258 + */
259 + public function set_passing_grade( $value ) {
260 + $this->_set_data( 'passing_grade', $value );
261 + }
262 +
263 + /**
264 + * @return array|mixed
265 + */
266 + public function get_passing_grade() {
267 + $type = $this->get_passing_grade_type();
268 + $value = get_post_meta( $this->get_id(), '_lp_passing_grade', true );
269 + if ( empty( $value ) ) {
270 + $value = 80;
271 + }
272 +
273 + switch ( $type ) {
274 + case 'point':
275 + break;
276 + case 'percentage':
277 + default:
278 + $value = "{$value}%";
279 + break;
280 + }
281 +
282 + return $value;
283 + }
284 +
285 + /**
286 + * @deprecated
287 + *
288 + * @param $value
289 + */
290 + public function set_show_check_answer( $value ) {
291 + _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.0.0' );
292 +
293 + $this->_set_data( 'show_check_answer', $value );
294 + }
295 +
296 + /**
297 + * @deprecated
298 + *
299 + * @return int|bool
300 + */
301 + public function get_show_check_answer() {
302 + _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.0.0' );
303 +
304 + return intval( $this->get_data( 'show_check_answer' ) );
305 + }
306 +
307 + /**
308 + * @deprecated
309 + *
310 + * @param $count
311 + */
312 + public function set_count_check_answer( $count ) {
313 + _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.0.0' );
314 +
315 + $this->_set_data( 'count_check_answer', $count );
316 + }
317 +
318 + /**
319 + * @deprecated
320 + *
321 + * @return int
322 + */
323 + public function get_check_answer_count() {
324 + _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.0.0' );
325 +
326 + return intval( $this->get_data( 'check_answer_count' ) );
327 + }
328 +
329 + /**
330 + * @deprecated
331 + *
332 + * @param $value
333 + */
334 + public function set_show_hint( $value ) {
335 + _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.0.0' );
336 +
337 + $this->_set_data( 'show_hint', $value );
338 + }
339 +
340 + /**
341 + * @deprecated
342 + *
343 + * @return int
344 + */
345 + public function get_show_hint() {
346 + _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.0.0' );
347 +
348 + return intval( $this->get_data( 'show_hint' ) );
349 + }
350 +
351 + /**
352 + * @deprecated
353 + *
354 + * @param $count
355 + */
356 + public function set_count_hint( $count ) {
357 + _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.0.0' );
358 +
359 + $this->_set_data( 'count_hint', $count );
360 + }
361 +
362 + /**
363 + * Return true if hint answer is enabled.
364 + *
365 + * @deprecated
366 + *
367 + * @return bool
368 + */
369 + public function enable_show_hint() {
370 + _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.0.0' );
371 +
372 + return apply_filters( 'learn-press/quiz/enable-show-hint', $this->get_data( 'show_hint' ) == 'yes', $this->get_id() );
373 + }
374 +
375 + /**
376 + * @deprecated
377 + *
378 + * @param $value
379 + */
380 + public function set_archive_history( $value ) {
381 + _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.0.0' );
382 +
383 + $this->_set_data( 'archive_history', $value );
384 + }
385 +
386 + /**
387 + * Return true if archive history is enabled.
388 + *
389 + * @deprecated
390 + *
391 + * @return bool
392 + */
393 + public function enable_archive_history() {
394 + _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.0.0' );
395 +
396 + return apply_filters( 'learn-press/quiz/enable-archive-history', $this->get_data( 'archive_history' ) == 'yes', $this->get_id() );
397 + }
398 +
399 + /**
400 + * Return total mark of quiz by calculating total mark of all questions.
401 + *
402 + * @return int
403 + */
404 + public function get_mark() {
405 + $mark = $this->get_data( 'mark', false );
406 + if ( false === $mark || '' === $mark ) {
407 + $questions = $this->get_question_ids();
408 + $mark = 0;
409 +
410 + foreach ( $questions as $question_id ) {
411 + $question = LP_Question::get_question( $question_id );
412 + if ( $question ) {
413 + $mark += $question->get_mark();
414 + }
415 + }
416 +
417 + $this->_set_data( 'mark', $mark );
418 + }
419 +
420 + return apply_filters( 'learn-press/quiz-mark', $mark, $this->get_id() );
421 + }
422 +
423 + /**
424 + * Get duration of quiz
425 + *
426 + * @return LP_Duration
427 + */
428 + public function get_duration() {
429 + $duration = parent::get_duration();
430 +
431 + return apply_filters( 'learn-press/quiz-duration', $duration, $this->get_id() );
432 + }
433 +
434 + /**
435 + * Get quiz questions.
436 + *
437 + * @param string $context
438 + *
439 + * @return mixed
440 + * @editor tungnx
441 + * @since 3.x.x
442 + * @version 1.0.1
443 + * @deprecated 4.2.0
444 + */
445 + public function get_questions( $context = 'display' ) {
446 + _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.2.0' );
447 + $questions = array();
448 + $ids = $this->_curd->read_question_ids( $this->get_id() );
449 +
450 + if ( $ids ) {
451 + foreach ( $ids as $id ) {
452 + $questions[ $id ] = $id;
453 + }
454 + }
455 +
456 + return apply_filters( 'learn-press/quiz/questions', $questions, $this->get_id(), $this->get_course_id(), $context );
457 + }
458 +
459 + /**
460 + * Quiz editor get questions.
461 + *
462 + * @return mixed
463 + */
464 + public function quiz_editor_get_questions() {
465 + // list questions
466 + $questions = $this->get_question_ids( 'edit' );
467 + // order questions in quiz
468 + $question_order = learn_press_quiz_get_questions_order( $questions );
469 +
470 + $result = array();
471 +
472 + foreach ( $questions as $id ) {
473 + $question = LP_Question::get_question( $id );
474 +
475 + $answers = array();
476 + // handle question answer
477 + if ( is_array( $question->get_data( 'answer_options' ) ) ) {
478 + foreach ( $question->get_data( 'answer_options' ) as $answer ) {
479 + $answers[] = $answer;
480 + }
481 + }
482 +
483 + $post = get_post( $id );
484 + $result[] = apply_filters(
485 + 'learn-press/quiz-editor/question-data',
486 + array(
487 + 'id' => $id,
488 + 'open' => false,
489 + 'title' => $post->post_title,
490 + 'type' => array(
491 + 'key' => $question->get_type(),
492 + 'label' => $question->get_type_label(),
493 + ),
494 + 'answers' => apply_filters( 'learn-press/quiz-editor/question-answers-data', $answers, $id, $this->get_id() ),
495 + 'settings' => array(
496 + 'content' => $post->post_content,
497 + 'mark' => get_post_meta( $id, '_lp_mark', true ),
498 + 'explanation' => get_post_meta( $id, '_lp_explanation', true ),
499 + 'hint' => get_post_meta( $id, '_lp_hint', true ),
500 + ),
501 + 'order' => $question_order[ $id ],
502 + ),
503 + $id,
504 + $this->get_id()
505 + );
506 + }
507 +
508 + return apply_filters( 'learn-press/quiz/quiz_editor_questions', $result, $this->get_id() );
509 + }
510 +
511 + /**
512 + * Get quiz duration html.
513 + *
514 + * @return mixed
515 + */
516 + public function get_duration_html() {
517 + $duration = $this->get_duration();
518 + if ( $duration ) {
519 + $duration = learn_press_seconds_to_time( $duration->get_seconds() );
520 + } else {
521 + $duration = __( 'Unlimited', 'learnpress' );
522 + }
523 +
524 + return apply_filters( 'learn_press_quiz_duration_html', $duration, $this );
525 + }
526 +
527 + /**
528 + * Get number questions in quiz.
529 + *
530 + * @return int
531 + */
532 + public function count_questions(): int {
533 + $size = 0;
534 + $questions = $this->get_question_ids();
535 +
536 + if ( $questions ) {
537 + $size = sizeof( $questions );
538 + }
539 +
540 + return (int) apply_filters( 'learn-press/quiz/count-questions', $size, $this->get_id() );
541 + }
542 +
543 + /**
544 + * Get all question's ids of the quiz.
545 + *
546 + * @param string $context
547 + *
548 + * @return int[]
549 + * @editor tungnx
550 + * @version 1.0.1
551 + * @since 3.2.0
552 + */
553 + public function get_question_ids( string $context = 'display' ): array {
554 + $question_ids = $this->_curd->read_question_ids( $this->get_id(), $context );
555 + $question_ids = apply_filters( 'learn-press/quiz/get-question-ids', $question_ids, $this->get_id(), $this->get_course_id(), $context );
556 + if ( ! is_array( $question_ids ) ) {
557 + $question_ids = array();
558 + }
559 +
560 + return $question_ids;
561 + }
562 +
563 + /**
564 + * Get number questions for user do it.
565 + *
566 + * @return mixed|null
567 + */
568 + public function get_number_questions_to_do() {
569 + return apply_filters( 'learn-press/quiz/number-questions-show', $this->count_questions(), $this );
570 + }
571 +
572 + /**
573 + * This quiz has any question?
574 + *
575 + * @return bool
576 + */
577 + public function has_questions() {
578 + return $this->count_questions() > 0;
579 + }
580 +
581 + /**
582 + * Get js localize script in frontend. [NOT USED]
583 + *
584 + * @return mixed
585 + */
586 + public function get_localize() {
587 + $localize = array(
588 + 'confirm_finish_quiz' => array(
589 + 'title' => __( 'Finish quiz', 'learnpress' ),
590 + 'message' => __( 'Are you sure you want to finish this quiz?', 'learnpress' ),
591 + ),
592 + 'confirm_retake_quiz' => array(
593 + 'title' => __( 'Retake quiz', 'learnpress' ),
594 + 'message' => __( 'Are you sure you want to retake this quiz?', 'learnpress' ),
595 + ),
596 + 'quiz_time_is_over' => array(
597 + 'title' => __( 'Time\'s up!', 'learnpress' ),
598 + 'message' => __( 'The time is up! Your quiz will automatically come to an end', 'learnpress' ),
599 + ),
600 + 'finished_quiz' => __( 'Congrats! You have finished this quiz', 'learnpress' ),
601 + 'retaken_quiz' => __( 'Congrats! You have re-taken this quiz. Please wait a moment and the page will reload', 'learnpress' ),
602 + );
603 +
604 + return apply_filters( 'learn_press_single_quiz_localize', $localize, $this );
605 + }
606 +
607 + /**
608 + * __isset function.
609 + *
610 + * @param mixed $key
611 + *
612 + * @return bool
613 + */
614 + public function __isset( $key ) {
615 + return metadata_exists( 'post', $this->get_id(), '_' . $key );
616 + }
617 +
618 + /**
619 + * __get function.
620 + *
621 + * @param string $key
622 + *
623 + * @return mixed
624 + * @deprecated 4.0.8
625 + */
626 + public function __get( $key ) {
627 + _deprecated_function( __METHOD__, '4.0.8' );
628 + /*echo '@deprecated[' . $key . ']';
629 + learn_press_debug( debug_backtrace() );
630 +
631 + return false;*/
632 + }
633 +
634 + /**
635 + * @param $feature
636 + *
637 + * @return mixed
638 + * @throws Exception
639 + * @deprecated 3.0.8
640 + */
641 + public function has( $feature ) {
642 + _deprecated_function( __FUNCTION__, '3.0.8' );
643 +
644 + $args = func_get_args();
645 + unset( $args[0] );
646 + $method = 'has_' . preg_replace( '!-!', '_', $feature );
647 + $callback = array( $this, $method );
648 + if ( is_callable( $callback ) ) {
649 + return call_user_func_array( $callback, $args );
650 + } else {
651 + throw new Exception( sprintf( __( 'The function %s doesn\'t exist', 'learnpress' ), $feature ) );
652 + }
653 + }
654 +
655 + /**
656 + * Return TRUE if quiz contain a question.
657 + *
658 + * @param int $question_id
659 + *
660 + * @return bool
661 + */
662 + public function has_question( $question_id ) {
663 + $questions = $this->get_question_ids();
664 +
665 + return apply_filters( 'learn-press/quiz/has-question', in_array( $question_id, $questions ), $question_id, $this->get_id() );
666 + }
667 +
668 + /**
669 + * Get question permalink from it's ID.
670 + * If permalink option is turn on, add name of question
671 + * into quiz permalink. Otherwise, add it's ID into
672 + * query var.
673 + *
674 + * @param int $question_id
675 + *
676 + * @return string
677 + * @deprecated 4.2.0
678 + */
679 + public function get_question_link( $question_id = null ) {
680 + _deprecated_function( __METHOD__, '4.2.0' );
681 + /*$course = learn_press_get_course();
682 + if ( ! $course ) {
683 + return '';
684 + }
685 +
686 + $permalink = $course->get_item_link( $this->get_id() );
687 + if ( '' != get_option( 'permalink_structure' ) && get_post_status( $this->get_id() ) != 'draft' ) {
688 + if ( get_post_type( $question_id ) === LP_QUESTION_CPT ) {
689 + $question_name = get_post_field( 'post_name', $question_id );
690 + preg_match( '/\?/i', $permalink, $result );
691 + if ( empty( $result ) ) {
692 + $permalink = $permalink . $question_name;
693 + } else {
694 + $permalink = preg_replace( '/\?/i', '/' . $question_name . '/?', $permalink );
695 + }
696 + }
697 + } else {
698 + $permalink = esc_url_raw( add_query_arg( array( 'question', $question_id ), $permalink ) );
699 + }
700 +
701 + // @deprecated
702 + $permalink = apply_filters( 'learn_press_quiz_question_permalink', $permalink, $question_id, $this );
703 +
704 + return apply_filters( 'learn-press/quiz/question-permalink', $permalink, $question_id, $this->get_id() );*/
705 + }
706 +
707 + /**
708 + * @param int $at
709 + *
710 + * @return bool
711 + * @deprecated 4.1.6.9
712 + */
713 + /*public function get_question_at( $at = 0 ) {
714 + $questions = $this->get_questions();
715 +
716 + if ( $questions ) {
717 + $questions = array_values( $questions );
718 +
719 + return @$questions[ $at ];
720 + }
721 +
722 + return false;
723 + }*/
724 +
725 + /**
726 + * Get prev question from a question.
727 + *
728 + * @param int $id
729 + *
730 + * @return bool
731 + * @deprecated 4.1.6.9
732 + */
733 + /*public function get_prev_question( $id ) {
734 + $prev = false;
735 + $questions = $this->get_questions();
736 +
737 + if ( $questions ) {
738 + $questions = array_values( $questions );
739 + $at = array_search( $id, $questions );
740 +
741 + if ( 0 < $at ) {
742 + $prev = $questions[ $at - 1 ];
743 + }
744 + }
745 +
746 + return apply_filters( 'learn-press/quiz/prev-question-id', $prev, $this->get_id() );
747 + }*/
748 +
749 + /**
750 + * Get next question from a question.
751 + *
752 + * @param int $id
753 + *
754 + * @return bool
755 + * @deprecated 4.1.6.9
756 + */
757 + /*public function get_next_question( $id ) {
758 + $next = false;
759 + $questions = $this->get_questions();
760 +
761 + if ( $questions ) {
762 + $questions = array_values( $questions );
763 + $at = array_search( $id, $questions );
764 +
765 + if ( sizeof( $questions ) - 1 > $at ) {
766 + $next = $questions[ $at + 1 ];
767 + }
768 + }
769 +
770 + return apply_filters( 'learn-press/quiz/next-question-id', $next, $this->get_id() );
771 + }*/
772 +
773 + /**
774 + * Get index number of a question.
775 + *
776 + * @param int $id
777 + * @param int $start
778 + *
779 + * @return bool|mixed
780 + * @deprecated 4.1.6.9
781 + */
782 + /*public function get_question_index( $id, $start = 0 ) {
783 + $index = 0;
784 + $questions = $this->get_questions();
785 +
786 + if ( $questions ) {
787 + $questions = array_values( $questions );
788 + $index = array_search( $id, $questions );
789 + }
790 +
791 + return apply_filters( 'learn-press/quiz/question-index', intval( $start ) + $index, $this->get_id() );
792 + }*/
793 +
794 + /**
795 + * Check question.
796 + *
797 + * @param $question_id
798 + * @param $user_id
799 + *
800 + * @return bool
801 + * @deprecated 4.2.0
802 + */
803 + public function check_question( $question_id, $user_id ) {
804 + _deprecated_function( __METHOD__, '4.2.0' );
805 + /*$question = LP_Question::get_question( $question_id );
806 +
807 + if ( ! $question ) {
808 + return false;
809 + }
810 +
811 + $user = learn_press_get_user( $user_id );
812 +
813 + $history = $user->get_quiz_results( $this->get_id() );
814 +
815 + if ( ! $history ) {
816 + return false;
817 + }
818 +
819 + $checked = array();
820 + $checked = array_filter( $checked );
821 +
822 + if ( ! in_array( $question_id, $checked ) ) {
823 + $checked[] = $question_id;
824 + }
825 +
826 + return true;*/
827 +
828 + }
829 +
830 + /**
831 + * Get question position in quiz.
832 + *
833 + * @param $question
834 + * @param int $user_id
835 + *
836 + * @return false|int|string
837 + * @deprecated 4.2.0
838 + */
839 + public function get_question_position( $question, $user_id = 0 ) {
840 + _deprecated_function( __METHOD__, '4.2.0' );
841 + /*if ( ! $user_id ) {
842 + $user_id = learn_press_get_current_user_id();
843 + }
844 +
845 + $user = learn_press_get_user( $user_id );
846 + $results = $user->get_quiz_results( $this->get_id(), '', '' );
847 +
848 + if ( $user && $results ) {
849 + $questions = (array) $results->questions;
850 +
851 + } else {
852 + $questions = $this->get_question_ids();
853 + }
854 +
855 + $position = array_search( $question, $questions );
856 +
857 + return $position;*/
858 + }
859 +
860 + /**
861 + * @param int $user_id
862 + * @param int $course_id
863 + *
864 + * @return bool|LP_Question
865 + * @deprecated 4.0.0
866 + */
867 + public function get_current_question( $user_id = 0, $course_id = 0 ) {
868 + _deprecated_function( sprintf( '%s::%s', __CLASS__, __FUNCTION__ ), '4.0.0' );
869 +
870 + /*$user = learn_press_get_user( $user_id );
871 + $id = $user->get_current_quiz_question( $this->get_id(), $course_id );
872 +
873 + return LP_Question::get_question( $id );*/
874 + }
875 +
876 + /**
877 + * @param string $return
878 + *
879 + * @return LP_Question|int
880 + */
881 + public function get_viewing_question( $return = '' ) {
882 + global $lp_quiz_question;
883 +
884 + return $return !== 'id' ? $lp_quiz_question : ( $lp_quiz_question ? $lp_quiz_question->get_id() : 0 );
885 + }
886 +
887 + /**
888 + * @param mixed $the_quiz
889 + * @param array $args
890 + *
891 + * @return LP_Quiz|bool
892 + */
893 + public static function get_quiz( $the_quiz = false, $args = array() ) {
894 + if ( is_numeric( $the_quiz ) && isset( LP_Global::$quizzes[ $the_quiz ] ) ) {
895 + return LP_Global::$quizzes[ $the_quiz ];
896 + }
897 +
898 + $the_quiz = self::get_quiz_object( $the_quiz );
899 +
900 + if ( ! $the_quiz ) {
901 + return false;
902 + }
903 +
904 + if ( isset( LP_Global::$quizzes[ $the_quiz->ID ] ) ) {
905 + return LP_Global::$quizzes[ $the_quiz->ID ];
906 + }
907 +
908 + if ( ! empty( $args['force'] ) ) {
909 + $force = ! ! $args['force'];
910 + unset( $args['force'] );
911 + } else {
912 + $force = false;
913 + }
914 + $key_args = wp_parse_args(
915 + $args,
916 + array(
917 + 'id' => $the_quiz->ID,
918 + 'type' => $the_quiz->post_type,
919 + )
920 + );
921 +
922 + $key = LP_Helper::array_to_md5( $key_args );
923 +
924 + if ( $force ) {
925 + LP_Global::$quizzes[ $key ] = false;
926 + LP_Global::$quizzes[ $the_quiz->ID ] = false;
927 + }
928 +
929 + if ( empty( LP_Global::$quizzes[ $key ] ) ) {
930 + $class_name = self::get_quiz_class( $the_quiz, $args );
931 + if ( is_string( $class_name ) && class_exists( $class_name ) ) {
932 + $quiz = new $class_name( $the_quiz->ID, $args );
933 + } elseif ( $class_name instanceof LP_Course_Item ) {
934 + $quiz = $class_name;
935 + } else {
936 + $quiz = new self( $the_quiz->ID, $args );
937 + }
938 + LP_Global::$quizzes[ $key ] = $quiz;
939 + LP_Global::$quizzes[ $the_quiz->ID ] = $quiz;
940 + }
941 +
942 + return LP_Global::$quizzes[ $key ];
943 + }
944 +
945 + /**
946 + * @param string $quiz_type
947 + *
948 + * @return string|false
949 + */
950 + private static function get_class_name_from_quiz_type( $quiz_type ) {
951 + return LP_QUIZ_CPT === $quiz_type ? __CLASS__ : 'LP_Quiz_' . implode( '_', array_map( 'ucfirst', explode( '-', $quiz_type ) ) );
952 + }
953 +
954 + /**
955 + * Get the lesson class name
956 + *
957 + * @param WP_Post $the_quiz
958 + * @param array $args (default: array())
959 + *
960 + * @return string
961 + */
962 + private static function get_quiz_class( $the_quiz, $args = array() ) {
963 + $quiz_id = absint( $the_quiz->ID );
964 + $type = $the_quiz->post_type;
965 +
966 + $class_name = self::get_class_name_from_quiz_type( $type );
967 +
968 + // Filter class name so that the class can be overridden if extended.
969 + return apply_filters( 'learn-press/quiz/object-class', $class_name, $type, $quiz_id );
970 + }
971 +
972 + /**
973 + * Get the quiz object
974 + *
975 + * @param mixed $the_quiz
976 + *
977 + * @uses WP_Post
978 + * @return WP_Post|bool false on failure
979 + */
980 + private static function get_quiz_object( $the_quiz ) {
981 + if ( false === $the_quiz ) {
982 + $the_quiz = get_post_type() === LP_QUIZ_CPT ? $GLOBALS['post'] : false;
983 + } elseif ( is_numeric( $the_quiz ) ) {
984 + $the_quiz = get_post( $the_quiz );
985 + } elseif ( $the_quiz instanceof LP_Course_Item ) {
986 + $the_quiz = get_post( $the_quiz->get_id() );
987 + } elseif ( ! ( $the_quiz instanceof WP_Post ) ) {
988 + $the_quiz = false;
989 + }
990 +
991 + return apply_filters( 'learn-press/quiz/post-object', $the_quiz );
992 + }
993 +
994 + public function set_show_hide_question( $show_or_hide ) {
995 + $this->_set_data( 'show_hide_question', $show_or_hide );
996 + }
997 +
998 + /**
999 + * Set quiz is preview or not.
1000 + * using
1001 + */
1002 + public function set_preview( $preview ) {
1003 + $this->_set_data( 'preview', $preview );
1004 + }
1005 +
1006 + /**
1007 + * Set option skip question will be minus points
1008 + *
1009 + * @param $skip
1010 + */
1011 + public function set_minus_skip_questions( $skip ) {
1012 + $this->_set_data( 'minus_skip_questions', $skip );
1013 + }
1014 +
1015 + /**
1016 + * Get quiz is preview or not.
1017 + * using
1018 + */
1019 + public function get_preview() {
1020 + return 'yes' === $this->get_data( 'preview' );
1021 + }
1022 +
1023 + // public function get_minus_points() {
1024 + // return $this->get_data( 'minus_points' );
1025 + // }
1026 +
1027 + /**
1028 + * Get option skip question will be minus points
1029 + *
1030 + * @return bool
1031 + */
1032 + public function get_minus_skip_questions(): bool {
1033 + return 'yes' === $this->get_data( 'minus_skip_questions', 'no' );
1034 + }
1035 +
1036 + /**
1037 + * Get css classes of question displays in a list.
1038 + *
1039 + * @param int $question_id
1040 + * @param null $position
1041 + *
1042 + * @return array
1043 + * @deprecated 4.1.6.9
1044 + */
1045 + /*public function get_question_number_class( $question_id, $position = null ) {
1046 + if ( null === $position ) {
1047 + $position = $this->get_question_index( $question_id );
1048 + }
1049 +
1050 + $class = array( 'question-' . $position );
1051 +
1052 + if ( $this->is_viewing_question( $question_id ) ) {
1053 + $class[] = 'current';
1054 + }
1055 +
1056 + $user = learn_press_get_current_user();
1057 + $quiz_data = $user->get_quiz_data( $this->get_id() );
1058 +
1059 + if ( $quiz_data ) {
1060 + if ( $quiz_data->is_skipped( $question_id ) ) {
1061 + $class[] = 'skipped';
1062 + }
1063 + }
1064 +
1065 + return $class;
1066 + }*/
1067 +
1068 + /**
1069 + * @param mixed $offset
1070 + *
1071 + * @return bool|mixed
1072 + * @deprecated 4.2.0
1073 + */
1074 + public function offsetGet( $offset ) {
1075 + _deprecated_function( __CLASS__ . '::' . __METHOD__, '4.2.0' );
1076 + return $this->offsetExists( $offset ) ? $this->_questions[ $offset ] : false;
1077 + }
1078 +
1079 + /**
1080 + * @param mixed $offset
1081 + *
1082 + * @return bool
1083 + * @deprecated 4.2.0
1084 + */
1085 + public function offsetExists( $offset ) {
1086 + _deprecated_function( __CLASS__ . '::' . __METHOD__, '4.2.0' );
1087 + /*return array_key_exists( $offset, $this->_questions );*/
1088 + }
1089 + }
1090 +}