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.1 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 All 141 releases
← All changes | inc/curds/class-lp-user-item-curd.php +725 -730 4.3.9 → 4.4.9 View file →
@@ -1,730 +1,725 @@
1 -<?php
2 -
3 -/**
4 - * Class LP_User_Item_CURD
5 - *
6 - * Class to manipulating user item with database.
7 - */
8 -class LP_User_Item_CURD implements LP_Interface_CURD {
9 - /**
10 - * Errors codes and message.
11 - *
12 - * @var array|bool
13 - */
14 - protected $_error_messages = false;
15 -
16 - /**
17 - * LP_User_Item_CURD constructor.
18 - */
19 - public function __construct() {
20 - $this->_error_messages = array(
21 - 'QUIZ_NOT_EXISTS' => __( 'The quiz does not exist.', 'learnpress' ),
22 - );
23 - }
24 -
25 - /**
26 - * @param LP_Quiz $quiz
27 - *
28 - * @return LP_Quiz|mixed
29 - * @throws Exception
30 - */
31 - public function load( &$quiz ) {
32 - $the_id = $quiz->get_id();
33 -
34 - if ( ! $the_id || LP_QUIZ_CPT !== learn_press_get_post_type( $the_id ) ) {
35 - throw new Exception( __( 'Invalid quiz.', 'learnpress' ) );
36 - }
37 -
38 - $quiz->set_data_via_methods(
39 - array(
40 - 'retake_count' => get_post_meta( $quiz->get_id(), '_lp_retake_count', true ),
41 - 'show_result' => get_post_meta( $quiz->get_id(), '_lp_show_result', true ),
42 - 'passing_grade_type' => get_post_meta( $quiz->get_id(), '_lp_passing_grade_type', true ),
43 - 'passing_grade' => get_post_meta( $quiz->get_id(), '_lp_passing_grade', true ),
44 - 'instant_check' => get_post_meta( $quiz->get_id(), '_lp_instant_check', true ),
45 - 'review_questions' => get_post_meta( $quiz->get_id(), '_lp_review', true ),
46 - )
47 - );
48 -
49 - $this->_load_questions( $quiz );
50 - // $this->_update_meta_cache( $quiz );
51 -
52 - return $quiz;
53 - }
54 -
55 - public function create( &$quiz ) {
56 - // TODO: Implement create() method.
57 - }
58 -
59 - public function update( &$quiz ) {
60 - // TODO: Implement update() method.
61 - }
62 -
63 - public function delete( &$quiz ) {
64 - // TODO: Implement delete() method.
65 - }
66 -
67 - public function duplicate( &$quiz, $args = array() ) {
68 - // TODO: Implement duplicate() method.
69 - }
70 -
71 - /**
72 - * @param LP_Quiz $quiz
73 - */
74 - protected function _load_questions( &$quiz ) {
75 - $id = $quiz->get_id();
76 - $questions = LP_Object_Cache::get( 'questions-' . $id, 'learn-press/quizzes' );
77 - if ( false === $questions ) {
78 - global $wpdb;
79 - $questions = array();
80 - $query = $wpdb->prepare(
81 - "
82 - SELECT p.*, qq.question_order AS `order`
83 - FROM {$wpdb->posts} p
84 - INNER JOIN {$wpdb->prefix}learnpress_quiz_questions qq ON p.ID = qq.question_id
85 - WHERE qq.quiz_id = %d
86 - AND p.post_status = %s
87 - ORDER BY question_order ASC
88 - ",
89 - $id,
90 - 'publish'
91 - );
92 -
93 - $results = $wpdb->get_results( $query, OBJECT_K );
94 -
95 - if ( $results ) {
96 - foreach ( $results as $k => $v ) {
97 - wp_cache_set( $v->ID, $v, 'posts' );
98 - $questions[ $v->ID ] = $v->ID;
99 - }
100 - }
101 - LP_Object_Cache::set( 'questions-' . $id, $questions, 'learn-press/quizzes' );
102 -
103 - $this->_load_question_answers( $quiz );
104 - }
105 - unset( $questions );
106 - }
107 -
108 - /**
109 - * @param LP_Quiz $quiz
110 - *
111 - * @deprecated 4.1.6.4
112 - */
113 - protected function _update_meta_cache( &$quiz ) {
114 - _deprecated_function( __FUNCTION__, '4.1.6.4' );
115 - $meta_ids = LP_Object_Cache::get( 'questions-' . $quiz->get_id(), 'learn-press/quizzes' );
116 -
117 - if ( false === $meta_ids ) {
118 - $meta_ids = array( $quiz->get_id() );
119 - } else {
120 - $meta_ids[] = $quiz->get_id();
121 - }
122 -
123 - // LP_Helper_CURD::update_meta_cache( $meta_ids );
124 - }
125 -
126 - /**
127 - * Load answer quiz's questions.
128 - */
129 - protected function _load_question_answers( &$quiz ) {
130 - global $wpdb;
131 -
132 - $questions = $this->get_questions( $quiz );
133 -
134 - if ( ! $questions ) {
135 - return;
136 - }
137 -
138 - $format = array_fill( 0, sizeof( $questions ), '%d' );
139 - $query = $wpdb->prepare(
140 - "
141 - SELECT *
142 - FROM {$wpdb->prefix}learnpress_question_answers
143 - WHERE question_id IN(" . join( ',', $format ) . ')
144 - ORDER BY question_id, `order` ASC
145 - ',
146 - $questions
147 - );
148 -
149 - $results = $wpdb->get_results( $query, OBJECT_K );
150 -
151 - if ( $results ) {
152 - $answer_options = array();
153 - $meta_ids = array();
154 - $group = 0;
155 - foreach ( $results as $k => $v ) {
156 - if ( empty( $answer_options[ $v->question_id ] ) ) {
157 - $answer_options[ $v->question_id ] = array();
158 - }
159 - $v = (array) $v;
160 -
161 - $answer_options[ $v['question_id'] ][] = $v;
162 - }
163 -
164 - foreach ( $answer_options as $question_id => $options ) {
165 - LP_Object_Cache::set( 'answer-options-' . $question_id, $options, 'learn-press/questions' );
166 - }
167 -
168 - foreach ( $meta_ids as $meta_id ) {
169 - // $this->_load_question_answer_meta( $meta_id );
170 - }
171 -
172 - $fetched = array_keys( $answer_options );
173 - $un_fetched = array_diff( $questions, $fetched );
174 - // $this->_load_question_answer_meta( $answer_options );
175 - } else {
176 - $un_fetched = $questions;
177 - }
178 -
179 - if ( $un_fetched ) {
180 - foreach ( $un_fetched as $question_id ) {
181 - LP_Object_Cache::set( 'answer-options-' . $question_id, array(), 'learn-press/questions' );
182 - }
183 - }
184 -
185 - }
186 -
187 - protected function _load_question_answer_meta( $meta_ids ) {
188 - global $wpdb;
189 -
190 - $format = array_fill( 0, sizeof( $meta_ids ), '%d' );
191 - $query = $wpdb->prepare(
192 - "
193 - SELECT *
194 - FROM {$wpdb->learnpress_question_answermeta}
195 - WHERE learnpress_question_answer_id IN(" . join( ',', $format ) . ')
196 - ',
197 - $meta_ids
198 - );
199 -
200 - $metas = $wpdb->get_results( $query );
201 -
202 - if ( $metas ) {
203 - foreach ( $metas as $meta ) {
204 - $key = $meta->meta_key;
205 - $option_key = $meta->learnpress_question_answer_id;
206 -
207 - if ( ! empty( $answer_options[ $option_key ] ) ) {
208 - if ( $key == 'checked' ) {
209 - $key = 'is_true';
210 - }
211 -
212 - $answer_options[ $option_key ][ $key ] = $meta->meta_value;
213 - }
214 - }
215 - }
216 - }
217 -
218 - /**
219 - * Sort questions by order.
220 - * Check in an array of questions if there is a key 'order'.
221 - *
222 - * @param $questions
223 - *
224 - * @return mixed
225 - */
226 - protected function _maybe_sort_questions( &$questions ) {
227 - if ( ! $questions ) {
228 - return $questions;
229 - }
230 -
231 - $first = reset( $questions );
232 -
233 - if ( empty( $first['order'] ) ) {
234 - return $questions;
235 - }
236 -
237 - uasort( $questions, array( $this, '_callback_sort_questions' ) );
238 -
239 - return $questions;
240 - }
241 -
242 - public function _callback_sort_questions( $a, $b ) {
243 - return $a['order'] > $b['order'];
244 - }
245 -
246 - /**
247 - * Reorder question by indexed number.
248 - *
249 - * @param LP_Quiz|WP_Post|int $the_quiz
250 - * @param mixed $questions
251 - *
252 - * @return mixed
253 - */
254 - public function reorder_questions( $the_quiz, $questions = false ) {
255 - global $wpdb;
256 -
257 - $the_quiz = learn_press_get_quiz( $the_quiz );
258 -
259 - if ( ! $the_quiz ) {
260 - return false;
261 - }
262 -
263 - if ( false == $questions ) {
264 - $query = $wpdb->prepare(
265 - "
266 - SELECT quiz_question_id as id
267 - FROM {$wpdb->prefix}learnpress_quiz_questions
268 - WHERE quiz_id = %d
269 - ORDER BY question_order ASC
270 - ",
271 - $the_quiz->get_id()
272 - );
273 -
274 - $rows = $wpdb->get_results( $query );
275 -
276 - if ( $rows ) {
277 - $update = array();
278 - $ids = wp_list_pluck( $rows, 'id' );
279 - $format = array_fill( 0, sizeof( $ids ), '%d' );
280 -
281 - foreach ( $rows as $order => $row ) {
282 - $update[] = $wpdb->prepare( 'WHEN quiz_question_id = %d THEN %d', $row->id, $order + 1 );
283 - }
284 -
285 - $query = $wpdb->prepare(
286 - "
287 - UPDATE {$wpdb->prefix}learnpress_quiz_questions
288 - SET question_order = CASE
289 - " . join( "\n", $update ) . '
290 - ELSE question_order END
291 - WHERE quiz_question_id IN(' . join( ',', $format ) . ')
292 - ',
293 - $ids
294 - );
295 -
296 - return $wpdb->query( $query );
297 - }
298 - } else {
299 - $query = "
300 - UPDATE {$wpdb->learnpress_quiz_questions}
301 - SET question_order = CASE
302 - ";
303 -
304 - for ( $order = 0, $n = sizeof( $questions ); $order < $n; $order ++ ) {
305 - $query .= $wpdb->prepare( 'WHEN question_id = %d THEN %d', $questions[ $order ], $order + 1 ) . "\n";
306 - }
307 -
308 - $query .= sprintf( 'ELSE question_order END WHERE quiz_id = %d', $the_quiz->get_id() );
309 -
310 - return $wpdb->query( $query );
311 - }
312 -
313 - return false;
314 - }
315 -
316 - /**
317 - * Get all questions in a quiz
318 - *
319 - * @param LP_Quiz $the_quiz
320 - *
321 - * @return array|mixed
322 - */
323 - public function get_questions( $the_quiz ) {
324 - $the_quiz = learn_press_get_quiz( $the_quiz );
325 -
326 - if ( ! $the_quiz ) {
327 - return $this->get_error( 'QUESTION_NOT_EXISTS' );
328 - }
329 -
330 - return LP_Object_Cache::get( 'questions-' . $the_quiz->get_id(), 'learn-press/quizzes' );
331 - }
332 -
333 - /**
334 - * Add existing question into quiz.
335 - *
336 - * @param LP_Quiz|int $the_quiz
337 - * @param $question_id
338 - * @param array $args
339 - *
340 - * @return mixed false on failed
341 - */
342 - public function add_question( $the_quiz, $question_id, $args = array() ) {
343 - $the_quiz = learn_press_get_quiz( $the_quiz );
344 -
345 - if ( ! $the_quiz ) {
346 - return $this->get_error( 'QUESTION_NOT_EXISTS' );
347 - }
348 -
349 - $question = learn_press_get_question( $question_id );
350 -
351 - if ( ! $question ) {
352 - return false;
353 - }
354 -
355 - if ( $this->is_exists_question( $question_id ) ) {
356 - return false;
357 - }
358 -
359 - global $wpdb;
360 -
361 - $id = $the_quiz->get_id();
362 - $args = wp_parse_args( $args, array( 'order' => - 1 ) );
363 - $this->reorder_questions( $the_quiz );
364 -
365 - if ( $args['order'] >= 0 ) {
366 - $query = $wpdb->prepare(
367 - "
368 - UPDATE {$wpdb->prefix}learnpress_quiz_questions
369 - SET question_order = question_order + 1
370 - WHERE quiz_id = %d AND question_order >= %d
371 - ",
372 - $id,
373 - $args['order']
374 - );
375 - $wpdb->get_results( $query );
376 - } else {
377 - $query = $wpdb->prepare(
378 - "
379 - SELECT max(question_order) + 1 as ordering
380 - FROM {$wpdb->prefix}learnpress_quiz_questions
381 - WHERE quiz_id = %d
382 - ",
383 - $id
384 - );
385 -
386 - $order = $wpdb->get_var( $query );
387 -
388 - if ( ! $order ) {
389 - $order = 1;
390 - }
391 -
392 - $args['order'] = $order;
393 - }
394 - $inserted = $wpdb->insert(
395 - $wpdb->prefix . 'learnpress_quiz_questions',
396 - array(
397 - 'quiz_id' => $id,
398 - 'question_id' => $question_id,
399 - 'question_order' => $args['order'],
400 - ),
401 - array( '%d', '%d', '%d' )
402 - );
403 -
404 - return $inserted ? $wpdb->insert_id : $inserted;
405 - }
406 -
407 - /**
408 - * Check if a question (or batch of questions) is already added to quiz.
409 - *
410 - * @param int $the_id
411 - * @param int|array $ids
412 - *
413 - * @return array|bool|null|object
414 - */
415 - public function is_exists_question( $the_id, $ids = array() ) {
416 - global $wpdb;
417 -
418 - settype( $ids, 'array' );
419 - $format = array_fill( 0, sizeof( $ids ), '%d' );
420 - $args = $ids;
421 - $args[] = $the_id;
422 - $query = $wpdb->prepare(
423 - "
424 - SELECT quiz_question_id
425 - FROM {$wpdb->learnpress_quiz_questions}
426 - WHERE question_id IN( " . join( ',', $format ) . ' )
427 - AND quiz_id = %d
428 - ',
429 - $args
430 - );
431 -
432 - $results = $wpdb->get_results( $query );
433 -
434 - if ( $results ) {
435 - return $results;
436 - }
437 -
438 - return false;
439 - }
440 -
441 - public function add_meta( &$object, $meta ) {
442 - // TODO: Implement add_meta() method.
443 - }
444 -
445 - public function delete_meta( &$object, $meta ) {
446 - // TODO: Implement delete_meta() method.
447 - }
448 -
449 - public function read_meta( &$object ) {
450 - // TODO: Implement read_meta() method.
451 - }
452 -
453 - /**
454 - * @param $object
455 - * @param $meta
456 - *
457 - * @return mixed
458 - */
459 - public function update_meta( &$object, $meta ) {
460 - return learn_press_update_user_item_meta( $object->get_user_item_id(), $meta->meta_key, $meta->meta_value );
461 - }
462 -
463 - /**
464 - * Get single user item by values of fields.
465 - *
466 - * @param string|array $field
467 - * @param string $value
468 - *
469 - * @return mixed
470 - * @since 3.1.0
471 - * @deprecated 4.2.5
472 - */
473 - public function get_item_by( $field, $value = '' ) {
474 - _deprecated_function( __METHOD__, '4.2.5' );
475 - if ( $rows = $this->get_items_by( $field, $value ) ) {
476 - return $rows[0];
477 - }
478 -
479 - return false;
480 - }
481 -
482 - /**
483 - * Get multiple rows of user item by values of fields.
484 - *
485 - * @param string|array $field
486 - * @param string $value
487 - *
488 - * @return array
489 - * @since 3.1.0
490 - * @deprecated 4.2.5
491 - */
492 - public function get_items_by( $field, $value = '' ) {
493 - _deprecated_function( __METHOD__, '4.2.5' );
494 - global $wpdb;
495 -
496 - $where = '';
497 - $order = 'ORDER BY user_item_id DESC';
498 -
499 - if ( is_array( $field ) ) {
500 - foreach ( $field as $k => $v ) {
501 - if ( is_string( $v ) ) {
502 - $where .= $wpdb->prepare( " AND {$k} = %s", $v );
503 - } else {
504 - $where .= $wpdb->prepare( " AND {$k} = %d", $v );
505 - }
506 - }
507 - } else {
508 - if ( is_string( $value ) ) {
509 - $where .= $wpdb->prepare( " AND {$field} = %s", $value );
510 - } else {
511 - $where .= $wpdb->prepare( " AND {$field} = %s", $value );
512 - }
513 - }
514 -
515 - $query = "SELECT * FROM {$wpdb->learnpress_user_items} WHERE 1 {$where} {$order}";
516 -
517 - return $wpdb->get_results( $query );
518 - }
519 -
520 - /**
521 - * Get WP_Object.
522 - *
523 - * @param $code
524 - *
525 - * @return bool|WP_Error
526 - */
527 - protected function get_error( $code ) {
528 - if ( isset( $this->_error_messages[ $code ] ) ) {
529 - return new WP_Error( $code, $this->_error_messages[ $code ] );
530 - }
531 -
532 - return false;
533 - }
534 -
535 - /**
536 - * Parse attribute 'preview' for all items in a course
537 - *
538 - * @param int $course_id
539 - * @param int $user_id
540 - *
541 - * @return array
542 - * @since 3.2.0
543 - * @editor tungnx
544 - * @modify 4.1.3 - comment - not use
545 - */
546 - /*public function parse_items_preview( $course_id, $user_id = 0 ) {
547 - $items = array();
548 -
549 - $course = learn_press_get_course( $course_id );
550 -
551 - if ( ! $course ) {
552 - return $items;
553 - }
554 -
555 - if ( ! $user_id ) {
556 - $user_id = get_current_user_id();
557 - }
558 -
559 - $user = learn_press_get_user( $user_id, false );
560 - $current_item = LP_Global::course_item();
561 - $get_item_ids = $course->get_item_ids();
562 - $enrolled = $user ? $user->has_enrolled_course( $course_id ) : false;
563 -
564 - if ( $get_item_ids ) {
565 - foreach ( $get_item_ids as $item_id ) {
566 - $is_preview = get_post_meta( $item_id, '_lp_preview', true );
567 -
568 - if ( $enrolled ) {
569 - $is_preview = 'no';
570 - }
571 -
572 - $cached = LP_Object_Cache::get(
573 - 'item-' . $user_id . '-' . $course_id . '-' . $item_id,
574 - 'learn-press/preview-items'
575 - );
576 -
577 - if ( false === $cached ) {
578 - LP_Object_Cache::set(
579 - 'item-' . $user_id . '-' . $course->get_id() . '-' . $item_id,
580 - $is_preview,
581 - 'learn-press/preview-items'
582 - );
583 - }
584 -
585 - $items[ $item_id ] = $is_preview;
586 - }
587 - }
588 -
589 - return $items;
590 - }*/
591 -
592 - /**
593 - * Parse classes for all items in a course.
594 - *
595 - * @param int $course_id .
596 - * @param int $user_id .
597 - * @param array|string $more .
598 - *
599 - * @return array
600 - * @throws Exception
601 - * @since 3.2.0
602 - * @editor tungnx
603 - */
604 - public function parse_items_classes( int $course_id = 0, int $user_id = 0, $more = array() ): array {
605 - $items = array();
606 -
607 - $course = learn_press_get_course( $course_id );
608 -
609 - if ( ! $course ) {
610 - return $items;
611 - }
612 -
613 - if ( ! $user_id ) {
614 - $user_id = get_current_user_id();
615 - }
616 -
617 - $get_item_ids = $course->get_item_ids();
618 -
619 - if ( empty( $get_item_ids ) ) {
620 - return $items;
621 - }
622 -
623 - $user = learn_press_get_user( $user_id );
624 - if ( ! $user ) {
625 - return $items;
626 - }
627 -
628 - $current_item = LP_Global::course_item();
629 - $enrolled = $user->has_enrolled_or_finished( $course_id );
630 - $is_free = $course->is_free();
631 - $no_required_enroll = $course->is_no_required_enroll();
632 - $can_view_content_course = $user->can_view_content_course( $course_id );
633 -
634 - foreach ( $get_item_ids as $item_id ) {
635 - $item = $course->get_item( $item_id );
636 -
637 - if ( ! $item instanceof LP_Course_Item ) {
638 - continue;
639 - }
640 -
641 - $can_view_item = $user->can_view_item( $item_id, $can_view_content_course );
642 -
643 - $defaults = array_merge(
644 - array(
645 - 'course-item',
646 - 'course-item-' . $item->get_item_type(),
647 - 'course-item-' . $item_id,
648 - ),
649 - (array) $more
650 - );
651 -
652 - $post_format = $item->get_format();
653 - if ( ( 'standard' !== $post_format ) && $post_format ) {
654 - $defaults[] = 'course-item-type-' . $post_format;
655 - }
656 -
657 - if ( $current_item && $current_item->get_id() == $item->get_id() ) {
658 - $defaults[] = 'current';
659 - }
660 -
661 - // Edit by tungnx, rewrite class to show icon.
662 - if ( $no_required_enroll ) {
663 - $defaults[] = 'item-free';
664 - } elseif ( ! $enrolled ) {
665 - $defaults['item-locked'] = 'item-locked';
666 -
667 - if ( $item->is_preview() ) {
668 - $defaults['item-preview'] = 'item-preview';
669 - $defaults['has-status'] = 'has-status';
670 - unset( $defaults['item-locked'] );
671 - }
672 - } elseif ( ! $can_view_item->flag ) {
673 - $defaults[] = 'item-locked';
674 - } else {
675 - $item_status = $user->get_item_status( $item_id, $course_id );
676 - $item_grade = $user->get_item_grade( $item_id, $course_id );
677 -
678 - if ( $item_status ) {
679 - $defaults[] = 'has-status';
680 - $defaults[] = 'status-' . $item_status;
681 - }
682 -
683 - switch ( $item_status ) {
684 - case 'started':
685 - break;
686 - case 'completed':
687 - $defaults[] = $item_grade;
688 - break;
689 - default:
690 - if ( $item->is_preview() ) {
691 - $defaults['item-preview'] = 'item-preview';
692 - $defaults['has-status'] = 'has-status';
693 - }
694 -
695 - $item_class = apply_filters(
696 - 'learn-press/course-item-status-class',
697 - $item_status,
698 - $item_grade,
699 - $item->get_item_type(),
700 - $item_id,
701 - $course_id
702 - );
703 -
704 - if ( $item_class ) {
705 - $defaults[] = $item_class;
706 - }
707 - }
708 - }
709 - // End.
710 -
711 - $classes = apply_filters(
712 - 'learn-press/course-item-class',
713 - $defaults,
714 - $item->get_item_type(),
715 - $item_id,
716 - $course_id
717 - );
718 -
719 - // Filter unwanted values.
720 - $classes = is_array( $classes ) ? $classes : explode( ' ', $classes );
721 - $classes = array_filter( $classes );
722 - $classes = array_unique( $classes );
723 -
724 - LP_Object_Cache::set( 'item-' . $user_id . '-' . $item_id, $classes, 'learn-press/post-classes' );
725 - $items[ $item_id ] = $classes;
726 - }
727 -
728 - return $items;
729 - }
730 -}
1 +<?php
2 +
3 +/**
4 + * Class LP_User_Item_CURD
5 + *
6 + * Class to manipulating user item with database.
7 + */
8 +class LP_User_Item_CURD implements LP_Interface_CURD {
9 + /**
10 + * Errors codes and message.
11 + *
12 + * @var array|bool
13 + */
14 + protected $_error_messages = false;
15 +
16 + /**
17 + * LP_User_Item_CURD constructor.
18 + */
19 + public function __construct() {
20 + $this->_error_messages = array(
21 + 'QUIZ_NOT_EXISTS' => __( 'The quiz does not exist.', 'learnpress' ),
22 + );
23 + }
24 +
25 + /**
26 + * @param LP_Quiz $quiz
27 + *
28 + * @return LP_Quiz|mixed
29 + * @throws Exception
30 + */
31 + public function load( &$quiz ) {
32 + $the_id = $quiz->get_id();
33 +
34 + if ( ! $the_id || LP_QUIZ_CPT !== learn_press_get_post_type( $the_id ) ) {
35 + throw new Exception( __( 'Invalid quiz.', 'learnpress' ) );
36 + }
37 +
38 + $quiz->set_retake_count( get_post_meta( $quiz->get_id(), '_lp_retake_count', true ) );
39 + $quiz->set_passing_grade_type( get_post_meta( $quiz->get_id(), '_lp_passing_grade_type', true ) );
40 + $quiz->set_passing_grade( get_post_meta( $quiz->get_id(), '_lp_passing_grade', true ) );
41 + $quiz->set_instant_check( get_post_meta( $quiz->get_id(), '_lp_instant_check', true ) );
42 + $quiz->set_review_questions( get_post_meta( $quiz->get_id(), '_lp_review', true ) );
43 +
44 + $this->_load_questions( $quiz );
45 + // $this->_update_meta_cache( $quiz );
46 +
47 + return $quiz;
48 + }
49 +
50 + public function create( &$quiz ) {
51 + // TODO: Implement create() method.
52 + }
53 +
54 + public function update( &$quiz ) {
55 + // TODO: Implement update() method.
56 + }
57 +
58 + public function delete( &$quiz ) {
59 + // TODO: Implement delete() method.
60 + }
61 +
62 + public function duplicate( &$quiz, $args = array() ) {
63 + // TODO: Implement duplicate() method.
64 + }
65 +
66 + /**
67 + * @param LP_Quiz $quiz
68 + */
69 + protected function _load_questions( &$quiz ) {
70 + $id = $quiz->get_id();
71 + $questions = LP_Object_Cache::get( 'questions-' . $id, 'learn-press/quizzes' );
72 + if ( false === $questions ) {
73 + global $wpdb;
74 + $questions = array();
75 + $query = $wpdb->prepare(
76 + "
77 + SELECT p.*, qq.question_order AS `order`
78 + FROM {$wpdb->posts} p
79 + INNER JOIN {$wpdb->prefix}learnpress_quiz_questions qq ON p.ID = qq.question_id
80 + WHERE qq.quiz_id = %d
81 + AND p.post_status = %s
82 + ORDER BY question_order ASC
83 + ",
84 + $id,
85 + 'publish'
86 + );
87 +
88 + $results = $wpdb->get_results( $query, OBJECT_K );
89 +
90 + if ( $results ) {
91 + foreach ( $results as $k => $v ) {
92 + wp_cache_set( $v->ID, $v, 'posts' );
93 + $questions[ $v->ID ] = $v->ID;
94 + }
95 + }
96 + LP_Object_Cache::set( 'questions-' . $id, $questions, 'learn-press/quizzes' );
97 +
98 + $this->_load_question_answers( $quiz );
99 + }
100 + unset( $questions );
101 + }
102 +
103 + /**
104 + * @param LP_Quiz $quiz
105 + *
106 + * @deprecated 4.1.6.4
107 + */
108 + protected function _update_meta_cache( &$quiz ) {
109 + _deprecated_function( __FUNCTION__, '4.1.6.4' );
110 + $meta_ids = LP_Object_Cache::get( 'questions-' . $quiz->get_id(), 'learn-press/quizzes' );
111 +
112 + if ( false === $meta_ids ) {
113 + $meta_ids = array( $quiz->get_id() );
114 + } else {
115 + $meta_ids[] = $quiz->get_id();
116 + }
117 +
118 + // LP_Helper_CURD::update_meta_cache( $meta_ids );
119 + }
120 +
121 + /**
122 + * Load answer quiz's questions.
123 + */
124 + protected function _load_question_answers( &$quiz ) {
125 + global $wpdb;
126 +
127 + $questions = $this->get_questions( $quiz );
128 +
129 + if ( ! $questions ) {
130 + return;
131 + }
132 +
133 + $format = array_fill( 0, sizeof( $questions ), '%d' );
134 + $query = $wpdb->prepare(
135 + "
136 + SELECT *
137 + FROM {$wpdb->prefix}learnpress_question_answers
138 + WHERE question_id IN(" . join( ',', $format ) . ')
139 + ORDER BY question_id, `order` ASC
140 + ',
141 + $questions
142 + );
143 +
144 + $results = $wpdb->get_results( $query, OBJECT_K );
145 +
146 + if ( $results ) {
147 + $answer_options = array();
148 + $meta_ids = array();
149 + $group = 0;
150 + foreach ( $results as $k => $v ) {
151 + if ( empty( $answer_options[ $v->question_id ] ) ) {
152 + $answer_options[ $v->question_id ] = array();
153 + }
154 + $v = (array) $v;
155 +
156 + $answer_options[ $v['question_id'] ][] = $v;
157 + }
158 +
159 + foreach ( $answer_options as $question_id => $options ) {
160 + LP_Object_Cache::set( 'answer-options-' . $question_id, $options, 'learn-press/questions' );
161 + }
162 +
163 + foreach ( $meta_ids as $meta_id ) {
164 + // $this->_load_question_answer_meta( $meta_id );
165 + }
166 +
167 + $fetched = array_keys( $answer_options );
168 + $un_fetched = array_diff( $questions, $fetched );
169 + // $this->_load_question_answer_meta( $answer_options );
170 + } else {
171 + $un_fetched = $questions;
172 + }
173 +
174 + if ( $un_fetched ) {
175 + foreach ( $un_fetched as $question_id ) {
176 + LP_Object_Cache::set( 'answer-options-' . $question_id, array(), 'learn-press/questions' );
177 + }
178 + }
179 +
180 + }
181 +
182 + protected function _load_question_answer_meta( $meta_ids ) {
183 + global $wpdb;
184 +
185 + $format = array_fill( 0, sizeof( $meta_ids ), '%d' );
186 + $query = $wpdb->prepare(
187 + "
188 + SELECT *
189 + FROM {$wpdb->learnpress_question_answermeta}
190 + WHERE learnpress_question_answer_id IN(" . join( ',', $format ) . ')
191 + ',
192 + $meta_ids
193 + );
194 +
195 + $metas = $wpdb->get_results( $query );
196 +
197 + if ( $metas ) {
198 + foreach ( $metas as $meta ) {
199 + $key = $meta->meta_key;
200 + $option_key = $meta->learnpress_question_answer_id;
201 +
202 + if ( ! empty( $answer_options[ $option_key ] ) ) {
203 + if ( $key == 'checked' ) {
204 + $key = 'is_true';
205 + }
206 +
207 + $answer_options[ $option_key ][ $key ] = $meta->meta_value;
208 + }
209 + }
210 + }
211 + }
212 +
213 + /**
214 + * Sort questions by order.
215 + * Check in an array of questions if there is a key 'order'.
216 + *
217 + * @param $questions
218 + *
219 + * @return mixed
220 + */
221 + protected function _maybe_sort_questions( &$questions ) {
222 + if ( ! $questions ) {
223 + return $questions;
224 + }
225 +
226 + $first = reset( $questions );
227 +
228 + if ( empty( $first['order'] ) ) {
229 + return $questions;
230 + }
231 +
232 + uasort( $questions, array( $this, '_callback_sort_questions' ) );
233 +
234 + return $questions;
235 + }
236 +
237 + public function _callback_sort_questions( $a, $b ) {
238 + return $a['order'] > $b['order'];
239 + }
240 +
241 + /**
242 + * Reorder question by indexed number.
243 + *
244 + * @param LP_Quiz|WP_Post|int $the_quiz
245 + * @param mixed $questions
246 + *
247 + * @return mixed
248 + */
249 + public function reorder_questions( $the_quiz, $questions = false ) {
250 + global $wpdb;
251 +
252 + $the_quiz = learn_press_get_quiz( $the_quiz );
253 +
254 + if ( ! $the_quiz ) {
255 + return false;
256 + }
257 +
258 + if ( false == $questions ) {
259 + $query = $wpdb->prepare(
260 + "
261 + SELECT quiz_question_id as id
262 + FROM {$wpdb->prefix}learnpress_quiz_questions
263 + WHERE quiz_id = %d
264 + ORDER BY question_order ASC
265 + ",
266 + $the_quiz->get_id()
267 + );
268 +
269 + $rows = $wpdb->get_results( $query );
270 +
271 + if ( $rows ) {
272 + $update = array();
273 + $ids = wp_list_pluck( $rows, 'id' );
274 + $format = array_fill( 0, sizeof( $ids ), '%d' );
275 +
276 + foreach ( $rows as $order => $row ) {
277 + $update[] = $wpdb->prepare( 'WHEN quiz_question_id = %d THEN %d', $row->id, $order + 1 );
278 + }
279 +
280 + $query = $wpdb->prepare(
281 + "
282 + UPDATE {$wpdb->prefix}learnpress_quiz_questions
283 + SET question_order = CASE
284 + " . join( "\n", $update ) . '
285 + ELSE question_order END
286 + WHERE quiz_question_id IN(' . join( ',', $format ) . ')
287 + ',
288 + $ids
289 + );
290 +
291 + return $wpdb->query( $query );
292 + }
293 + } else {
294 + $query = "
295 + UPDATE {$wpdb->learnpress_quiz_questions}
296 + SET question_order = CASE
297 + ";
298 +
299 + for ( $order = 0, $n = sizeof( $questions ); $order < $n; $order ++ ) {
300 + $query .= $wpdb->prepare( 'WHEN question_id = %d THEN %d', $questions[ $order ], $order + 1 ) . "\n";
301 + }
302 +
303 + $query .= sprintf( 'ELSE question_order END WHERE quiz_id = %d', $the_quiz->get_id() );
304 +
305 + return $wpdb->query( $query );
306 + }
307 +
308 + return false;
309 + }
310 +
311 + /**
312 + * Get all questions in a quiz
313 + *
314 + * @param LP_Quiz $the_quiz
315 + *
316 + * @return array|mixed
317 + */
318 + public function get_questions( $the_quiz ) {
319 + $the_quiz = learn_press_get_quiz( $the_quiz );
320 +
321 + if ( ! $the_quiz ) {
322 + return $this->get_error( 'QUESTION_NOT_EXISTS' );
323 + }
324 +
325 + return LP_Object_Cache::get( 'questions-' . $the_quiz->get_id(), 'learn-press/quizzes' );
326 + }
327 +
328 + /**
329 + * Add existing question into quiz.
330 + *
331 + * @param LP_Quiz|int $the_quiz
332 + * @param $question_id
333 + * @param array $args
334 + *
335 + * @return mixed false on failed
336 + */
337 + public function add_question( $the_quiz, $question_id, $args = array() ) {
338 + $the_quiz = learn_press_get_quiz( $the_quiz );
339 +
340 + if ( ! $the_quiz ) {
341 + return $this->get_error( 'QUESTION_NOT_EXISTS' );
342 + }
343 +
344 + $question = learn_press_get_question( $question_id );
345 +
346 + if ( ! $question ) {
347 + return false;
348 + }
349 +
350 + if ( $this->is_exists_question( $question_id ) ) {
351 + return false;
352 + }
353 +
354 + global $wpdb;
355 +
356 + $id = $the_quiz->get_id();
357 + $args = wp_parse_args( $args, array( 'order' => - 1 ) );
358 + $this->reorder_questions( $the_quiz );
359 +
360 + if ( $args['order'] >= 0 ) {
361 + $query = $wpdb->prepare(
362 + "
363 + UPDATE {$wpdb->prefix}learnpress_quiz_questions
364 + SET question_order = question_order + 1
365 + WHERE quiz_id = %d AND question_order >= %d
366 + ",
367 + $id,
368 + $args['order']
369 + );
370 + $wpdb->get_results( $query );
371 + } else {
372 + $query = $wpdb->prepare(
373 + "
374 + SELECT max(question_order) + 1 as ordering
375 + FROM {$wpdb->prefix}learnpress_quiz_questions
376 + WHERE quiz_id = %d
377 + ",
378 + $id
379 + );
380 +
381 + $order = $wpdb->get_var( $query );
382 +
383 + if ( ! $order ) {
384 + $order = 1;
385 + }
386 +
387 + $args['order'] = $order;
388 + }
389 + $inserted = $wpdb->insert(
390 + $wpdb->prefix . 'learnpress_quiz_questions',
391 + array(
392 + 'quiz_id' => $id,
393 + 'question_id' => $question_id,
394 + 'question_order' => $args['order'],
395 + ),
396 + array( '%d', '%d', '%d' )
397 + );
398 +
399 + return $inserted ? $wpdb->insert_id : $inserted;
400 + }
401 +
402 + /**
403 + * Check if a question (or batch of questions) is already added to quiz.
404 + *
405 + * @param int $the_id
406 + * @param int|array $ids
407 + *
408 + * @return array|bool|null|object
409 + */
410 + public function is_exists_question( $the_id, $ids = array() ) {
411 + global $wpdb;
412 +
413 + settype( $ids, 'array' );
414 + $format = array_fill( 0, sizeof( $ids ), '%d' );
415 + $args = $ids;
416 + $args[] = $the_id;
417 + $query = $wpdb->prepare(
418 + "
419 + SELECT quiz_question_id
420 + FROM {$wpdb->learnpress_quiz_questions}
421 + WHERE question_id IN( " . join( ',', $format ) . ' )
422 + AND quiz_id = %d
423 + ',
424 + $args
425 + );
426 +
427 + $results = $wpdb->get_results( $query );
428 +
429 + if ( $results ) {
430 + return $results;
431 + }
432 +
433 + return false;
434 + }
435 +
436 + public function add_meta( &$object, $meta ) {
437 + // TODO: Implement add_meta() method.
438 + }
439 +
440 + public function delete_meta( &$object, $meta ) {
441 + // TODO: Implement delete_meta() method.
442 + }
443 +
444 + public function read_meta( &$object ) {
445 + // TODO: Implement read_meta() method.
446 + }
447 +
448 + /**
449 + * @param $object
450 + * @param $meta
451 + *
452 + * @return mixed
453 + */
454 + public function update_meta( &$object, $meta ) {
455 + return learn_press_update_user_item_meta( $object->get_user_item_id(), $meta->meta_key, $meta->meta_value );
456 + }
457 +
458 + /**
459 + * Get single user item by values of fields.
460 + *
461 + * @param string|array $field
462 + * @param string $value
463 + *
464 + * @return mixed
465 + * @since 3.1.0
466 + * @deprecated 4.2.5
467 + */
468 + public function get_item_by( $field, $value = '' ) {
469 + _deprecated_function( __METHOD__, '4.2.5' );
470 + if ( $rows = $this->get_items_by( $field, $value ) ) {
471 + return $rows[0];
472 + }
473 +
474 + return false;
475 + }
476 +
477 + /**
478 + * Get multiple rows of user item by values of fields.
479 + *
480 + * @param string|array $field
481 + * @param string $value
482 + *
483 + * @return array
484 + * @since 3.1.0
485 + * @deprecated 4.2.5
486 + */
487 + public function get_items_by( $field, $value = '' ) {
488 + _deprecated_function( __METHOD__, '4.2.5' );
489 + global $wpdb;
490 +
491 + $where = '';
492 + $order = 'ORDER BY user_item_id DESC';
493 +
494 + if ( is_array( $field ) ) {
495 + foreach ( $field as $k => $v ) {
496 + if ( is_string( $v ) ) {
497 + $where .= $wpdb->prepare( " AND {$k} = %s", $v );
498 + } else {
499 + $where .= $wpdb->prepare( " AND {$k} = %d", $v );
500 + }
501 + }
502 + } else {
503 + if ( is_string( $value ) ) {
504 + $where .= $wpdb->prepare( " AND {$field} = %s", $value );
505 + } else {
506 + $where .= $wpdb->prepare( " AND {$field} = %s", $value );
507 + }
508 + }
509 +
510 + $query = "SELECT * FROM {$wpdb->learnpress_user_items} WHERE 1 {$where} {$order}";
511 +
512 + return $wpdb->get_results( $query );
513 + }
514 +
515 + /**
516 + * Get WP_Object.
517 + *
518 + * @param $code
519 + *
520 + * @return bool|WP_Error
521 + */
522 + protected function get_error( $code ) {
523 + if ( isset( $this->_error_messages[ $code ] ) ) {
524 + return new WP_Error( $code, $this->_error_messages[ $code ] );
525 + }
526 +
527 + return false;
528 + }
529 +
530 + /**
531 + * Parse attribute 'preview' for all items in a course
532 + *
533 + * @param int $course_id
534 + * @param int $user_id
535 + *
536 + * @return array
537 + * @since 3.2.0
538 + * @editor tungnx
539 + * @modify 4.1.3 - comment - not use
540 + */
541 + /*public function parse_items_preview( $course_id, $user_id = 0 ) {
542 + $items = array();
543 +
544 + $course = learn_press_get_course( $course_id );
545 +
546 + if ( ! $course ) {
547 + return $items;
548 + }
549 +
550 + if ( ! $user_id ) {
551 + $user_id = get_current_user_id();
552 + }
553 +
554 + $user = learn_press_get_user( $user_id, false );
555 + $current_item = LP_Global::course_item();
556 + $get_item_ids = $course->get_item_ids();
557 + $enrolled = $user ? $user->has_enrolled_course( $course_id ) : false;
558 +
559 + if ( $get_item_ids ) {
560 + foreach ( $get_item_ids as $item_id ) {
561 + $is_preview = get_post_meta( $item_id, '_lp_preview', true );
562 +
563 + if ( $enrolled ) {
564 + $is_preview = 'no';
565 + }
566 +
567 + $cached = LP_Object_Cache::get(
568 + 'item-' . $user_id . '-' . $course_id . '-' . $item_id,
569 + 'learn-press/preview-items'
570 + );
571 +
572 + if ( false === $cached ) {
573 + LP_Object_Cache::set(
574 + 'item-' . $user_id . '-' . $course->get_id() . '-' . $item_id,
575 + $is_preview,
576 + 'learn-press/preview-items'
577 + );
578 + }
579 +
580 + $items[ $item_id ] = $is_preview;
581 + }
582 + }
583 +
584 + return $items;
585 + }*/
586 +
587 + /**
588 + * Parse classes for all items in a course.
589 + *
590 + * @param int $course_id .
591 + * @param int $user_id .
592 + * @param array|string $more .
593 + *
594 + * @return array
595 + * @throws Exception
596 + * @since 3.2.0
597 + * @editor tungnx
598 + */
599 + public function parse_items_classes( int $course_id = 0, int $user_id = 0, $more = array() ): array {
600 + $items = array();
601 +
602 + $course = learn_press_get_course( $course_id );
603 +
604 + if ( ! $course ) {
605 + return $items;
606 + }
607 +
608 + if ( ! $user_id ) {
609 + $user_id = get_current_user_id();
610 + }
611 +
612 + $get_item_ids = $course->get_item_ids();
613 +
614 + if ( empty( $get_item_ids ) ) {
615 + return $items;
616 + }
617 +
618 + $user = learn_press_get_user( $user_id );
619 + if ( ! $user ) {
620 + return $items;
621 + }
622 +
623 + $current_item = LP_Global::course_item();
624 + $enrolled = $user->has_enrolled_or_finished( $course_id );
625 + $is_free = $course->is_free();
626 + $no_required_enroll = $course->is_no_required_enroll();
627 + $can_view_content_course = $user->can_view_content_course( $course_id );
628 +
629 + foreach ( $get_item_ids as $item_id ) {
630 + $item = $course->get_item( $item_id );
631 +
632 + if ( ! $item instanceof LP_Course_Item ) {
633 + continue;
634 + }
635 +
636 + $can_view_item = $user->can_view_item( $item_id, $can_view_content_course );
637 +
638 + $defaults = array_merge(
639 + array(
640 + 'course-item',
641 + 'course-item-' . $item->get_item_type(),
642 + 'course-item-' . $item_id,
643 + ),
644 + (array) $more
645 + );
646 +
647 + $post_format = $item->get_format();
648 + if ( ( 'standard' !== $post_format ) && $post_format ) {
649 + $defaults[] = 'course-item-type-' . $post_format;
650 + }
651 +
652 + if ( $current_item && $current_item->get_id() == $item->get_id() ) {
653 + $defaults[] = 'current';
654 + }
655 +
656 + // Edit by tungnx, rewrite class to show icon.
657 + if ( $no_required_enroll ) {
658 + $defaults[] = 'item-free';
659 + } elseif ( ! $enrolled ) {
660 + $defaults['item-locked'] = 'item-locked';
661 +
662 + if ( $item->is_preview() ) {
663 + $defaults['item-preview'] = 'item-preview';
664 + $defaults['has-status'] = 'has-status';
665 + unset( $defaults['item-locked'] );
666 + }
667 + } elseif ( ! $can_view_item->flag ) {
668 + $defaults[] = 'item-locked';
669 + } else {
670 + $item_status = $user->get_item_status( $item_id, $course_id );
671 + $item_grade = $user->get_item_grade( $item_id, $course_id );
672 +
673 + if ( $item_status ) {
674 + $defaults[] = 'has-status';
675 + $defaults[] = 'status-' . $item_status;
676 + }
677 +
678 + switch ( $item_status ) {
679 + case 'started':
680 + break;
681 + case 'completed':
682 + $defaults[] = $item_grade;
683 + break;
684 + default:
685 + if ( $item->is_preview() ) {
686 + $defaults['item-preview'] = 'item-preview';
687 + $defaults['has-status'] = 'has-status';
688 + }
689 +
690 + $item_class = apply_filters(
691 + 'learn-press/course-item-status-class',
692 + $item_status,
693 + $item_grade,
694 + $item->get_item_type(),
695 + $item_id,
696 + $course_id
697 + );
698 +
699 + if ( $item_class ) {
700 + $defaults[] = $item_class;
701 + }
702 + }
703 + }
704 + // End.
705 +
706 + $classes = apply_filters(
707 + 'learn-press/course-item-class',
708 + $defaults,
709 + $item->get_item_type(),
710 + $item_id,
711 + $course_id
712 + );
713 +
714 + // Filter unwanted values.
715 + $classes = is_array( $classes ) ? $classes : explode( ' ', $classes );
716 + $classes = array_filter( $classes );
717 + $classes = array_unique( $classes );
718 +
719 + LP_Object_Cache::set( 'item-' . $user_id . '-' . $item_id, $classes, 'learn-press/post-classes' );
720 + $items[ $item_id ] = $classes;
721 + }
722 +
723 + return $items;
724 + }
725 +}