PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.3.7
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.3.7
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 4.2.1 All 138 releases
learnpress / inc / Models / UserModel.php

UserModel.php in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.3.7, at inc/Models/UserModel.php

802 lines 20.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace LearnPress\Models;
4
5 /**
6 * Class UserModel
7 *
8 * @version 1.0.3
9 * @since 4.2.6.9
10 */
11
12 use Exception;
13 use LearnPress\Databases\Course\CourseJsonDB;
14 use LearnPress\Databases\UserItemsDB;
15 use LearnPress\Filters\Course\CourseJsonFilter;
16 use LearnPress\Filters\UserItemsFilter;
17 use LearnPress\Services\UserService;
18 use LP_Cache;
19 use LP_Debug;
20 use LearnPress\Databases\UserDB;
21 use LearnPress\Filters\UserFilter;
22
23 use LP_User_Items_DB;
24 use LP_User_Items_Filter;
25 use LP_WP_Filesystem;
26 use stdClass;
27 use Throwable;
28 use WP_Error;
29 use WP_User;
30
31 class UserModel {
32 /**
33 * Auto increment, Primary key
34 *
35 * @var int
36 */
37 public $ID = 0;
38 /**
39 * @var string
40 */
41 public $user_login = '';
42 /**
43 * @var string
44 */
45 public $user_nicename;
46 /**
47 * @var string
48 */
49 public $user_email = null;
50 /**
51 * @var string
52 */
53 public $user_url = null;
54 /**
55 * @var string
56 */
57 public $user_register = '';
58 /**
59 * Display name of user.
60 *
61 * @var string
62 */
63 public $display_name = '';
64 /**
65 * @var stdClass all meta data
66 */
67 public $meta_data = null;
68 /**
69 * @var string image url
70 */
71 public $image_url = '';
72
73 // Meta keys
74 const META_KEY_IMAGE = '_lp_profile_picture';
75 const META_KEY_COVER_IMAGE = '_lp_profile_cover_image';
76 const META_KEY_USER_SLUG = '_lp_user_slug';
77 // Roles
78 const ROLE_INSTRUCTOR = LP_TEACHER_ROLE;
79 const ROLE_ADMINISTRATOR = 'administrator';
80
81 /**
82 * If data get from database, map to object.
83 * Else create new object to save data to database.
84 *
85 * @param array|object|mixed $data
86 */
87 public function __construct( $data = null ) {
88 if ( $data ) {
89 $this->map_to_object( $data );
90 }
91
92 if ( is_null( $this->meta_data ) ) {
93 $this->meta_data = new stdClass();
94 }
95 }
96
97 /**
98 * Map array, object data to UserItemModel.
99 * Use for data get from database.
100 *
101 * @param array|object|mixed $data
102 *
103 * @return UserModel
104 */
105 public function map_to_object( $data ): UserModel {
106 foreach ( $data as $key => $value ) {
107 if ( property_exists( $this, $key ) ) {
108 $this->{$key} = $value;
109 }
110 }
111
112 return $this;
113 }
114
115 /**
116 * Get course by ID
117 *
118 * @param int $user_id
119 * @param bool $check_cache
120 *
121 * @return false|static
122 */
123 public static function find( int $user_id, bool $check_cache = false ) {
124 $filter_user = new UserFilter();
125 $filter_user->ID = $user_id;
126 $key_cache = "userModel/find/id/{$user_id}";
127 $lp_course_cache = new LP_Cache();
128
129 // Check cache
130 if ( $check_cache ) {
131 $user_model = $lp_course_cache->get_cache( $key_cache );
132 if ( $user_model instanceof UserModel ) {
133 return $user_model;
134 }
135 }
136
137 // Query database no cache.
138 $user_model = self::get_user_model_from_db( $filter_user );
139
140 // Set cache
141 if ( $user_model instanceof UserModel ) {
142 $lp_course_cache->set_cache( $key_cache, $user_model );
143 }
144
145 return $user_model;
146 }
147
148 /**
149 * Get course from database.
150 * If not exists, return false.
151 * If exists, return CoursePostModel.
152 *
153 * @param UserFilter $filter
154 *
155 * @return UserModel|false|static
156 * @since 4.2.6.9
157 * @version 1.0.1
158 */
159 public static function get_user_model_from_db( UserFilter $filter ) {
160 $lp_user_db = UserDB::getInstance();
161 $user_model = false;
162
163 try {
164 $filter->only_fields = [ 'ID', 'user_nicename', 'user_login', 'user_email', 'display_name' ];
165 $lp_user_db->get_query_single_row( $filter );
166 $query_single_row = $lp_user_db->get_users( $filter );
167 $user_rs = $lp_user_db->wpdb->get_row( $query_single_row );
168 if ( $user_rs instanceof stdClass ) {
169 $user_model = new UserModel( $user_rs );
170 }
171 } catch ( Throwable $e ) {
172 error_log( __METHOD__ . ': ' . $e->getMessage() );
173 }
174
175 return $user_model;
176 }
177
178 /**
179 * Get all meta_data, all keys of a user it
180 *
181 * @return stdClass|null
182 * @throws Exception
183 */
184 public function get_all_metadata() {
185 }
186
187 /**
188 * Get meta value by key.
189 *
190 * @param string $key
191 * @param mixed $default_value
192 *
193 * @return false|mixed
194 */
195 public function get_meta_value_by_key( string $key, $default_value = false ) {
196 if ( $this->meta_data instanceof stdClass && isset( $this->meta_data->{$key} ) ) {
197 return $this->meta_data->{$key};
198 }
199
200 $value = get_user_meta( $this->ID, $key, true );
201 if ( empty( $value ) ) {
202 $value = $default_value;
203 }
204
205 $this->meta_data->{$key} = $value;
206
207 return $value;
208 }
209
210 /**
211 * Set meta value by key.
212 *
213 * @param string $key
214 * @param $value
215 *
216 * @return void
217 * @since 4.2.7.2
218 * @version 1.0.0
219 */
220 public function set_meta_value_by_key( string $key, $value ) {
221 $this->meta_data->{$key} = $value;
222 update_user_meta( $this->ID, $key, $value );
223 }
224
225 /**
226 * Retrieve the pretty slug used instead of user_name.
227 *
228 * This value is used to build links such as instructor links and user profile links.
229 * If a pretty slug has not been generated yet, it falls back to user_name when
230 * $fallback_to_username is true.
231 *
232 * @param bool $fallback_to_username Whether to fall back to username if no pretty slug exists.
233 *
234 * @return string
235 */
236 /*public function get_pretty_slug( bool $fallback_to_username = true ): string {
237 $slug = sanitize_title( (string) $this->get_meta_value_by_key( self::META_KEY_USER_SLUG, '' ) );
238
239 if ( '' !== $slug || ! $fallback_to_username ) {
240 return $slug;
241 }
242
243 return $this->get_username();
244 }*/
245
246 /**
247 * Get slug link of user.
248 * Get from column user_nicename of table wp_users
249 *
250 * @return string
251 * @since 4.3.6
252 * @version 1.0.0
253 */
254 public function get_slug_link(): string {
255 return (string) $this->user_nicename;
256 }
257
258 /**
259 * Update pretty slug manually.
260 *
261 * @param string $slug
262 *
263 * @return string|WP_Error
264 * @since 4.3.4
265 * @version 1.0.1
266 */
267 public function update_user_nicename( string $slug ) {
268 try {
269 $slug = sanitize_title( wp_unslash( $slug ) );
270
271 if ( empty( $slug ) ) {
272 throw new Exception( __( 'Cannot create a user with an empty nicename.' ) );
273 } elseif ( mb_strlen( $slug ) > 50 ) {
274 throw new Exception( __( 'Nicename may not be longer than 50 characters.' ) );
275 }
276
277 $userModelFind = UserService::instance()->get_user_by_slug_link( $slug );
278 // If not found any user with the slug, or found user is current user, update slug, else throw error.
279 if ( ! $userModelFind ) {
280 $this->user_nicename = $slug;
281 $this->save();
282 } elseif ( $userModelFind->get_id() !== $this->get_id() ) {
283 // Found another user with the slug, throw error.
284 throw new Exception(
285 sprintf(
286 /* translators: 1: user slug */
287 esc_html__( 'This user slug "%s" already exists.', 'learnpress' ),
288 $slug
289 )
290 );
291 }
292 } catch ( Throwable $e ) {
293 return new WP_Error( 'lp_user_slug_update_failed', $e->getMessage() );
294 }
295
296 return $slug;
297 }
298
299 /**
300 * Get upload profile src.
301 *
302 * @return string
303 */
304 public function get_image_url(): string {
305 if ( ! empty( $this->image_url ) ) {
306 return $this->image_url;
307 }
308
309 $profile_picture = $this->get_meta_value_by_key( self::META_KEY_IMAGE, '' );
310 if ( ! empty( $profile_picture ) ) {
311 // Check if hase slug / at the beginning of the path, if not add it.
312 $slash = substr( $profile_picture, 0, 1 ) === '/' ? '' : '/';
313 $profile_picture = $slash . $profile_picture;
314 // End check.
315 $upload = learn_press_user_profile_picture_upload_dir();
316 $file_path = $upload['basedir'] . $profile_picture;
317
318 if ( file_exists( $file_path ) ) {
319 $this->image_url = $upload['baseurl'] . $profile_picture;
320 } else { // For remote url.
321 $this->image_url = $profile_picture;
322 }
323 }
324
325 return $this->image_url;
326 }
327
328 /**
329 * Get upload cover image src.
330 *
331 * @return string
332 * @since 4.2.7.2
333 * @version 1.0.0
334 */
335 public function get_cover_image_url(): string {
336 $cover_image = $this->get_meta_value_by_key( self::META_KEY_COVER_IMAGE, '' );
337 if ( ! empty( $cover_image ) ) {
338 // Check if hase slug / at the beginning of the path, if not add it.
339 $slash = substr( $cover_image, 0, 1 ) === '/' ? '' : '/';
340 $cover_image = $slash . $cover_image;
341 // End check.
342 $upload = learn_press_user_profile_picture_upload_dir();
343 $file_path = $upload['basedir'] . $cover_image;
344
345 if ( file_exists( $file_path ) ) {
346 return $upload['baseurl'] . $cover_image;
347 } else { // For remote url.
348 return $cover_image;
349 }
350 }
351
352 return '';
353 }
354
355 /**
356 * Set cover image url.
357 *
358 * @param string $url
359 *
360 * @return void
361 * @since 4.2.7.2
362 * @version 1.0.0
363 */
364 public function set_cover_image_url( string $url ) {
365 $this->set_meta_value_by_key( self::META_KEY_COVER_IMAGE, $url );
366 }
367
368 /**
369 * Delete cover image.
370 *
371 * @return void
372 * @since 4.2.7.2
373 * @version 1.0.0
374 */
375 public function delete_cover_image() {
376 $upload_dir = learn_press_user_profile_picture_upload_dir();
377
378 // Delete old image if exists
379 $image_path = $this->get_meta_value_by_key( UserModel::META_KEY_COVER_IMAGE, '' );
380 if ( $image_path ) {
381 $path = $upload_dir['basedir'] . '/' . $image_path;
382
383 if ( file_exists( $path ) ) {
384 LP_WP_Filesystem::instance()->unlink( $path );
385 }
386 }
387
388 // Save empty string to database.
389 $this->set_cover_image_url( '' );
390 }
391
392 /**
393 * Get display name
394 *
395 * Hook from function get_the_author_meta of WP
396 *
397 * @return string
398 * @uses get_the_author_meta
399 * @version 1.0.1
400 * @since 4.2.7
401 */
402 public function get_display_name(): string {
403 return apply_filters(
404 'get_the_author_display_name',
405 $this->display_name,
406 $this->get_id(),
407 $this->get_id()
408 );
409 }
410
411 /**
412 * Get url instructor.
413 *
414 * @move from LP_User
415 * @return string
416 * @version 1.0.1
417 * @since 4.2.3
418 */
419 public function get_url_instructor(): string {
420
421 $single_instructor_link = '';
422
423 try {
424 $user_name = $this->get_slug_link();
425 $single_instructor_page_id = learn_press_get_page_id( 'single_instructor' );
426 if ( ! $single_instructor_page_id ) {
427 return $single_instructor_link;
428 }
429 $single_instructor_link = trailingslashit(
430 trailingslashit( get_page_link( $single_instructor_page_id ) ) . $user_name
431 );
432 } catch ( Throwable $e ) {
433 error_log( __METHOD__ . ': ' . $e->getMessage() );
434 }
435
436 return $single_instructor_link;
437 }
438
439 /**
440 * Get profile avatar url
441 * 1. Get upload avatar src
442 * 2. If not exists, get form Gravatar
443 * 3. If not exists, get default image
444 *
445 * @return string
446 * @since 4.2.7.2
447 * @version 1.0.1
448 */
449 public function get_avatar_url(): string {
450 $avatar_url = $this->get_upload_avatar_src();
451 if ( empty( $avatar_url ) ) {
452 // Get form Gravatar.
453 $args = learn_press_get_avatar_thumb_size();
454 $args = apply_filters( 'learn-press/gravatar/args', $args );
455 $avatar_url = get_avatar_url( $this->get_id(), $args );
456 // If not exists, get default avatar.
457 if ( empty( $avatar_url ) ) {
458 $avatar_url = LP_PLUGIN_URL . 'assets/images/avatar-default.png';
459 }
460 }
461
462 return $avatar_url;
463 }
464
465 /**
466 * Get upload avatar src.
467 *
468 * @return string
469 * @since 4.2.7.2
470 * @version 1.0.0
471 * @move from get_upload_profile_src method on LP_Profile class
472 */
473 public function get_upload_avatar_src(): string {
474 $uploaded_avatar_src = '';
475 $profile_picture = $this->get_meta_value_by_key( self::META_KEY_IMAGE, '' );
476
477 if ( $profile_picture ) {
478 // Check if hase slug / at the beginning of the path, if not, add it.
479 $slash = substr( $profile_picture, 0, 1 ) === '/' ? '' : '/';
480 $profile_picture = $slash . $profile_picture;
481 // End check.
482 $upload = learn_press_user_profile_picture_upload_dir();
483 $file_path = $upload['basedir'] . $profile_picture;
484
485 if ( file_exists( $file_path ) ) {
486 $uploaded_avatar_src = $upload['baseurl'] . $profile_picture;
487 }
488 }
489
490 return apply_filters( 'learn-press/user/upload-avatar-src', $uploaded_avatar_src, $this );
491 }
492
493 /**
494 * Get links socials of use on Profile page
495 * Icon is svg
496 *
497 * @move from LP_Abstract_User
498 * @return array
499 * @since 4.2.3
500 * @version 1.0.2
501 */
502 public function get_profile_social(): array {
503 $socials = array();
504 $extra_info = learn_press_get_user_extra_profile_info( $this->get_id() );
505
506 if ( $extra_info ) {
507 foreach ( $extra_info as $k => $v ) {
508 if ( empty( $v ) ) {
509 continue;
510 }
511
512 switch ( $k ) {
513 case 'facebook':
514 $i = '<i class="lp-user-ico lp-icon-facebook"></i>';
515 break;
516 case 'twitter':
517 $i = '<i class="lp-user-ico lp-icon-twitter"></i>';
518 break;
519 case 'linkedin':
520 $i = '<i class="lp-user-ico lp-icon-linkedin"></i>';
521 break;
522 case 'youtube':
523 $i = '<i class="lp-user-ico lp-icon-youtube-play"></i>';
524 break;
525 default:
526 $i = sprintf(
527 '<i class="lp-user-ico lp-icon-%s"></i>',
528 esc_attr( $k )
529 );
530 }
531
532 $icon = apply_filters(
533 'learn-press/user-profile-social-icon',
534 $i,
535 $k,
536 $this->get_id(),
537 $this
538 );
539 $socials[ $k ] = sprintf(
540 '<a href="%s">%s</a>',
541 esc_url_raw( $v ),
542 $icon
543 );
544 }
545 }
546
547 return apply_filters( 'learn-press/user-profile-socials', $socials, $this->get_id(), $this );
548 }
549
550 /**
551 * Update data to database.
552 *
553 * If user_item_id is empty, insert new data, else update data.
554 *
555 * @throws Exception
556 * @since 4.2.5
557 * @version 1.0.1
558 */
559 public function save( bool $force_save = false ) {
560 $data = get_object_vars( $this );
561
562 // Check if exists user id.
563 if ( empty( $this->ID ) ) { // Insert data.
564 unset( $data['ID'] );
565 $user_id = wp_insert_user( $data );
566 } else { // Update data.
567 if ( ! $force_save ) {
568 if ( ! current_user_can( 'edit_user', $this->get_id() ) ) {
569 throw new Exception( __( 'Sorry, you are not allowed to edit this user.' ) );
570 }
571 }
572
573 $user_id = wp_update_user( $data );
574 }
575
576 if ( is_wp_error( $user_id ) ) {
577 throw new Exception( $user_id->get_error_message() );
578 } else {
579 $this->ID = $user_id;
580 }
581
582 $this->clean_caches();
583 }
584
585 /**
586 * Clean caches.
587 *
588 * @return void
589 */
590 public function clean_caches() {
591 // Clear cache.
592 $key_cache = "userModel/find/id/{$this->get_id()}";
593 $lp_course_cache = new LP_Cache();
594 $lp_course_cache->clear( $key_cache );
595 }
596
597 /**
598 * @return int
599 */
600 public function get_id(): int {
601 return (int) $this->ID;
602 }
603
604 /**
605 * Get description of user.
606 *
607 * @return string
608 * @since 4.2.6.9
609 * @version 1.0.1
610 */
611 public function get_description(): string {
612 return get_the_author_meta( 'description', $this->get_id() );
613 }
614
615 /**
616 * Get email of user.
617 *
618 * @return string
619 * @since 4.2.7.4
620 * @version 1.0.0
621 */
622 public function get_email(): string {
623 return $this->user_email ?? '';
624 }
625
626 /**
627 * Get username of user.
628 *
629 * @return string
630 * @since 4.2.7.4
631 * @version 1.0.0
632 */
633 public function get_username(): string {
634 return $this->user_login ?? '';
635 }
636
637 /**
638 * Get statistic info of instructor user
639 *
640 * @param array $params
641 *
642 * @return array
643 * @since 4.1.6
644 * @version 1.0.7
645 */
646 public function get_instructor_statistic( array $params = [] ): array {
647 $statistic = array(
648 'total_course' => 0,
649 'published_course' => 0,
650 'pending_course' => 0,
651 'total_student' => 0,
652 'student_completed' => 0,
653 'student_in_progress' => 0,
654 );
655
656 try {
657 $key_cache_first = "instructor/{$this->get_id()}/statistic";
658 $statistic_cache = LP_Cache::cache_load_first( 'get', $key_cache_first );
659 if ( $statistic_cache !== false ) {
660 return $statistic_cache;
661 }
662
663 $user_id = $this->get_id();
664 $lp_user_items_db = LP_User_Items_DB::getInstance();
665 $courseJsonDB = CourseJsonDB::getInstance();
666
667 // Count total user completed course of author
668 $filter_course = new CourseJsonFilter();
669 $filter_course->only_fields = array( 'ID' );
670 $filter_course->post_author = $user_id;
671 $filter_course->post_status = [ 'publish', 'private' ];
672 $filter_course->return_string_query = true;
673 $query_courses_str = $courseJsonDB::getInstance()->get_courses( $filter_course );
674
675 $filter_count_users = new LP_User_Items_Filter();
676 $filter_count_users->item_type = LP_COURSE_CPT;
677 $filter_count_users->where[] = "AND item_id IN ({$query_courses_str})";
678 $count_student_has_status = $lp_user_items_db->count_status_by_items( $filter_count_users );
679 // Count total user in progress course of author
680
681 // Get total users attend course of author
682 $filter_count_users = $lp_user_items_db->count_user_attend_courses_of_author( $user_id );
683 $count_users_attend_courses_of_author = $lp_user_items_db->get_user_courses( $filter_count_users );
684
685 // Get total courses publish of author
686 $filter_count_courses = $courseJsonDB->count_courses_of_author( $user_id, [ 'publish' ] );
687 $total_courses_publish_of_author = $courseJsonDB->get_courses( $filter_count_courses );
688
689 // Get total courses of author
690 $filter_count_courses = $courseJsonDB->count_courses_of_author( $user_id );
691 $total_courses_of_author = $courseJsonDB->get_courses( $filter_count_courses );
692
693 // Get total courses pending of author
694 $filter_count_courses = $courseJsonDB->count_courses_of_author( $user_id, [ 'pending' ] );
695 $total_courses_pending_of_author = $courseJsonDB->get_courses( $filter_count_courses );
696
697 $statistic['total_course'] = $total_courses_of_author;
698 $statistic['published_course'] = $total_courses_publish_of_author;
699 $statistic['pending_course'] = $total_courses_pending_of_author;
700 $statistic['total_student'] = $count_users_attend_courses_of_author;
701 $statistic['student_completed'] = $count_student_has_status->{LP_COURSE_FINISHED} ?? 0;
702 $statistic['student_in_progress'] = $count_student_has_status->{LP_COURSE_GRADUATION_IN_PROGRESS} ?? 0;
703
704 $statistic = apply_filters( 'lp/profile/instructor/statistic', $statistic, $this );
705
706 // Set cache first.
707 LP_Cache::cache_load_first( 'set', $key_cache_first, $statistic );
708 } catch ( Throwable $e ) {
709 LP_Debug::error_log( $e );
710 }
711
712 return $statistic;
713 }
714
715 /**
716 * Get statistic info of student user
717 *
718 * @return array
719 * @since 4.1.6
720 * @version 1.0.0
721 */
722 public function get_student_statistic(): array {
723 $statistic = array(
724 'enrolled_courses' => 0,
725 'in_progress_course' => 0,
726 'finished_courses' => 0,
727 'passed_courses' => 0,
728 'failed_courses' => 0,
729 );
730
731 try {
732 $user_id = $this->get_id();
733 $lp_user_items_db = LP_User_Items_DB::getInstance();
734
735 // Count status
736 $filter = new LP_User_Items_Filter();
737 $filter->user_id = $user_id;
738 $count_status = $lp_user_items_db->count_status_by_items( $filter );
739 $total_courses_enrolled = intval( $count_status->{LP_COURSE_PURCHASED} ?? 0 )
740 + intval( $count_status->{LP_COURSE_ENROLLED} ?? 0 )
741 + intval( $count_status->{LP_COURSE_FINISHED} ?? 0 );
742
743 $statistic['enrolled_courses'] = $total_courses_enrolled;
744 $statistic['in_progress_course'] = $count_status->{LP_COURSE_GRADUATION_IN_PROGRESS} ?? 0;
745 $statistic['finished_courses'] = $count_status->{LP_COURSE_FINISHED} ?? 0;
746 $statistic['passed_courses'] = $count_status->{LP_COURSE_GRADUATION_PASSED} ?? 0;
747 $statistic['failed_courses'] = $count_status->{LP_COURSE_GRADUATION_FAILED} ?? 0;
748 } catch ( Throwable $e ) {
749 LP_Debug::error_log( $e );
750 }
751
752 return apply_filters( 'lp/profile/student/statistic', $statistic, $this );
753 }
754
755 /**
756 * Check user is instructor or not.
757 *
758 * @return bool
759 * @since 4.2.7.6
760 * @version 1.0.1
761 */
762 public function is_instructor(): bool {
763 $wp_user = new WP_User( $this );
764 return user_can( $wp_user, self::ROLE_INSTRUCTOR )
765 || user_can( $wp_user, self::ROLE_ADMINISTRATOR );
766 }
767
768 /**
769 * Get quizzes attend of user.
770 *
771 * @param LP_User_Items_Filter|UserItemsFilter $filter
772 * @param int $total_rows
773 *
774 * @return array|int|string|null
775 * @throws Exception
776 * @since 4.2.8.2
777 * @version 1.0.1
778 */
779 public function get_quizzes_attend( $filter, int &$total_rows = 0 ) {
780 $lp_db_user_items = UserItemsDB::getInstance();
781 $filter->order_by = 'user_item_id';
782 $filter->order = 'DESC';
783 $filter->user_id = $this->get_id();
784 $filter->item_type = LP_QUIZ_CPT;
785 $filter->ref_type = LP_COURSE_CPT;
786
787 return $lp_db_user_items->get_user_items( $filter, $total_rows );
788 }
789
790 /**
791 * Get roles of user.
792 *
793 * @return array
794 * @since 4.3.6
795 * @version 1.0.0
796 */
797 public function get_roles(): array {
798 $user = new WP_User( $this );
799 return is_array( $user->roles ) ? $user->roles : [];
800 }
801 }
802