PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.0
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.0
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 / curds / class-lp-quiz-curd.php

class-lp-quiz-curd.php in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.4.0, at inc/curds/class-lp-quiz-curd.php

750 lines 18.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class LP_Quiz_CURD.
4 *
5 * @author ThimPress
6 * @package LearnPress/Classes/CURD
7 * @since 3.0.0
8 */
9
10 /**
11 * Prevent loading this file directly
12 */
13 defined( 'ABSPATH' ) || exit();
14
15 if ( ! function_exists( 'LP_Quiz_CURD' ) ) {
16
17 /**
18 * Class LP_Quiz_CURD
19 *
20 * Class to manipulating quiz with database.
21 */
22 class LP_Quiz_CURD extends LP_Object_Data_CURD implements LP_Interface_CURD {
23
24 /**
25 * LP_Quiz_CURD constructor.
26 */
27 public function __construct() {
28 $this->_error_messages = array(
29 'QUIZ_NOT_EXISTS' => __( 'The quiz does not exist.', 'learnpress' ),
30 );
31 }
32
33 /**
34 * @param LP_Quiz $quiz
35 *
36 * @return LP_Quiz|mixed
37 * @throws Exception
38 */
39 public function load( &$quiz ) {
40 $id = $quiz->get_id();
41 if ( ! $id || learn_press_get_post_type( $id ) !== LP_QUIZ_CPT ) {
42
43 throw new Exception( sprintf( __( 'Invalid quiz with ID "%d".', 'learnpress' ), $id ) );
44 }
45
46 // LP_Helper_CURD::update_meta_cache( $quiz->get_id() );
47
48 $quiz->set_data_via_methods(
49 array(
50 // 'show_result' => get_post_meta( $quiz->get_id(), '_lp_show_result', true ),
51 'passing_grade_type' => get_post_meta( $quiz->get_id(), '_lp_passing_grade_type', true ),
52 'passing_grade' => get_post_meta( $quiz->get_id(), '_lp_passing_grade', true ),
53 // 'show_check_answer' => get_post_meta( $quiz->get_id(), '_lp_show_check_answer', true ),
54 // 'count_check_answer' => get_post_meta( $quiz->get_id(), '_lp_check_answer_count', true ),
55 // 'show_hint' => get_post_meta( $quiz->get_id(), '_lp_show_hint', true ),
56 // 'archive_history' => get_post_meta( $quiz->get_id(), '_lp_archive_history', true ),
57 // 'count_hint' => get_post_meta( $quiz->get_id(), '_lp_hint_count', true ),
58 'pagination' => get_post_meta( $quiz->get_id(), '_lp_pagination', true ),
59 'review_questions' => get_post_meta( $quiz->get_id(), '_lp_review', true ),
60 'show_correct_review' => get_post_meta( $quiz->get_id(), '_lp_show_correct_review', true ),
61 'preview' => get_post_meta( $quiz->get_id(), '_lp_preview', true ),
62 // 'minus_points' => get_post_meta( $quiz->get_id(), '_lp_minus_points', true ),
63 'minus_skip_questions' => get_post_meta( $quiz->get_id(), '_lp_minus_skip_questions', true ),
64
65 'instant_check' => get_post_meta( $quiz->get_id(), '_lp_instant_check', true ),
66 'negative_marking' => get_post_meta( $quiz->get_id(), '_lp_negative_marking', true ),
67 'retake_count' => get_post_meta( $quiz->get_id(), '_lp_retake_count', true ),
68 )
69 );
70
71 return $quiz;
72 }
73
74 /**
75 * Create quiz, with default meta.
76 *
77 * @param $args
78 *
79 * @return int|WP_Error
80 */
81 public function create( &$args ) {
82
83 $args = wp_parse_args(
84 $args,
85 array(
86 'id' => '',
87 'status' => 'publish',
88 'title' => __( 'New Quiz', 'learnpress' ),
89 'content' => '',
90 'author' => learn_press_get_current_user_id(),
91 )
92 );
93
94 $quiz_id = wp_insert_post(
95 array(
96 'ID' => $args['id'],
97 'post_type' => LP_QUIZ_CPT,
98 'post_status' => $args['status'],
99 'post_title' => $args['title'],
100 'post_content' => $args['content'],
101 'post_author' => $args['author'],
102 )
103 );
104
105 if ( $quiz_id ) {
106 // add default meta for new lesson
107 $default_meta = LP_Quiz::get_default_meta();
108
109 if ( is_array( $default_meta ) ) {
110 foreach ( $default_meta as $key => $value ) {
111 update_post_meta( $quiz_id, '_lp_' . $key, $value );
112 }
113 }
114 }
115
116 return $quiz_id;
117 }
118
119 public function update( &$quiz ) {
120 // TODO: Implement update() method.
121 }
122
123 /**
124 * Delete quiz.
125 *
126 * @since 3.0.0
127 *
128 * @param object $quiz_id
129 */
130 public function delete( &$quiz_id ) {
131 // course curd
132 $curd = new LP_Course_CURD();
133
134 // allow hook
135 do_action( 'learn-press/before-delete-quiz', $quiz_id );
136
137 // remove quiz from course items
138 $curd->remove_item( $quiz_id );
139 // remove questions from quiz
140 $this->remove_questions( $quiz_id, '', true );
141 }
142
143 /**
144 * Duplicate quiz.
145 *
146 * @since 3.0.0
147 *
148 * @param $quiz_id_origin
149 * @param array $args
150 *
151 * @return mixed|WP_Error
152 */
153 public function duplicate( &$quiz_id_origin, $args = array() ) {
154 $quiz_id_new = 0;
155
156 try {
157 if ( ! $quiz_id_origin ) {
158 return new WP_Error( 'lp/clone/quiz/id_null', 'Op! Quiz ID not found' );
159 }
160
161 if ( learn_press_get_post_type( $quiz_id_origin ) != LP_QUIZ_CPT ) {
162 return new WP_Error( 'lp/clone/quiz/type_invalid', 'Op! The quiz does not exist' );
163 }
164
165 // Ensure that user can create quiz
166 if ( ! current_user_can( 'edit_posts' ) ) {
167 return new WP_Error( 'lp/clone/quiz/permission', 'Sorry! You have not permission to duplicate this quiz' );
168 }
169
170 // Duplicate quiz
171 $quiz_id_new = learn_press_duplicate_post( $quiz_id_origin, $args, true );
172
173 if ( ! $quiz_id_new || is_wp_error( $quiz_id_new ) ) {
174 return new WP_Error( 'lp/clone/quiz/clone_error', 'Sorry! Failed to duplicate quiz!' );
175 } else {
176 // duplicate questions.
177 $this->duplicate_questions( $quiz_id_origin, $quiz_id_new );
178
179 do_action( 'learn-press/item/after-duplicate', $quiz_id_origin, $quiz_id_new, $args );
180 }
181 } catch ( Throwable $e ) {
182 error_log( $e->getMessage() );
183 }
184
185 return $quiz_id_new;
186 }
187
188 /**
189 * Duplicate questions.
190 *
191 * @param int $quiz_id_origin
192 * @param int $quiz_id_new
193 *
194 * @return void
195 */
196 public function duplicate_questions( int $quiz_id_origin, int $quiz_id_new ) {
197 $question_curd = new LP_Question_CURD();
198
199 try {
200 $quiz_origin = learn_press_get_quiz( $quiz_id_origin );
201 if ( ! $quiz_origin ) {
202 return;
203 }
204
205 $questions_origin = $quiz_origin->get_question_ids();
206
207 foreach ( $questions_origin as $question_id_origin ) {
208 $can_clone = true;
209 $args = compact( 'question_id_origin', 'quiz_origin', 'quiz_id_new' );
210 $can_clone = apply_filters( 'lp/quiz/question/can-clone', $can_clone, $args );
211
212 if ( ! $can_clone ) {
213 continue;
214 }
215
216 // duplicate question
217 $question_id_new = $question_curd->duplicate( $question_id_origin, array( 'post_status' => 'publish' ) );
218
219 if ( ! $question_id_new || is_wp_error( $question_id_new ) ) {
220 continue;
221 }
222
223 // add duplicate question to new quiz
224 $this->add_question( $quiz_id_new, $question_id_new );
225 }
226 } catch ( Throwable $e ) {
227 error_log( $e->getMessage() );
228 }
229 }
230
231 /**
232 * @param LP_Quiz $quiz
233 *
234 * @deprecated 4.1.7
235 */
236 /*protected function _load_questions( &$quiz ) {
237 $id = $quiz->get_id();
238 $questions = LP_Object_Cache::get( 'questions-' . $id, 'learn-press/quizzes' );
239
240 if ( false === $questions || $quiz->get_no_cache() ) {
241 $this->load_questions( $quiz->get_id() );
242 }
243 }*/
244
245 /**
246 * Read question of a quiz from database
247 *
248 * @param int $quiz_id
249 * @param string $context
250 *
251 * @return array|bool
252 */
253 /*public function read_questions( $quiz_id, $context = 'display' ) {
254 $quiz = learn_press_get_quiz( $quiz_id );
255
256 if ( ! $quiz ) {
257 return false;
258 }
259
260 return $quiz->get_question_ids( $context );
261 }*/
262
263 /**
264 * Read all question ids of a quiz.
265 *
266 * @param int $quiz_id
267 * @param string $context
268 *
269 * @return array
270 */
271 public function read_question_ids( int $quiz_id = 0, string $context = 'display' ): array {
272 $lp_question_db = LP_Question_DB::getInstance();
273 $question_ids = [];
274
275 try {
276 $quiz = learn_press_get_quiz( $quiz_id );
277 if ( ! $quiz ) {
278 return array();
279 }
280
281 if ( $context === 'display' ) {
282 $statuses = array( 'publish' );
283 } else {
284 $statuses = array( 'publish', 'draft', 'auto-draft' );
285 }
286
287 $filter = new LP_Question_Filter();
288 $filter->ID = $quiz_id;
289 $filter->post_status = $statuses;
290
291 $question_ids = $lp_question_db->get_list_question_ids_of_quiz( $filter );
292 } catch ( Throwable $e ) {
293 error_log( $e->getMessage() );
294 }
295
296 return $question_ids;
297 }
298
299 /**
300 * @deprecated 4.1.7
301 */
302 /*public function update_question_ids( $quiz_id ) {
303 wp_cache_delete( 'quiz-' . $quiz_id, 'quiz-questions' );
304
305 $quiz = learn_press_get_quiz( $quiz_id );
306
307 if ( $quiz ) {
308 $question_ids = $quiz->get_question_ids();
309 } else {
310 $question_ids = array();
311 }
312
313 update_post_meta( $quiz_id, '_questions', $question_ids );
314 update_post_meta( $quiz_id, '_question_count', sizeof( $question_ids ) );
315 }*/
316
317 /**
318 * Get quiz ids that contains a question.
319 *
320 * @since 3.1.0
321 *
322 * @param int $question_id
323 *
324 * @return array
325 */
326 public function get_quiz_by_question( $question_id ) {
327 global $wpdb;
328 $query = $wpdb->prepare(
329 "
330 SELECT ID
331 FROM {$wpdb->posts} p
332 INNER JOIN {$wpdb->learnpress_quiz_questions} qq ON qq.quiz_id = p.ID
333 WHERE qq.question_id = %d
334 ",
335 $question_id
336 );
337
338 return $wpdb->get_col( $query );
339 }
340
341 public function load_questions( $quiz_id ) {
342
343 global $wpdb;
344
345 if ( is_array( $quiz_id ) ) {
346 foreach ( $quiz_id as $q_id ) {
347 $this->load_questions( $q_id );
348 }
349
350 return;
351 }
352
353 $query = $wpdb->prepare(
354 "
355 SELECT ID, post_title, post_content, post_status, post_type, post_author, post_date, post_name
356 FROM {$wpdb->posts} p
357 INNER JOIN {$wpdb->prefix}learnpress_quiz_questions qq ON p.ID = qq.question_id
358 WHERE qq.quiz_id = %d
359 AND p.post_status = %s
360 ORDER BY question_order, quiz_question_id ASC
361 ",
362 $quiz_id,
363 'publish'
364 );
365
366 $question_ids = array();
367 $results = $wpdb->get_results( $query );
368
369 if ( $results ) {
370 foreach ( $results as $k => $v ) {
371 settype( $v, 'object' );
372 wp_cache_set( $v->ID, $v, 'posts' );
373
374 $question_ids[] = $v->ID;
375 }
376 }
377
378 LP_Object_Cache::set( 'questions-' . $quiz_id, $question_ids, 'learn-press/quizzes' );
379
380 // LP_Helper_CURD::cache_posts( $question_ids );
381 $question_factory = new LP_Question_CURD();
382 $question_factory->load_answer_options( $question_ids );
383 }
384
385 /**
386 * Sort questions by order.
387 * Check in an array of questions if there is a key 'order'.
388 *
389 * @param $questions
390 *
391 * @return mixed
392 */
393 protected function _maybe_sort_questions( &$questions ) {
394 if ( ! $questions ) {
395 return $questions;
396 }
397
398 $first = reset( $questions );
399
400 if ( empty( $first['order'] ) ) {
401 return $questions;
402 }
403
404 uasort( $questions, array( $this, '_callback_sort_questions' ) );
405
406 return $questions;
407 }
408
409 public function _callback_sort_questions( $a, $b ) {
410 return $a['order'] > $b['order'];
411 }
412
413 /**
414 * Reorder question by indexed number.
415 *
416 * @param LP_Quiz|WP_Post|int $the_quiz
417 * @param mixed $questions
418 *
419 * @return mixed
420 */
421 public function reorder_questions( $the_quiz, $questions = false ) {
422 global $wpdb;
423
424 $the_quiz = learn_press_get_quiz( $the_quiz );
425
426 if ( ! $the_quiz ) {
427 return false;
428 }
429
430 if ( false == $questions ) {
431 $query = $wpdb->prepare(
432 "
433 SELECT quiz_question_id as id
434 FROM {$wpdb->prefix}learnpress_quiz_questions
435 WHERE quiz_id = %d
436 ORDER BY question_order ASC
437 ",
438 $the_quiz->get_id()
439 );
440
441 $rows = $wpdb->get_results( $query );
442
443 if ( $rows ) {
444 $update = array();
445 $ids = wp_list_pluck( $rows, 'id' );
446 $format = array_fill( 0, sizeof( $ids ), '%d' );
447
448 foreach ( $rows as $order => $row ) {
449 $update[] = $wpdb->prepare( 'WHEN quiz_question_id = %d THEN %d', $row->id, $order + 1 );
450 }
451
452 $query = $wpdb->prepare(
453 "
454 UPDATE {$wpdb->prefix}learnpress_quiz_questions
455 SET question_order = CASE
456 " . join( "\n", $update ) . '
457 ELSE question_order END
458 WHERE quiz_question_id IN(' . join( ',', $format ) . ')
459 ',
460 $ids
461 );
462
463 return $wpdb->query( $query );
464 }
465 } else {
466 $query = "
467 UPDATE {$wpdb->learnpress_quiz_questions}
468 SET question_order = CASE
469 ";
470 for ( $order = 0, $n = sizeof( $questions ); $order < $n; $order ++ ) {
471 $query .= $wpdb->prepare( 'WHEN question_id = %d THEN %d', $questions[ $order ], $order + 1 ) . "\n";
472 }
473 $query .= sprintf( 'ELSE question_order END WHERE quiz_id = %d', $the_quiz->get_id() );
474
475 return $wpdb->query( $query );
476 }
477
478 return false;
479 }
480
481
482 /**
483 * Get all questions in a quiz
484 *
485 * @param LP_Quiz $the_quiz
486 *
487 * @return array|mixed
488 */
489 public function get_questions( $the_quiz ) {
490 $the_quiz = learn_press_get_quiz( $the_quiz );
491
492 if ( ! $the_quiz ) {
493 return $this->get_error( 'QUIZ_NOT_EXISTS' );
494 }
495
496 return LP_Object_Cache::get( 'questions-' . $the_quiz->get_id(), 'learn-press/quizzes' );
497 }
498
499 /**
500 * Add existing question into quiz.
501 *
502 * @param LP_Quiz|int $the_quiz
503 * @param $question_id
504 * @param array $args
505 *
506 * @return mixed false on failed
507 */
508 public function add_question( $the_quiz, $question_id, $args = array() ) {
509 $the_quiz = learn_press_get_quiz( $the_quiz );
510
511 if ( ! $the_quiz ) {
512 return $this->get_error( 'QUIZ_NOT_EXISTS' );
513 }
514
515 $question = learn_press_get_question( $question_id );
516
517 if ( ! $question ) {
518 return false;
519 }
520
521 if ( $this->is_exists_question( $the_quiz->get_id(), $question_id ) ) {
522 return false;
523 }
524
525 // list exist quiz question
526 //$list_questions = $this->get_questions( $the_quiz );
527 // add new question and set to cache
528 //$list_questions[ $question_id ] = strval( $question_id );
529 //LP_Object_Cache::set( 'questions-' . $the_quiz->get_id(), $list_questions, 'learn-press/quizzes' );
530
531 global $wpdb;
532
533 $id = $the_quiz->get_id();
534 $args = wp_parse_args( $args, array( 'order' => - 1 ) );
535
536 if ( $args['order'] >= 0 ) {
537 $query = $wpdb->prepare(
538 "
539 UPDATE {$wpdb->prefix}learnpress_quiz_questions
540 SET question_order = question_order + 1
541 WHERE quiz_id = %d AND question_order >= %d
542 ",
543 $id,
544 $args['order']
545 );
546 $wpdb->get_results( $query );
547 } else {
548 $query = $wpdb->prepare(
549 "
550 SELECT max(question_order) + 1 as ordering
551 FROM {$wpdb->prefix}learnpress_quiz_questions
552 WHERE quiz_id = %d
553 ",
554 $id
555 );
556
557 $order = $wpdb->get_var( $query );
558
559 if ( ! $order ) {
560 $order = 1;
561 }
562
563 $args['order'] = $order;
564 }
565
566 $inserted = $wpdb->insert(
567 $wpdb->prefix . 'learnpress_quiz_questions',
568 array(
569 'quiz_id' => $id,
570 'question_id' => $question_id,
571 'question_order' => $args['order'],
572 ),
573 array( '%d', '%d', '%d' )
574 );
575
576 $return = $inserted ? $wpdb->insert_id : $inserted;
577
578 do_action( 'learn-press/quiz-added-question', $inserted, $question_id, $the_quiz->get_id() );
579
580 return $return;
581 }
582
583 /**
584 * Check if a question (or batch of questions) is already added to quiz.
585 *
586 * @param int $the_id
587 * @param int|array $ids
588 *
589 * @return array|bool|null|object
590 */
591 public function is_exists_question( $the_id, $ids ) {
592 global $wpdb;
593
594 settype( $ids, 'array' );
595 $format = array_fill( 0, sizeof( $ids ), '%d' );
596
597 $questions_ids = implode( ', ', $ids );
598
599 $query = $wpdb->prepare(
600 "
601 SELECT quiz_question_id
602 FROM {$wpdb->learnpress_quiz_questions}
603 WHERE question_id IN( " . join( ',', $format ) . ' )
604 AND quiz_id = %d
605 ',
606 $questions_ids,
607 $the_id
608 );
609
610 $results = $wpdb->get_results( $query );
611
612 if ( $results ) {
613 return $results;
614 }
615
616 return false;
617 }
618
619 /**
620 * Update order question in quiz.
621 *
622 * @param $order
623 *
624 * @return false|int
625 */
626 public function sort_questions( $order ) {
627 global $wpdb;
628
629 foreach ( $order as $index => $question_id ) {
630 $update = $wpdb->update(
631 $wpdb->learnpress_quiz_questions,
632 array( 'question_order' => $index + 1 ),
633 array( 'question_id' => $question_id ),
634 array( '%d' ),
635 array( '%d' )
636 );
637
638 if ( $update === false ) {
639 return false;
640 }
641 }
642
643 return true;
644 }
645
646 /**
647 * Remove question from quiz.
648 *
649 * @since 3.0.0
650 *
651 * @param $quiz_id
652 * @param $question_id
653 * @param bool $force | remove all questions from quiz
654 *
655 * @return bool|false|int|WP_Error
656 */
657 public function remove_questions( $quiz_id, $question_id, $force = false ) {
658 $quiz = learn_press_get_quiz( $quiz_id );
659
660 if ( ! $quiz ) {
661 return $this->get_error( 'QUIZ_NOT_EXISTS' );
662 }
663
664 global $wpdb;
665
666 if ( $force ) {
667 // remove all questions from quiz
668 $delete = $wpdb->delete(
669 $wpdb->prefix . 'learnpress_quiz_questions',
670 array( 'quiz_id' => $quiz_id ),
671 array( '%d' )
672 );
673 } else {
674 do_action( 'learn-press/delete-quiz-question', $question_id, $quiz_id );
675
676 // remove question from quiz
677 $delete = $wpdb->delete(
678 $wpdb->prefix . 'learnpress_quiz_questions',
679 array(
680 'quiz_id' => $quiz_id,
681 'question_id' => $question_id,
682 ),
683 array( '%d', '%d' )
684 );
685
686 do_action( 'learn-press/deleted-quiz-question', $question_id, $quiz_id, $delete );
687
688 // reorder questions
689 $this->reorder_questions( $quiz );
690 }
691
692 // increment quiz questions
693 learn_press_reset_auto_increment( 'learnpress_quiz_questions' );
694
695 return $delete;
696 }
697
698 /**
699 * Update order quiz question answers.
700 *
701 * @since 3.0.0
702 *
703 * @param $answers
704 *
705 * @return array
706 */
707 public function sort_question_answers( $answers ) {
708 global $wpdb;
709
710 $orders = array();
711
712 foreach ( $answers as $index => $answer_id ) {
713 $order = $index + 1;
714
715 $orders[ $answer_id ] = $order;
716
717 $wpdb->update(
718 $wpdb->learnpress_question_answers,
719 array( 'order' => $order ),
720 array( 'question_answer_id' => $answer_id )
721 );
722 }
723
724 return $orders;
725 }
726
727 public function add_meta( &$object, $meta ) {
728 // TODO: Implement add_meta() method.
729 }
730
731 public function delete_meta( &$object, $meta ) {
732 // TODO: Implement delete_meta() method.
733 }
734
735 public function read_meta( &$object ) {
736 // TODO: Implement read_meta() method.
737 }
738
739 /**
740 * @param $object
741 * @param $meta
742 *
743 * @return mixed
744 */
745 public function update_meta( &$object, $meta ) {
746 return learn_press_update_user_item_meta( $object->get_user_item_id(), $meta->meta_key, $meta->meta_value );
747 }
748 }
749 }
750