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

abstract-lp-user.php in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.1.6.9.1, at inc/user/abstract-lp-user.php

2,275 lines 55.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Class LP_Abstract_User
5 *
6 * @author ThimPress
7 * @package LearnPress/Classes
8 * @version 3.0.0
9 */
10
11 /**
12 * Prevent loading this file directly
13 */
14 defined( 'ABSPATH' ) || exit();
15
16 if ( ! class_exists( 'LP_Abstract_User' ) ) {
17
18 /**
19 * Class LP_Abstract_User
20 */
21 class LP_Abstract_User extends LP_Abstract_Object_Data {
22
23 /**
24 * @var WP_User object
25 */
26 public $user = false;
27
28 /**
29 * @var null
30 */
31 public $profile_picture_src = null;
32
33 /**
34 * @var null
35 */
36 public $profile_picture_type = null;
37
38 /**
39 * @var array
40 */
41 protected $_data = array(
42 'email' => '',
43 'user_login' => '',
44 'description' => '',
45 'first_name' => '',
46 'last_name' => '',
47 'nickname' => '',
48 'display_name' => '',
49 'date_created' => '',
50 'date_modified' => '',
51 'role' => '',
52 'roles' => array(),
53 );
54
55 /**
56 * @var LP_User_CURD
57 */
58 protected $_curd = null;
59
60 /**
61 * LP_Abstract_User constructor.
62 *
63 * @param int $the_user
64 * @param array $args
65 */
66 public function __construct( $the_user = 0, $args = array() ) {
67
68 parent::__construct( $the_user, $args );
69
70 $this->_curd = new LP_User_CURD();
71
72 if ( is_numeric( $the_user ) && $the_user > 0 ) {
73 $this->set_id( $the_user );
74 } elseif ( $the_user instanceof self ) {
75 $this->set_id( absint( $the_user->get_id() ) );
76 } elseif ( ! empty( $the_user->ID ) ) {
77 $this->set_id( absint( $the_user->ID ) );
78 }
79
80 if ( $this->get_id() > 0 ) {
81 $this->load();
82 }
83
84 }
85
86 /**
87 * Load user data from curd
88 */
89 public function load() {
90 $this->_curd->load( $this );
91 }
92
93 /**
94 * Get data for a course user has enrolled.
95 *
96 * @param int $course_id .
97 *
98 * @return LP_User_Item_Course|bool
99 * @version 3.1.3
100 * @editor tungnx
101 * @modify 4.1.3
102 */
103 public function get_course_data( int $course_id = 0 ) {
104 $lp_user_items_db = LP_User_Items_DB::getInstance();
105
106 try {
107 if ( ! $course_id ) {
108 $course_id = get_the_ID();
109 }
110
111 /*if ( $this instanceof LP_User_Guest ) {
112 throw new Exception( 'User is Guest' );
113 }*/
114
115 $filter = new LP_User_Items_Filter();
116 $filter->item_id = $course_id;
117 $filter->user_id = $this->get_id();
118 $last_user_course = $lp_user_items_db->get_last_user_course( $filter );
119
120 if ( $last_user_course ) {
121 $object_course_data = new LP_User_Item_Course( $last_user_course );
122 } else {
123 $object_course_data = false;
124 /**
125 * Todo: some themes still not check false, so still use below code.\
126 * @editor tungnx 4.1.6.9
127 */
128 $object_course_data = new LP_User_Item_Course( $course_id );
129 }
130 } catch ( Throwable $e ) {
131 $object_course_data = false;
132 }
133
134 return $object_course_data;
135 }
136
137 /**
138 * Get user course item.
139 *
140 * @param int $item_id
141 * @param int $course_id
142 * @param string $field - Optional. Value of field to return.
143 *
144 * @return LP_User_Item_Quiz|LP_User_Item|bool
145 */
146 public function get_item_data( $item_id, $course_id, $field = '' ) {
147 $user_item = $this->get_user_item( $item_id, $course_id );
148
149 switch ( $field ) {
150 case 'end_time':
151 return $user_item->get_end_time();
152 }
153
154 return $user_item;
155 }
156
157 /**
158 * Get data for a item user started in table user-items
159 *
160 * @param int $item_id
161 * @param int $course_id
162 *
163 * @return LP_User_Item_Quiz|LP_User_Item|bool
164 */
165 public function get_user_item( $item_id, $course_id ) {
166 $data = false;
167
168 $course_data = $this->get_course_data( $course_id );
169
170 if ( $course_data ) {
171 $data = $course_data->get_item( $item_id );
172 }
173
174 return $data;
175 }
176
177 /**
178 * Return TRUE if user has used function for checking the question.
179 *
180 * @param int $question_id
181 * @param int $quiz_id
182 * @param int $course_id
183 *
184 * @return mixed
185 * @since 3.0.0
186 */
187 public function has_checked_question( $question_id, $quiz_id, $course_id = 0 ) {
188 $checked = false;
189
190 if ( $this->get_quiz_data( $quiz_id, $course_id ) ) {
191 $data = $this->get_quiz_data( $quiz_id, $course_id );
192 $checked = $data->has_checked_question( $question_id );
193 }
194
195 return apply_filters(
196 'learn-press/user/checked-question',
197 $checked,
198 $question_id,
199 $quiz_id,
200 $course_id,
201 $this->get_id()
202 );
203 }
204
205 /**
206 * Magic function to get user data
207 *
208 * @param $key
209 *
210 * @return bool
211 */
212 public function __get( $key ) {
213 $return = false;
214
215 if ( strtolower( $key ) !== 'id' ) {
216 _deprecated_argument( __CLASS__ . '::' . $key, '3.0.0' );
217 }
218
219 if ( ! empty( $this->user->data->{$key} ) ) {
220 $return = $this->user->data->{$key};
221 } else {
222 if ( isset( $this->{$key} ) ) {
223 $return = $this->{$key};
224 } elseif ( strpos( $key, '_lp_' ) === false ) {
225 $key = '_lp_' . $key;
226 $return = get_user_meta( $this->get_id(), $key, true );
227 if ( ! empty( $value ) ) {
228 $this->$key = $return;
229 }
230 }
231 }
232
233 return $return;
234 }
235
236 /**
237 * Check if a course is exists then return it's ID.
238 * Try to get it from global.
239 *
240 * @param int $course_id
241 * @param string $return
242 *
243 * @return bool|false|int|LP_Course
244 */
245 protected function _get_course( $course_id, $return = 'id' ) {
246
247 // if $course_id is not passed then try to get it from global
248 if ( ! $course_id && learn_press_is_course() ) {
249 $course_id = get_the_ID();
250 }
251
252 // Validate course
253 $course = learn_press_get_course( $course_id );
254
255 if ( $course ) {
256 switch ( $return ) {
257 case 'id':
258 return $course_id;
259 case 'object':
260 return $course;
261 }
262 }
263
264 return false;
265 }
266
267 /**
268 *
269 * @param int $item_id
270 * @param int $course_id
271 *
272 * @return bool
273 *
274 * @since 3.0.0
275 */
276 protected function _verify_course_item( $item_id, $course_id = 0 ) {
277 $course = $this->_get_course( $course_id, 'object' );
278
279 if ( false !== $course ) {
280 return $course->has_item( $item_id ) ? $course_id : false;
281 }
282
283 return false;
284 }
285
286 /**
287 * Return TRUE if an item has a status.
288 *
289 * @param array $statuses
290 * @param int $item_id
291 * @param int $course_id
292 *
293 * @return mixed
294 *
295 * @since 3.0.0
296 */
297 public function has_item_status( $statuses, $item_id, $course_id ) {
298 settype( $statuses, 'array' );
299 $status = $this->get_item_status( $item_id, $course_id );
300
301 //Todo: tungnx
302 //$status = $this->getItemStatus( $item_id, $course_id );
303
304 return apply_filters(
305 'learn-press/user-has-item-status',
306 in_array( $status, $statuses ),
307 $statuses,
308 $item_id,
309 $course_id,
310 $this->get_id()
311 );
312 }
313
314 /**
315 * Get all records of an item.
316 *
317 * @param int $item_id
318 * @param int $course_id
319 * @param bool $return_last
320 *
321 * @return bool|mixed
322 */
323 public function get_item_archive( $item_id, $course_id = 0, $return_last = false ) {
324 $records = LP_Object_Cache::get(
325 'course-item-' . $this->get_id() . '-' . $course_id . '-' . $item_id,
326 'lp-user-course-items'
327 );
328
329 if ( $records ) {
330 // $records = array_filter( $records );
331 }
332
333 if ( $return_last && is_array( $records ) ) {
334 $records = reset( $records );
335 }
336
337 return $records;
338 }
339
340 /**
341 * Count number of rows for an item in user-items
342 *
343 * @param int $item_id
344 * @param int $course_id
345 *
346 * @return int
347 * @editor tungnx
348 * @modify 4.1.3 - comment - not user
349 */
350 /*public function count_item_archive( $item_id, $course_id = 0 ) {
351 $count = 0;
352
353 if ( $items = $this->get_item_archive( $item_id, $course_id ) ) {
354 $count = sizeof( $items );
355 }
356
357 return $count;
358 }*/
359
360 /**
361 * Check quiz can retake?
362 *
363 * @param [type] $quiz_id
364 * @param [type] $course_id
365 *
366 * @return boolean
367 */
368 public function has_retake_quiz( $quiz_id, $course_id ): bool {
369 $user_quiz = $this->get_item_data( $quiz_id, $course_id );
370 $flag = false;
371
372 if ( $user_quiz ) {
373 $retaken = $user_quiz->get_retaken_count();
374 $retake_config = get_post_meta( $quiz_id, '_lp_retake_count', true );
375
376 if ( $retake_config == '-1' ) { // For no limit
377 $flag = true;
378 } elseif ( absint( $retaken ) < absint( $retake_config ) ) {
379 $flag = true;
380 }
381 }
382
383 return apply_filters( 'lp/quiz/can-retake', $flag );
384 }
385
386 /**
387 * Get quiz status for the user
388 *
389 * @param int $quiz_id
390 * @param int $course_id
391 *
392 * @return mixed
393 */
394 public function get_quiz_status( $quiz_id, $course_id = 0 ) {
395 return $this->get_item_status( $quiz_id, $course_id );
396 }
397
398 /**
399 * Get quiz status for the user
400 *
401 * @param int $lesson_id
402 * @param int $course_id
403 *
404 * @return mixed
405 */
406 public function get_lesson_status( $lesson_id, $course_id = 0 ) {
407 return $this->get_item_status( $lesson_id, $course_id );
408 }
409
410 /**
411 * @param int $item_id
412 * @param int $course_id
413 * @param bool $last
414 *
415 * @return mixed
416 * @since 3.0.0
417 */
418 public function get_item( $item_id, $course_id = 0, $last = false ) {
419 if ( ! $course_id ) {
420 $course_id = get_the_ID();
421 }
422
423 if ( ! $course_id ) {
424 return false;
425 }
426
427 $course_data = $this->get_course_data( $course_id );
428 if ( $course_data ) {
429 return $course_data->get_item( $item_id );
430 }
431
432 return false;
433 }
434
435 /**
436 * @param int $item_id
437 * @param int $course_id
438 *
439 * @return mixed
440 * @since 3.0.0
441 * @version 1.0.1
442 * @editor tungnx
443 * @modify 4.1.4.1
444 */
445 public function get_item_grade( $item_id, $course_id = 0 ) {
446 if ( ! $course_id ) {
447 $course_id = get_the_ID();
448 }
449
450 $grade = false;
451
452 $course_data = $this->get_course_data( $course_id );
453
454 if ( $course_data ) {
455 $grade = $course_data->get_item_result( $item_id, 'grade' );
456 }
457
458 return apply_filters( 'learn-press/user-item-grade', $grade, $item_id, $this->get_id(), $course_id );
459 }
460
461 /**
462 * Get current status of an item for user.
463 *
464 * @param int $item_id
465 * @param int $course_id
466 *
467 * @return bool|mixed
468 */
469 public function get_item_status( $item_id, $course_id = 0 ) {
470 $status = '';
471
472 if ( ! $course_id ) {
473 $course_id = get_the_ID();
474 }
475
476 if ( ! $course_id ) {
477 return $status;
478 }
479
480 $item = $this->get_item( $item_id, $course_id, true );
481
482 if ( false !== $item ) {
483 $status = $item['status'];
484 }
485
486 return apply_filters( 'learn-press/user-item-status', $status, $item_id, $this->get_id(), $course_id );
487 }
488
489 /**
490 * To rewrite get_item_status on abstract-lp-user.
491 *
492 * @throws Exception
493 * @author tungnx
494 */
495 /*public function getItemStatus( $item_id, $course_id ) {
496 $status = LP_User_Items_DB::getInstance()->get_item_status( $item_id, $course_id );
497
498 return $status;
499 }*/
500
501 /**
502 * Update viewing item data into database.
503 *
504 * @param int $item_id
505 * @param int $course_id
506 *
507 * @return bool
508 * @since 3.0.0
509 * @version 4.0.1
510 * @depecated 4.1.6.9
511 */
512 /*public function maybe_update_item( $item_id, $course_id ) {
513 $return = false;
514
515 try {
516 $course_data = $this->get_course_data( $course_id );
517
518 if ( $course_data ) {
519 $item = $course_data->get_item( $item_id );
520
521 if ( ! $item ) {
522 $item = LP_User_Item::get_item_object( $item_id );
523
524 if ( ! $item ) {
525 return $return;
526 }
527
528 if ( $item instanceof LP_User_Item_Quiz ) {
529 return $return;
530 }
531
532 $item->set_ref_id( $course_id );
533 $item->set_parent_id( $course_data->get_user_item_id() );
534
535 $return = $item->update();
536 }
537 }
538 } catch ( Throwable $e ) {
539 error_log( $e->getMessage() );
540 }
541
542 return $return;
543 }*/
544
545 /**
546 * Get item user has accessed in last time.
547 *
548 * @param int $course_id
549 * @param bool $permalink - Optional. TRUE will return permalink instead of ID.
550 *
551 * @return mixed
552 * @depecated 4.1.6.9
553 */
554 public function get_current_item( $course_id, $permalink = false ) {
555 _deprecated_function( __FUNCTION__, '4.1.6.9' );
556 return 0;
557 /*$course_data = $this->get_course_data( $course_id );
558 if ( ! $course_data ) {
559 return false;
560 }
561
562 $course = learn_press_get_course( $course_id );
563 $id = learn_press_get_user_item_meta( $course_data->get_user_item_id(), '_current_item' );
564 if ( ! $id || $this->has_completed_item( $id, $course_id ) ) {
565 $items = $course->get_items( '', false );
566 if ( $items ) {
567 foreach ( $items as $item_id ) {
568 if ( ! $this->has_completed_item( $item_id, $course_id ) ) {
569 $id = $item_id;
570 break;
571 }
572 }
573
574 if ( ! $id ) {
575 $id = reset( $items );
576 }
577 }
578
579 if ( $id ) {
580 learn_press_update_user_item_meta( $course_data->get_user_item_id(), '_current_item', $id );
581 }
582 }
583
584 if ( $permalink && $id ) {
585 return apply_filters(
586 'learn-press/current-course-item-permalink',
587 $course->get_item_link( $id ),
588 $course_id,
589 $this->get_id()
590 );
591 } else {
592 return apply_filters( 'learn-press/current-course-item', $id, $course_id, $this->get_id() );
593 }*/
594 }
595
596 /**
597 * Get current question's ID/Permalink inside quiz.
598 *
599 * @param int $quiz_id
600 * @param int $course_id
601 * @param bool $permalink
602 *
603 * @return bool|int|string
604 * @depecated 4.1.6.9
605 */
606 /*public function get_current_question( $quiz_id, $course_id, $permalink = false ) {
607 _deprecated_function( sprintf( '%s::%s', __CLASS__, __FUNCTION__ ), '4.0.0' );
608 }*/
609
610 /**
611 * Get previous Question
612 *
613 * @param null $quiz_id
614 * @param int $course_id
615 * @param false $permalink
616 * @depecated 4.1.6.9
617 */
618 /*public function get_prev_question( $quiz_id = null, $course_id = 0, $permalink = false ) {
619 _deprecated_function( sprintf( '%s::%s', __CLASS__, __FUNCTION__ ), '4.0.0' );
620 }*/
621
622 /**
623 * Get next Question
624 *
625 * @param null $quiz_id
626 * @param int $course_id
627 * @param false $permalink
628 * @depecated 4.1.6.9
629 */
630 /*public function get_next_question( $quiz_id = null, $course_id = 0, $permalink = false ) {
631 _deprecated_function( sprintf( '%s::%s', __CLASS__, __FUNCTION__ ), '4.0.0' );
632 }*/
633
634 /**
635 * Checks if has status of a quiz for user
636 *
637 * @param string|array $statuses
638 * @param int $quiz_id
639 * @param int $course_id
640 * @param boolean $force
641 *
642 * @return bool
643 */
644 public function has_quiz_status( $statuses, $quiz_id, $course_id = 0, $force = false ) {
645 $status = $this->get_quiz_status( $quiz_id, $course_id );
646
647 settype( $statuses, 'array' );
648
649 return apply_filters(
650 'learn_press_user_has_quiz_status',
651 in_array( $status, $statuses ),
652 $statuses,
653 $status,
654 $quiz_id,
655 $course_id,
656 $this->get_id()
657 );
658 }
659
660 /**
661 * Get current results of a quiz
662 *
663 * @param int $quiz_id
664 * @param int $course_id
665 * @param string $prop
666 *
667 * @return mixed
668 */
669 public function get_quiz_results( $quiz_id, $course_id = 0, $prop = 'result' ) {
670 $user_quiz = $this->get_item_data( $quiz_id, $course_id );
671
672 return $user_quiz ? $user_quiz->get_results( $prop ) : false;
673 }
674
675 /**
676 * Get current progress of user's quiz.
677 *
678 * @param int $quiz_id
679 * @param int $course_id
680 *
681 * @return LP_User_Item_Quiz|false
682 */
683 public function get_quiz_data( $quiz_id, $course_id = 0 ) {
684 $result = false;
685 $course_result = $this->get_course_data( $course_id );
686 if ( $course_result ) {
687 $result = $course_result->get_item( $quiz_id );
688 }
689
690 return $result;
691 }
692
693 /**
694 * Mark question that user has checked.
695 *
696 * @param int $question_id
697 * @param int $quiz_id
698 * @param int $course_id
699 *
700 * @return WP_Error|mixed
701 * @since 3.0.0
702 * @editor tungnx
703 * @modify 4.1.4.1 - comment - not use
704 */
705 /*public function check_question( $question_id, $quiz_id, $course_id ) {
706 if ( ! $course = learn_press_get_course( $course_id ) ) {
707 return false;
708 }
709
710 if ( ! $course->has_item( $quiz_id ) ) {
711 return false;
712 }
713
714 $quiz = $course->get_item( $quiz_id );
715
716 if ( ! $quiz->has_question( $question_id ) ) {
717 return false;
718 }
719
720 $quiz_data = $this->get_item_data( $quiz_id, $course_id );
721
722 return $quiz_data->check_question( $question_id );
723 }*/
724
725 /**
726 * Mark question that user has checked.
727 *
728 * @param int $question_id
729 * @param int $quiz_id
730 * @param int $course_id
731 *
732 * @return WP_Error|mixed
733 * @since 3.0.0
734 */
735 public function hint( $question_id, $quiz_id, $course_id ) {
736 $course = learn_press_get_course( $course_id );
737 if ( ! $course ) {
738 return false;
739 }
740
741 if ( ! $course->has_item( $quiz_id ) ) {
742 return false;
743 }
744
745 /**
746 * @var $quiz LP_Quiz
747 */
748 $quiz = $course->get_item( $quiz_id );
749 if ( ! $quiz instanceof LP_Course_Item_Quiz ) {
750 return false;
751 }
752
753 if ( ! $quiz->has_question( $question_id ) ) {
754 return false;
755 }
756
757 $quiz_data = $this->get_item_data( $quiz_id, $course_id );
758 $remain = $quiz_data->hint( $question_id );
759 if ( false === $remain ) {
760 return new WP_Error( 1001, __( 'You can not hint question.', 'learnpress' ) );
761 }
762
763 return $remain;
764 }
765
766 /**
767 * Return true if check answer is enabled.
768 *
769 * @param int $quiz_id
770 * @param int $course_id
771 *
772 * @return bool
773 * @deprecated 4.1.4.1
774 */
775 /*public function can_check_answer( $quiz_id, $course_id = 0 ) {
776 _deprecated_function( __FUNCTION__, '4.1.4.1' );
777 if ( ! $course_id ) {
778 $course_id = get_the_ID();
779 }
780
781 if ( $quiz_data = $this->get_item_data( $quiz_id, $course_id ) ) {
782 return $quiz_data->can_check_answer();
783 }
784
785 return false;
786 }*/
787
788 /**
789 * Return true if check answer is enabled.
790 *
791 * @param int $quiz_id
792 * @param int $course_id
793 *
794 * @return bool
795 * @depecated 4.1.6.9
796 */
797 /*public function can_hint_answer( $quiz_id, $course_id = 0 ) {
798
799 if ( ! $course_id ) {
800 $course_id = get_the_ID();
801 }
802
803 if ( $quiz_data = $this->get_item_data( $quiz_id, $course_id ) ) {
804 return $quiz_data->can_hint_answer();
805 }
806
807 return false;
808 }*/
809
810
811 public function get_quiz_last_results( $quiz_id ) {
812 $results = $this->get_course_info( $quiz_id );
813 if ( $results ) {
814 $results = reset( $results );
815 }
816
817 return apply_filters( 'learn_press_user_quiz_last_results', $results, $quiz_id, $this );
818 }
819
820 /**
821 * Get history of a quiz for an user
822 *
823 * @param int $quiz_id
824 * @param int $course_id
825 * @param int $history_id
826 * @param bool $force
827 *
828 * @return mixed|null|void
829 * @editor tungnx
830 * @modify 4.1.4.1 - comment - not use
831 */
832 /*public function get_quiz_history( $quiz_id, $course_id = 0, $history_id = null, $force = false ) {
833 $course_id = $this->_get_course( $course_id );
834
835 $course = learn_press_get_course( $course_id );
836 if ( $course ) {
837 $quizzes = $course->get_quizzes( 'ID' );
838 } else {
839 $quizzes = array();
840 }
841 $key = $this->get_id() . '-' . $course_id . '-' . $quiz_id;
842
843 $cached = LP_Cache::get_quiz_history( false, array() );
844
845 if ( ( ! array_key_exists( $key, $cached ) || $force ) && $quizzes && in_array( $quiz_id, $quizzes ) ) {
846 global $wpdb;
847 $t1 = $wpdb->learnpress_user_items;
848 $t2 = $wpdb->learnpress_user_itemmeta;
849 $in = array_fill( 0, sizeof( $quizzes ), '%d' );
850 $prepare_params = array_merge(
851 array( 'lp_quiz', $this->get_id(), $course_id ),
852 $quizzes
853 );
854 $query = $wpdb->prepare(
855 "
856 SELECT *
857 FROM $t1 uq
858 WHERE uq.item_type = %s
859 AND uq.user_id = %d
860 AND uq.ref_id = %d
861 AND uq.item_id IN(" . join( ',', $in ) . ')
862 ORDER BY uq.user_item_id DESC
863 ',
864 $prepare_params
865 );
866
867 $history = array();
868 foreach ( $quizzes as $_quiz_id ) {
869 $history[ $this->get_id() . '-' . $course_id . '-' . $_quiz_id ] = array();
870 }
871 if ( $results = $wpdb->get_results( $query ) ) {
872 $item_ids = array();
873 foreach ( $results as $result ) {
874 $item_ids[] = $result->user_item_id;
875 $cache_key = $this->get_id() . '-' . $course_id . '-' . $result->item_id;
876 if ( empty( $history[ $cache_key ] ) ) {
877 $history[ $cache_key ] = array();
878 }
879 // limit newest 10 items
880 if ( sizeof( $history[ $cache_key ] ) >= 10 ) {
881 // break;
882 }
883
884 $history[ $cache_key ][ $result->user_item_id ] = (object) array(
885 'history_id' => $result->user_item_id,
886 'start' => $result->start_time,
887 'end' => $result->end_time,
888 'status' => $result->status,
889 'question' => '',
890 'questions' => array(),
891 'question_answers' => array(),
892 );
893 }
894 if ( $item_ids && $meta = $this->_get_quiz_meta( $item_ids ) ) {
895 $maps = array(
896 'questions' => 'questions',
897 'current_question' => 'question',
898 'question_answers' => 'question_answers',
899 'question_checked' => 'question_checked',
900 );
901 foreach ( $meta as $k => $v ) {
902 $_key = $this->get_id() . '-' . $course_id . '-' . $v->item_id;
903 if ( empty( $history[ $_key ] ) ) {
904 continue;
905 }
906 if ( empty( $history[ $_key ][ $v->user_item_id ] ) ) {
907 continue;
908 }
909 $obj_key = ! empty( $maps[ $v->meta_key ] ) ? $maps[ $v->meta_key ] : $v->meta_key;
910 if ( ! $obj_key ) {
911 continue;
912 }
913 $history[ $_key ][ $v->user_item_id ]->{$obj_key} = LP_Helper::maybe_unserialize( $v->meta_value );
914 }
915 }
916 }
917
918 if ( $history ) {
919 foreach ( $history as $k1 => $v1 ) {
920 if ( empty( $cached[ $k1 ] ) ) {
921 $cached[ $k1 ] = $v1;
922 continue;
923 }
924 foreach ( $v1 as $k2 => $v2 ) {
925 $cached[ $k1 ][ $k2 ] = $v2;
926 }
927 }
928 }
929 LP_Cache::set_quiz_history( $cached );
930 }
931
932 return apply_filters(
933 'learn_press_user_quiz_history',
934 isset( $cached[ $key ] ) ? $cached[ $key ] : array(),
935 $this,
936 $quiz_id
937 );
938 }*/
939
940 /**
941 * @editor tungnx
942 * @modify 4.1.4.1 - comment - not use
943 */
944 /*private function _get_quiz_meta( $user_item_id ) {
945 global $wpdb;
946 settype( $user_item_id, 'array' );
947 $in = array_fill( 0, sizeof( $user_item_id ), '%d' );
948
949 $query = $wpdb->prepare(
950 "
951 SELECT learnpress_user_item_id as user_item_id, meta_key, meta_value, item_id
952 FROM {$wpdb->prefix}learnpress_user_itemmeta im
953 INNER JOIN {$wpdb->prefix}learnpress_user_items i ON i.user_item_id = im.learnpress_user_item_id
954 WHERE learnpress_user_item_id IN(" . join( ',', $in ) . ')
955 ',
956 $user_item_id
957 );
958
959 return $wpdb->get_results( $query );
960 }*/
961
962 /**
963 * @editor tungnx
964 * @modify 4.1.4.1 comment - not use
965 */
966 /*public function get_current_results( $quiz_id, $course_id = 0 ) {
967 $course_id = $this->_get_course( $course_id );
968
969 $history = $this->get_quiz_history( $quiz_id, $course_id );
970 $current = false;
971 if ( $history ) {
972 $current = reset( $history );
973 }
974
975 return $current;
976 }*/
977
978 /**
979 * Check if user has at least one role.
980 *
981 * @param array|string $roles
982 *
983 * @return array
984 */
985 public function has_role( $roles ) {
986 settype( $roles, 'array' );
987
988 return array_intersect( $roles, $this->get_roles() );
989 }
990
991 /**
992 * Detect the type of user
993 *
994 * @param string|int $type
995 *
996 * @return bool
997 */
998 public function is( $type ) {
999 $is = false;
1000 if ( $type === 'current' ) {
1001 $is = $this->is( get_current_user_id() );
1002 } elseif ( is_string( $type ) ) {
1003 $name = preg_replace( '!LP_User(_?)!', '', get_class( $this ) );
1004 $is = strtolower( $name ) == strtolower( $type );
1005 } elseif ( is_numeric( $type ) ) {
1006 $is = $this->get_id() && ( $this->get_id() == $type );
1007 }
1008
1009 return $is;
1010 }
1011
1012 /**
1013 *
1014 * Check what the user can do
1015 *
1016 * @param $role
1017 *
1018 * @return mixed
1019 * @throws Exception
1020 */
1021 public function can( $role ) {
1022 _deprecated_function( __FUNCTION__, '3.0.8' );
1023 $args = func_get_args();
1024 unset( $args[0] );
1025 $method = 'can_' . preg_replace( '!-!', '_', $role );
1026 $callback = array( $this, $method );
1027 if ( is_callable( $callback ) ) {
1028 return call_user_func_array( $callback, $args );
1029 } else {
1030 throw new Exception( sprintf( __( 'The role %s for user doesn\'t exist', 'learnpress' ), $role ) );
1031 }
1032 }
1033
1034 public function can_edit_item( $item_id, $course_id = 0 ) {
1035 $return = $this->is_admin();
1036
1037 if ( ! $return ) {
1038 $course_id = $this->_get_course( $course_id );
1039
1040 $course_author = learn_press_get_course_user( $course_id );
1041 if ( $course_author && $course_author->get_id() == $this->get_id() ) {
1042 $return = true;
1043 }
1044 }
1045
1046 return apply_filters( 'learn_press_user_can_edit_item', $return, $item_id, $course_id, $this->get_id() );
1047 }
1048
1049 /**
1050 * Check if user can finish course by getting current progress
1051 * and compares with course passing condition.
1052 *
1053 * @param int $course_id
1054 *
1055 * @return bool
1056 * @editor tungnx
1057 * @modify 4.1.3
1058 */
1059 public function can_finish_course( int $course_id ) {
1060 _deprecated_function( __FUNCTION__, '4.1.3', 'is_course_finished' );
1061
1062 return true;
1063 }
1064
1065 /**
1066 * Check if course has any passed status for an user.
1067 * Statuses: depending on value of column `status` in user_items.
1068 * - purchased: bought and order is completed, `start_date` and `end_date` is null
1069 * - enrolled: value of column `status` in user_items is enrolled
1070 * - started: value of column `status` in user_items is started
1071 * - enrolled: value of column `status` in user_items is enrolled
1072 *
1073 * @param int $course_id
1074 * @param string|array $statuses
1075 *
1076 * @return bool
1077 * @since 2.0
1078 */
1079 public function has_course_status( $course_id, $statuses ) {
1080 $status = $this->get_course_status( $course_id );
1081
1082 if ( is_array( $statuses ) ) {
1083 return in_array( $status, $statuses );
1084 } elseif ( is_string( $statuses ) ) {
1085 return $statuses == $status;
1086 }
1087
1088 return false;
1089 }
1090
1091 /**
1092 * @depecated 4.1.6.9.1
1093 */
1094 /*public function get_completed_items( $course_id ) {
1095 $this->_curd->get_user_items( $this->get_id(), $course_id );
1096
1097 return $this->_curd->get_user_completed_items( $this->get_id(), $course_id );
1098 }*/
1099
1100 /**
1101 * Finish course
1102 *
1103 * @param int $course_id
1104 *
1105 * @return int|bool
1106 */
1107 public function finish_course( int $course_id ) {
1108 $return = false;
1109 $course = learn_press_get_course( $course_id );
1110
1111 if ( $course ) {
1112 $user_course = $this->get_course_data( $course_id );
1113
1114 $result = $user_course->calculate_course_results();
1115
1116 // Save result for course
1117 LP_User_Items_Result_DB::instance()->update( $user_course->get_user_item_id(), wp_json_encode( $result ) );
1118
1119 if ( $result['pass'] ) {
1120 $graduation = LP_COURSE_GRADUATION_PASSED;
1121 } else {
1122 $graduation = LP_COURSE_GRADUATION_FAILED;
1123 }
1124
1125 $user_course->set_graduation( $graduation );
1126 $user_course->save();
1127
1128 $return = $user_course->complete( 'finished' );
1129
1130 if ( $return ) {
1131 do_action( 'learn-press/user-course-finished', $course_id, $this->get_id(), $return );
1132 }
1133 }
1134
1135 return apply_filters( 'learn-press/user-course-finished-data', $return, $course_id, $this->get_id() );
1136 }
1137
1138 /**
1139 * Check user instructor.
1140 *
1141 * @return bool
1142 */
1143 public function is_instructor(): bool {
1144
1145 $roles = $this->get_data( 'roles' ) ? $this->get_data( 'roles' ) : array();
1146
1147 return in_array( LP_TEACHER_ROLE, $roles );
1148 }
1149
1150 /**
1151 * Check user admin.
1152 *
1153 * @return bool
1154 */
1155 public function is_admin() {
1156 $roles = $this->get_data( 'roles' ) ? $this->get_data( 'roles' ) : array();
1157
1158 return in_array( 'administrator', $roles );
1159 }
1160
1161
1162 public function can_create_course() {
1163 return $this->is_instructor() || $this->is_admin();
1164 }
1165
1166 /**
1167 * Wrap function to check this user is author of a post.
1168 *
1169 * @param int $post_id
1170 *
1171 * @return bool
1172 * @since 3.1.0
1173 */
1174 public function is_author_of( $post_id ) {
1175 return absint( get_post_field( 'post_author', $post_id ) ) === $this->get_id();
1176 }
1177
1178 public function has( $role ) {
1179 _deprecated_function( __FUNCTION__, '3.0.8' );
1180
1181 $args = func_get_args();
1182 unset( $args[0] );
1183 $method = 'has_' . preg_replace( '!-!', '_', $role );
1184 $callback = array( $this, $method );
1185 if ( is_callable( $callback ) ) {
1186 return call_user_func_array( $callback, $args );
1187 } else {
1188 throw new Exception( sprintf( __( 'The role %s for user doesn\'t exist', 'learnpress' ), $role ) );
1189 }
1190 }
1191
1192 public function get( $role ) {
1193 $args = func_get_args();
1194 unset( $args[0] );
1195 $method = 'get_' . preg_replace( '!-!', '_', $role );
1196 $callback = array( $this, $method );
1197 if ( is_callable( $callback ) ) {
1198 return call_user_func_array( $callback, $args );
1199 } else {
1200 throw new Exception( sprintf( __( 'The role %s for user doesn\'t exist', 'learnpress' ), $role ) );
1201 }
1202 }
1203
1204 /**
1205 * Check user has passed course.
1206 *
1207 * @param $course_id
1208 *
1209 * @return mixed
1210 */
1211 public function has_passed_course( $course_id ) {
1212 $user_course = $this->get_course_data( $course_id );
1213
1214 if ( $user_course && $user_course->is_passed() ) {
1215 return true;
1216 } else {
1217 return false;
1218 }
1219 }
1220
1221 /**
1222 * Checks if user has started a quiz
1223 * - FALSE if user has not started quiz
1224 * - String if user has started quiz (status of quiz)
1225 *
1226 * @param int $quiz_id
1227 * @param int $course_id
1228 *
1229 * @return mixed
1230 */
1231 public function has_started_quiz( $quiz_id, $course_id = 0 ) {
1232 $course_id = $this->_get_course( $course_id );
1233 $started = false;
1234 $started = $this->has_quiz_status( array( 'started', 'completed' ), $quiz_id, $course_id );
1235
1236 return apply_filters( 'learn_press_user_started_quiz', $started, $quiz_id, $course_id, $this->get_id() );
1237 }
1238
1239 /**
1240 * Return true if user has completed a quiz
1241 *
1242 * @param int $quiz_id
1243 * @param int $course_id
1244 *
1245 * @return bool
1246 * @depecated 4.1.6.9
1247 */
1248 /*public function has_completed_quiz( $quiz_id, $course_id = 0 ): bool {
1249 return $this->get_item_status( $quiz_id, $course_id ) == 'completed';
1250 }*/
1251
1252 /**
1253 * Mark a lesson is completed for user
1254 *
1255 * @param int $lesson_id
1256 * @param int $course_id
1257 * @param bool $return_wp_error
1258 *
1259 * @return bool|WP_Error
1260 */
1261 public function complete_lesson( $lesson_id, $course_id = 0, $return_wp_error = true ) {
1262 try {
1263 $course_id = $this->_get_course( $course_id );
1264
1265 $course_data = $this->get_course_data( $course_id );
1266
1267 $result = false;
1268
1269 /**
1270 * If user has stared a lesson, get user lesson information
1271 */
1272 $item = $course_data->get_item( $lesson_id );
1273 if ( $item ) {
1274 if ( $item->is_completed() ) {
1275 throw new Exception(
1276 __( 'You have already completed this lesson.', 'learnpress' ),
1277 LP_COMPLETE_ITEM_FAIL
1278 );
1279 }
1280
1281 $item->set_end_time( current_time( 'mysql', 1 ) );
1282 $item->set_status( 'completed' );
1283 $item->set_graduation( 'passed' );
1284
1285 $updated = $item->update();
1286
1287 if ( is_wp_error( $updated ) ) {
1288 return $return_wp_error ? $updated : false;
1289 } else {
1290 $result = true;
1291 }
1292 }
1293
1294 do_action( 'learn-press/user-completed-lesson', $lesson_id, $course_id, $this->get_id() );
1295 } catch ( Exception $ex ) {
1296 $result = $return_wp_error ? new WP_Error( $ex->getCode(), $ex->getMessage() ) : false;
1297 }
1298
1299 return $result;
1300 }
1301
1302 /**
1303 * Returns TRUE if user has already completed a lesson
1304 *
1305 * @param int $lesson_id Lesson id.
1306 * @param null $course_id Course id.
1307 *
1308 * @return bool
1309 * @depecated 4.1.6.9
1310 */
1311 public function has_completed_lesson( $lesson_id = 0, $course_id = null ): bool {
1312 return 'completed' === $this->get_item_status( $lesson_id, $course_id );
1313 }
1314
1315 /**
1316 * Return current status of course for user
1317 *
1318 * @param int $course_id
1319 * @param string $field
1320 * @param bool $force
1321 *
1322 * @return mixed
1323 */
1324 public function get_course_info( int $course_id, $field = null, $force = false ) {
1325 $user_data = $this->get_course_data( $course_id );
1326 if ( $user_data ) {
1327 return $user_data->get_results( $field );
1328 }
1329
1330 return false;
1331 }
1332
1333 /**
1334 * @param $course_id
1335 *
1336 * @return int
1337 * @depecated 4.1.6.9
1338 */
1339 public function get_course_history_id( $course_id ) {
1340 $history = $this->get_course_info( $course_id );
1341
1342 return ! empty( $history['history_id'] ) ? $history['history_id'] : 0;
1343 }
1344
1345 /**
1346 * Get current status of a course for user.
1347 *
1348 * @param int $course_id
1349 *
1350 * @return mixed
1351 * @editor tungnx
1352 * @modify 4.1.3
1353 * @version 1.0.1
1354 */
1355 public function get_course_status( int $course_id ): string {
1356 $status = '';
1357
1358 try {
1359 $user_data = $this->get_course_data( $course_id );
1360
1361 if ( $user_data ) {
1362 $status = $user_data->get_status();
1363 }
1364 } catch ( Throwable $e ) {
1365 if ( LP_Debug::is_debug() ) {
1366 error_log( $e->getMessage() );
1367 }
1368 }
1369
1370 return apply_filters( 'learn-press/user-course-status', $status, $course_id, $this->get_id() );
1371 }
1372
1373 /**
1374 * Controls what this user can do with a course.
1375 *
1376 * 0 => No accessible
1377 * 10 => Normal users (like not logged in)
1378 * 20 => Author of course
1379 * 30 => Admin site
1380 * 35 => No require enrollment
1381 * 40 => Ordered but not completed
1382 * 50 => Order is completed but not enrolled
1383 * 60 => User has already enrolled course
1384 * 70 => User has already finished course
1385 *
1386 * @param int $course_id
1387 *
1388 * @return int
1389 * @since 3.1.0
1390 * @editor tungnx
1391 * @modify 4.1.3 - comment - not use
1392 */
1393 /*public function get_course_access_level( $course_id ) {
1394 $access_level = LP_Object_Cache::get(
1395 'course-' . $course_id . '-' . $this->get_id(),
1396 'learn-press/course-access-levels'
1397 );
1398
1399 if ( false === $access_level ) {
1400 $course = learn_press_get_course( $course_id );
1401
1402 if ( ! $course ) {
1403 $access_level = LP_COURSE_ACCESS_LEVEL_0;
1404 } elseif ( $this->is_admin() ) {
1405 $access_level = LP_COURSE_ACCESS_LEVEL_30;
1406 } elseif ( $this->is_author_of( $course_id ) ) {
1407 $access_level = LP_COURSE_ACCESS_LEVEL_20;
1408 } else {
1409 $access_level = LP_COURSE_ACCESS_LEVEL_10;
1410 }
1411
1412 // Default level
1413 $access_level = apply_filters(
1414 'learn-press/course-access-level-default',
1415 $access_level,
1416 $course_id,
1417 $this->get_id()
1418 );
1419 $course_data = $this->get_course_data( $course_id );
1420
1421 if ( $course_data && $course_data->get_user_item_id() ) {
1422 // if ( $course_data->get_access_level() >= 50 ) {
1423 switch ( $course_data->get_status() ) {
1424 case 'completed':
1425 case 'failed':
1426 $access_level = LP_COURSE_ACCESS_LEVEL_60;
1427 break;
1428 case 'in-progress':
1429 case 'enrolled':
1430 $access_level = LP_COURSE_ACCESS_LEVEL_70;
1431 break;
1432 }
1433 // }
1434 } else {
1435 $order = $this->get_course_order( $course_id );
1436
1437 if ( $order ) {
1438 switch ( $order->get_status() ) {
1439 case 'completed':
1440 $access_level = LP_COURSE_ACCESS_LEVEL_50;
1441 break;
1442 default:
1443 $access_level = LP_COURSE_ACCESS_LEVEL_40;
1444 }
1445 }
1446 }
1447
1448 LP_Object_Cache::set(
1449 'course-' . $course_id . '-' . $this->get_id(),
1450 $access_level,
1451 'learn-press/course-access-levels'
1452 );
1453 }
1454
1455 return apply_filters( 'learn-press/course-access-level', $access_level, $course_id, $this->get_id() );
1456 }*/
1457
1458 /**
1459 * @editor tungnx
1460 * @reason comment - not use
1461 * @modify 4.1.2
1462 */
1463 /*public function get_item_access_level( $item_id, $course_id ) {
1464 $access_level = 0;
1465
1466 if ( $course = learn_press_get_course( $course_id ) ) {
1467 if ( $course->has_item( $item_id ) ) {
1468 if ( 10 < $this->get_course_access_level( $course_id ) ) {
1469 $access_level = 10;
1470 } else {
1471 $item = $course->get_item( $item_id );
1472 if ( $item->is_preview() ) {
1473 $access_level = 10;
1474 }
1475 }
1476 }
1477 }
1478
1479 return apply_filters(
1480 'learn-press/course-item-access-level',
1481 $access_level,
1482 $item_id,
1483 $course_id,
1484 $this->get_id()
1485 );
1486 }*/
1487
1488 /**
1489 * Set new access-level of an user with a course.
1490 *
1491 * @param int $access_level
1492 * @param int $course_id
1493 *
1494 * @return mixed
1495 * @since 3.1.0
1496 * @editor tungnx
1497 * @reason comment - not use
1498 * @modify 4.1.2
1499 */
1500 /*public function set_course_access_level( $access_level, $course_id ) {
1501 if ( $access_level !== $this->get_course_access_level( $course_id ) ) {
1502 LP_Object_Cache::set(
1503 'course-' . $course_id . '-' . $this->get_id(),
1504 $access_level,
1505 'learn-press/course-access-levels'
1506 );
1507 }
1508
1509 return $access_level;
1510 }*/
1511
1512 /**
1513 * Check if user have an access-level.
1514 * Consider the passed access-level is max level user have.
1515 *
1516 * @param int[] $access_level
1517 * @param int $course_id
1518 * @param string $compare
1519 *
1520 * @return bool
1521 * @since 3.1.0
1522 * @editor tungnx
1523 * @modify 4.1.3 - not - use
1524 */
1525 /*public function has_course_access_level( $access_level, $course_id, $compare = '<=' ) {
1526 $user_access_level = $this->get_course_access_level( $course_id );
1527
1528 switch ( $compare ) {
1529 case 'any':
1530 settype( $access_level, 'array' );
1531 $has = in_array( $user_access_level, $access_level );
1532 break;
1533 default:
1534 $has = version_compare( $user_access_level, $access_level );
1535 }
1536
1537 return $has;
1538 }*/
1539
1540 /**
1541 * Check if user has an access-level with a course.
1542 *
1543 * @param int $access_level
1544 * @param int $course_id
1545 *
1546 * @return bool
1547 * @since 3.1.0
1548 * @editor tungnx
1549 * @modify 4.1.2
1550 * @reason comment - not use
1551 */
1552 /*public function is_access_level( $access_level, $course_id ) {
1553 $user_access_level = $this->get_course_access_level( $course_id );
1554
1555 return $user_access_level === $access_level;
1556 }*/
1557
1558 /**
1559 * Check if user is already ordered a course.
1560 *
1561 * @param int $course_id
1562 *
1563 * @return mixed|LP_Order
1564 * @editor tungnx
1565 * @modify 4.1.3 - comment - not use
1566 */
1567 /*public function has_ordered_course( $course_id ) {
1568 $return = apply_filters(
1569 'learn-press/user-has-ordered-course',
1570 $this->get_course_order( $course_id ),
1571 $course_id,
1572 $this->get_id()
1573 );
1574
1575 // Deprecated since 3.0.0
1576 $return = apply_filters( 'learn_press_user_has_ordered_course', $return, $course_id, $this->get_id() );
1577
1578 return $return;
1579 }*/
1580
1581 /**
1582 * Get order status of a course.
1583 *
1584 * @param int $course_id
1585 *
1586 * @return mixed
1587 */
1588 public function get_order_status( $course_id ) {
1589 try {
1590 $order = $this->get_course_order( $course_id );
1591
1592 if ( ! $order ) {
1593 throw new Exception( 'Order not exists' );
1594 }
1595
1596 $order_status = apply_filters(
1597 'learn-press/course-order-status',
1598 get_post_status( $order->get_id() ),
1599 $course_id,
1600 $this->get_id()
1601 );
1602 } catch ( Throwable $e ) {
1603 $order_status = false;
1604 }
1605
1606 return $order_status;
1607 }
1608
1609 /**
1610 * @param $item
1611 * @param int $course_id
1612 * @param bool $force
1613 *
1614 * @return mixed|void
1615 */
1616 public function has_completed_item( $item, $course_id = 0, $force = false ) {
1617
1618 $course_id = $this->_get_course( $course_id );
1619
1620 $return = false;
1621 $item_id = 0;
1622 if ( is_numeric( $item ) ) {
1623 $item_id = absint( $item );
1624 } else {
1625 settype( $item, 'array' );
1626 if ( ! empty( $item['ID'] ) ) {
1627 $item_id = absint( $item['ID'] );
1628 }
1629 }
1630 if ( $item_id ) {
1631 if ( empty( $item['item_type'] ) ) {
1632 $type = learn_press_get_post_type( $item_id );
1633 } else {
1634 $type = $item['item_type'];
1635 }
1636 if ( ! $type ) {
1637 $type = learn_press_get_post_type( $item_id );
1638 }
1639
1640 if ( $type == 'lp_lesson' || $type == 'lp_quiz' ) {
1641 $return = 'completed' === $this->get_item_status( $item_id, $course_id );
1642 }
1643 }
1644
1645 return apply_filters( 'learn_press_user_has_completed_item', $return, $item );
1646 }
1647
1648 /**
1649 * Get the remaining time of a course for the user.
1650 *
1651 * @param int $course_id
1652 *
1653 * @return bool|int|string
1654 */
1655 public function get_course_remaining_time( $course_id ) {
1656 $course = learn_press_get_course( $course_id );
1657 $remain = false;
1658
1659 if ( $course && $course->get_id() ) {
1660 $course_data = $this->get_course_data( $course_id, true );
1661 if ( $course_data ) {
1662 $remain = $course_data->is_exceeded();
1663 }
1664 }
1665
1666 return $remain > 0 ? learn_press_seconds_to_weeks( $remain ) : false;
1667 }
1668
1669 /**
1670 * Get the order that contains the course.
1671 *
1672 * @param int $course_id
1673 *
1674 * @return bool|LP_Order
1675 * @editor tungnx
1676 * @throws Exception
1677 * @version 1.0.2
1678 * @since 4.1.1
1679 */
1680 public function get_course_order( int $course_id ) {
1681 $lp_order = false;
1682 $lp_order_db = LP_Order_DB::getInstance();
1683 $lp_order_id = $lp_order_db->get_last_lp_order_id_of_user_course( $this->get_id(), $course_id );
1684
1685 if ( $lp_order_id ) {
1686 $lp_order = new LP_Order( $lp_order_id );
1687 }
1688
1689 return $lp_order;
1690 }
1691
1692 /**
1693 * Enroll this user to a course.
1694 *
1695 * @param int $course_id
1696 * @param int $order_id - Optional. An user can be enrolled to a course
1697 *
1698 * @return bool|WP_Error
1699 * @throws Exception
1700 * @since 3.3.0
1701 * @editor tungnx
1702 * @version 3.3.1
1703 * @modify 4.1.3 - comment - not use
1704 */
1705 // public function enroll_course( int $course_id = 0, int $order_id = 0 ) {
1706 // $lp_user_items_db = LP_User_Items_DB::getInstance();
1707 //
1708 // try {
1709 // /*$user_item_api = new LP_User_Item_CURD();
1710 // $find_query = array(
1711 // 'item_id' => $course_id,
1712 // 'user_id' => $this->get_id(),
1713 // );
1714 //
1715 // if ( $order_id ) {
1716 // $find_query['ref_id'] = $order_id;
1717 // }*/
1718 //
1719 // $filter = new LP_User_Items_Filter();
1720 // $filter->user_id = get_current_user_id();
1721 // $filter->item_id = $course_id;
1722 // $course_item = $lp_user_items_db->get_last_user_course( $filter );
1723 //
1724 // if ( ! $course_item ) {
1725 // $course_item = LP_User_Item::get_empty_item();
1726 // } else {
1727 // $course_item = (array) $course_item;
1728 // }
1729 //
1730 // $user_id = $this->get_id();
1731 //
1732 // $course_item['user_id'] = $user_id;
1733 // $course_item['item_id'] = $course_id;
1734 // $course_item['item_type'] = learn_press_get_post_type( $course_id );
1735 // $course_item['ref_id'] = $order_id;
1736 // $course_item['ref_type'] = ( $order_id != 0 ) ? learn_press_get_post_type( $order_id ) : '';
1737 // $course_item['start_time'] = current_time( 'mysql', true );
1738 // $course_item['access_level'] = 50;
1739 //
1740 // /**
1741 // * @editor tungnx
1742 // * @fixed: case no auto enroll
1743 // */
1744 // if ( 'yes' == LP_Settings::get_option( 'auto_enroll' ) ) {
1745 // $course_item['graduation'] = 'in-progress';
1746 // }
1747 //
1748 // $user_course = new LP_User_Item_Course( $course_item );
1749 // $user_course->set_status( LP_COURSE_PURCHASED );
1750 //
1751 // if ( ! $user_course->update( true ) ) {
1752 // throw new Exception( __( 'Update user item error.', 'learnpress' ) );
1753 // }
1754 //
1755 // /*$user_id = is_user_logged_in() ? $this->get_id() : 0;
1756 //
1757 // global $wpdb;
1758 // $query = $wpdb->prepare(
1759 // "
1760 // UPDATE {$wpdb->learnpress_user_items}
1761 // SET access_level = %d
1762 // WHERE user_id = %d
1763 // AND item_id = %d
1764 // AND user_item_id NOT IN(%d)
1765 // ",
1766 // 0,
1767 // $user_id,
1768 // $course_id,
1769 // $user_course->get_user_item_id()
1770 // );
1771 // $wpdb->query( $query );*/
1772 //
1773 // $return = $user_course->get_user_item_id();
1774 // } catch ( Exception $ex ) {
1775 // error_log( $ex->getMessage() );
1776 // return false;
1777 // }
1778 //
1779 // return $return;
1780 // }
1781
1782 /**
1783 * Enroll this user to a course.
1784 *
1785 * @param int $course_id
1786 * @param int $order_id
1787 * @param bool $force - Optional. Force create db record for preview quiz case
1788 * @param bool $wp_error - Optional. TRUE will return WP_Error object if there is an error.
1789 * @editor tungnx - comment - not use
1790 * @return bool|mixed|WP_Error
1791 */
1792 /*public function enroll( $course_id, $order_id, $force = false, $wp_error = false ) {
1793 global $wpdb;
1794
1795 _deprecated_function( __FUNCTION__, '4.1.0' );
1796
1797 try {
1798 $course = learn_press_get_course( $course_id );
1799 $user_id = $this->get_id();
1800
1801 if ( $course->is_required_enroll() && ! $force ) {
1802 $order = learn_press_get_order( $order_id );
1803
1804 if ( ! $order ) {
1805 throw new Exception( __( 'Failed to enroll course.', 'learnpress' ), 10000 );
1806 }
1807
1808 if ( ! $this->can_enroll_course( $course_id ) ) {
1809 throw new Exception( __( 'Failed to enroll course.', 'learnpress' ), 10001 );
1810 }
1811
1812 if ( ! $this->get_id() ) {
1813 throw new Exception( __( 'Please login to enroll course.', 'learnpress' ), 10002 );
1814 }
1815 }
1816
1817 $return = $this->enroll_course( $course_id, $order_id, false, $wp_error );
1818
1819 return $return;
1820
1821 } catch ( Exception $ex ) {
1822 return new WP_Error( $ex->getCode(), $ex->getMessage() );
1823 }
1824 }*/
1825
1826 /**
1827 * @param $question_id
1828 *
1829 * @return null|string
1830 */
1831 public function get_quiz_by_question( $question_id ) {
1832 global $wpdb;
1833 $query = $wpdb->prepare(
1834 "
1835 SELECT quiz_id
1836 FROM {$wpdb->prefix}learnpress_user_items uq
1837 INNER JOIN {$wpdb->prefix}learnpress_user_itemmeta uqm ON uqm.learnpress_user_item_id = uq.user_item_id AND uqm.meta_key = %s AND uqm.meta_value LIKE %s
1838 ",
1839 'questions',
1840 '%i:' . $wpdb->esc_like( $question_id . '' ) . ';%'
1841 );
1842
1843 return $wpdb->get_var( $query );
1844 }
1845
1846 /**
1847 * @param $question_id
1848 * @param null $quiz_id
1849 *
1850 * @return bool
1851 */
1852 public function get_answer_results( $question_id, $quiz_id = null ) {
1853
1854 _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '3.0.0' );
1855
1856 $data = false;
1857 if ( ! $quiz_id ) {
1858 $quiz_id = $this->get_quiz_by_question( $question_id );
1859 }
1860 if ( $quiz_id ) {
1861 $question = LP_Question::get_question( $question_id );
1862
1863 if ( $question ) {
1864 $quiz_results = $this->get_quiz_results( $quiz_id );
1865 if ( ! empty( $quiz_results->question_answers ) ) {
1866 $question_answer = array_key_exists(
1867 $question_id,
1868 $quiz_results->question_answers
1869 ) ? $quiz_results->question_answers[ $question_id ] : null;
1870 $data = $question->check( $question_answer );
1871 }
1872 }
1873 }
1874
1875 return $data;
1876 }
1877
1878 /**
1879 * @param $question_id
1880 * @param null $quiz_id
1881 *
1882 * @return bool
1883 */
1884 public function is_answered_question( $question_id, $quiz_id = null ) {
1885 if ( empty( $this->answered_questions ) ) {
1886 $this->answered_questions = array();
1887 }
1888 if ( ! $quiz_id ) {
1889 $quiz_id = $this->get_quiz_by_question( $question_id );
1890 }
1891
1892 $results = $this->get_quiz_results( $quiz_id );
1893 $answered = ! empty( $results->question_answers ) ? $results->question_answers : array();
1894
1895 return $answered ? array_key_exists( $question_id, $answered ) : false;
1896 }
1897
1898 /**
1899 * @param array $args
1900 *
1901 * @return LP_Query_List_Table
1902 * @editor tungnx
1903 * @deprecated 4.1.6
1904 */
1905 /*public function get_purchased_courses( array $args = array() ): LP_Query_List_Table {
1906 $filter = new LP_User_Items_Filter();
1907 $filter->fields = array( 'item_id' );
1908 $filter->user_id = $this->get_id();
1909 $filter->status = $args['status'] ?? '';
1910 $filter->page = $args['paged'] ?? 1;
1911 $filter->limit = $args['limit'] ?? $filter->limit;
1912 $total_rows = 0;
1913 $result_courses = LP_User_Item_Course::get_user_courses( $filter, $total_rows );
1914
1915 $course_ids = LP_Course::get_course_ids( $result_courses, 'item_id' );
1916
1917 $courses = array(
1918 'total' => $total_rows,
1919 'paged' => $filter->page,
1920 'limit' => $filter->limit,
1921 'items' => $course_ids,
1922 );
1923
1924 return new LP_Query_List_Table( $courses );
1925 }*/
1926
1927 /**
1928 * @return array
1929 */
1930 public function get_roles() {
1931 return (array) $this->get_data( 'roles' );
1932 }
1933
1934 /**
1935 * @param $question_id
1936 * @param $quiz_id
1937 * @param int $course_id
1938 *
1939 * @return bool
1940 */
1941 public function has_checked_answer( $question_id, $quiz_id, $course_id = 0 ) {
1942 if ( ! $course_id ) {
1943 $course_id = get_the_ID();
1944 }
1945
1946 $quiz_data = $this->get_item_data( $quiz_id, $course_id );
1947
1948 return $quiz_data ? $quiz_data->has_checked_question( $question_id ) : false;
1949 }
1950
1951 /**
1952 * @param $question_id
1953 * @param $quiz_id
1954 * @param int $course_id
1955 *
1956 * @return bool
1957 */
1958 public function has_hinted_answer( $question_id, $quiz_id, $course_id = 0 ) {
1959 if ( ! $course_id ) {
1960 $course_id = get_the_ID();
1961 }
1962
1963 $quiz_data = $this->get_item_data( $quiz_id, $course_id );
1964
1965 return $quiz_data ? $quiz_data->has_hinted_question( $question_id ) : false;
1966 }
1967
1968 /**
1969 * Return TRUE if user is already exists.
1970 *
1971 * @return bool
1972 */
1973 public function is_exists() {
1974 return ! ! get_user_by( 'id', $this->get_id() );
1975 }
1976
1977 /**
1978 * Check if the user is logged in.
1979 *
1980 * @return bool
1981 */
1982 public function is_logged_in() {
1983 return $this->get_id() == get_current_user_id();
1984 }
1985
1986 /**
1987 * Get upload profile src
1988 * Option: null: get origin picture, "thumbnail": get thumbnail picture
1989 *
1990 * @param mixed $size
1991 *
1992 * @return string
1993 */
1994 public function get_upload_profile_src( $size = '' ) {
1995 return LP_Profile::instance( $this->get_id() )->get_upload_profile_src( $size );
1996 }
1997
1998 /**
1999 * @param string $type
2000 * @param int $size
2001 * @param bool $src_only
2002 *
2003 * @return false|string
2004 */
2005 public function get_profile_picture( $type = '', $size = 96, $src_only = false ) {
2006 return LP_Profile::instance( $this->get_id() )->get_profile_picture( $type, $size );
2007 }
2008
2009 /**
2010 * Get links socials of use on Profile page
2011 *
2012 * @param int $user_id
2013 * @return array
2014 */
2015 public function get_profile_socials( int $user_id = 0 ): array {
2016 $socials = array();
2017 $extra_info = learn_press_get_user_extra_profile_info( $user_id );
2018
2019 if ( $extra_info ) {
2020 foreach ( $extra_info as $k => $v ) {
2021 if ( empty( $v ) ) {
2022 continue;
2023 }
2024
2025 switch ( $k ) {
2026 case 'facebook':
2027 $i = '<i class="fab fa-facebook-f"></i>';
2028 break;
2029 case 'twitter':
2030 $i = '<i class="fab fa-twitter"></i>';
2031 break;
2032 case 'googleplus':
2033 $i = '<i class="fab fa-google-plus-g"></i>';
2034 break;
2035 case 'youtube':
2036 $i = '<i class="fab fa-youtube"></i>';
2037 break;
2038 default:
2039 $i = sprintf( '<i class="fab fa-%s"></i>', $k );
2040 }
2041
2042 $icon = apply_filters(
2043 'learn-press/user-profile-social-icon',
2044 $i,
2045 $k,
2046 $this->get_id(),
2047 $this
2048 );
2049 $socials[ $k ] = sprintf( '<a href="%s">%s</a>', esc_url_raw( $v ), $icon );
2050 }
2051 }
2052
2053 return apply_filters( 'learn-press/user-profile-socials', $socials, $this->get_id(), $this );
2054 }
2055
2056 /**
2057 * Check if user can access to a course.
2058 *
2059 * @param int $course_id
2060 *
2061 * @return mixed
2062 * @editor tungnx
2063 * @modify 4.1.3 - comment - not use
2064 */
2065 /*public function can_access_course( $course_id ) {
2066
2067 $accessible = $this->has_course_access_level(
2068 array(
2069 LP_COURSE_ACCESS_LEVEL_60,
2070 LP_COURSE_ACCESS_LEVEL_70,
2071 ),
2072 $course_id,
2073 'any'
2074 );
2075
2076 $accessible = apply_filters(
2077 'learn-press/user-can-access-course',
2078 $accessible,
2079 $course_id,
2080 $this->get_id()
2081 );
2082
2083 return $accessible;
2084 }*/
2085
2086 /**
2087 * Check course of user has graduation is in-progress
2088 *
2089 * @param $course_id
2090 * @return bool
2091 * @throws Exception
2092 */
2093 public function is_course_in_progress( $course_id ): bool {
2094 $user = learn_press_get_user( $this->get_id() );
2095 $user_course = $user->get_course_data( $course_id );
2096
2097 return $user_course && LP_COURSE_GRADUATION_IN_PROGRESS === $user_course->get_graduation();
2098 }
2099
2100 /**
2101 * Return TRUE if user can do a quiz
2102 *
2103 * @param $quiz_id
2104 * @param int $course_id
2105 *
2106 * @return bool
2107 * @throws Exception
2108 */
2109 public function can_do_quiz( $quiz_id, $course_id = 0 ) {
2110 $course = learn_press_get_course( $course_id );
2111
2112 if ( $course->is_required_enroll() ) {
2113 $can = $this->has_course_status(
2114 $course_id,
2115 array( 'enrolled' )
2116 ) && ! $this->has_started_quiz( $quiz_id, $course_id );
2117 } else {
2118 $can = ! $this->has_started_quiz( $quiz_id, $course_id );
2119 }
2120
2121 return apply_filters( 'learn_press_user_can_do_quiz', $can, $quiz_id, $this->get_id(), $course_id );
2122 }
2123
2124 public function evaluate_course_results( $course_id ) {
2125 $user_course = $this->get_course_data( $course_id );
2126
2127 return isset( $user_course ) ? $user_course->get_results( 'result' ) : 0;
2128 }
2129
2130 /**
2131 * @editor tungnx
2132 * @modify 4.1.4.1 - comment - not use
2133 */
2134 /*public function has_reached_passing_condition( $course_id ) {
2135 $course = learn_press_get_course( $course_id );
2136 $result = $this->evaluate_course_results( $course_id );
2137
2138 return $return = $result >= $course->get_passing_condition();
2139 }*/
2140
2141 /**
2142 * Check if all items in course completed.
2143 *
2144 * @return boolean
2145 * @author Nhamdv <email@email.com>
2146 */
2147 public function is_completed_all_items( $course_id ) {
2148 $course = learn_press_get_course( $course_id );
2149
2150 $course_data = $this->get_course_data( $course_id );
2151
2152 $course_results = $course_data->get_result();
2153
2154 if ( ! isset( $course_results['completed_items'] ) ) {
2155 return false;
2156 }
2157
2158 return $course_results['completed_items'] >= $course->count_items();
2159 }
2160
2161 public function get_role() {
2162 return $this->is_admin() ? 'admin' : ( $this->is_instructor() ? 'instructor' : 'user' );
2163 }
2164
2165 /**
2166 * Get user course's grade.
2167 * Possible values:
2168 * + passed User has finished and passed course.
2169 * + failed User has finished but failed.
2170 * + in-progress User still is learning course.
2171 *
2172 * @param $course_id
2173 *
2174 * @return string|bool
2175 */
2176 public function get_course_grade( $course_id ) {
2177 $grade = false;
2178 $course_data = $this->get_course_data( $course_id );
2179
2180 if ( $course_data ) {
2181 $grade = $course_data->get_status( 'graduation' );
2182 }
2183
2184 return apply_filters( 'learn-press/user-course-grade', $grade, $this->get_id(), $course_id );
2185 }
2186
2187 /**
2188 * Check if user is a GUEST by checking the meta _lp_temp_user is exists.
2189 *
2190 * @return bool
2191 */
2192 public function is_guest(): bool {
2193 return ! $this->get_id() || ! get_user_by( 'id', $this->get_id() );
2194 }
2195
2196 /**
2197 * Check if user can edit a post.
2198 *
2199 * @param int $post_id
2200 *
2201 * @return bool
2202 */
2203 public function can_edit( int $post_id ): bool {
2204 if ( $this->get_id() !== get_current_user_id() ) {
2205 return false;
2206 }
2207
2208 return current_user_can( 'edit_post', $post_id );
2209 }
2210
2211 /**
2212 * Get email of user
2213 *
2214 * @return string
2215 */
2216 public function get_email(): string {
2217 return $this->get_data( 'email', '' );
2218 }
2219
2220 /**
2221 * Return user_login of the user.
2222 *
2223 * @return string
2224 */
2225 public function get_username(): string {
2226 return $this->get_data( 'user_login', '' );
2227 }
2228
2229 /**
2230 * Return user bio information.
2231 *
2232 * @return string
2233 */
2234 public function get_description(): string {
2235 return $this->get_data( 'description', '' );
2236 }
2237
2238 /**
2239 * Return user first name.
2240 *
2241 * @return string
2242 */
2243 public function get_first_name(): string {
2244 return $this->get_data( 'first_name', '' );
2245 }
2246
2247 /**
2248 * Return user last name.
2249 *
2250 * @return string
2251 */
2252 public function get_last_name(): string {
2253 return $this->get_data( 'last_name', '' );
2254 }
2255
2256 /**
2257 * Return user nickname.
2258 *
2259 * @return string
2260 */
2261 public function get_nickname(): string {
2262 return $this->get_data( 'nickname', '' );
2263 }
2264
2265 /**
2266 * Return user display name.
2267 *
2268 * @return string
2269 */
2270 public function get_display_name(): string {
2271 return $this->get_data( 'display_name', '' );
2272 }
2273 }
2274 }
2275