PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.2
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.2
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.2, at inc/curds/class-lp-quiz-curd.php

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