map_to_object( $data ); } if ( is_null( $this->meta_data ) ) { $this->meta_data = new stdClass(); } } /** * Map array, object data to UserItemModel. * Use for data get from database. * * @param array|object|mixed $data * * @return UserModel */ public function map_to_object( $data ): UserModel { foreach ( $data as $key => $value ) { if ( property_exists( $this, $key ) ) { $this->{$key} = $value; } } return $this; } /** * Get course by ID * * @param int $user_id * @param bool $check_cache * * @return false|static */ public static function find( int $user_id, bool $check_cache = false ) { $filter_user = new UserFilter(); $filter_user->ID = $user_id; $key_cache = "userModel/find/id/{$user_id}"; $lp_course_cache = new LP_Cache(); // Check cache if ( $check_cache ) { $user_model = $lp_course_cache->get_cache( $key_cache ); if ( $user_model instanceof UserModel ) { return $user_model; } } // Query database no cache. $user_model = self::get_user_model_from_db( $filter_user ); // Set cache if ( $user_model instanceof UserModel ) { $lp_course_cache->set_cache( $key_cache, $user_model ); } return $user_model; } /** * Get course from database. * If not exists, return false. * If exists, return CoursePostModel. * * @param UserFilter $filter * * @return UserModel|false|static * @since 4.2.6.9 * @version 1.0.1 */ public static function get_user_model_from_db( UserFilter $filter ) { $lp_user_db = UserDB::getInstance(); $user_model = false; try { $filter->only_fields = [ 'ID', 'user_nicename', 'user_login', 'user_email', 'display_name' ]; $lp_user_db->get_query_single_row( $filter ); $query_single_row = $lp_user_db->get_users( $filter ); $user_rs = $lp_user_db->wpdb->get_row( $query_single_row ); if ( $user_rs instanceof stdClass ) { $user_model = new UserModel( $user_rs ); } } catch ( Throwable $e ) { error_log( __METHOD__ . ': ' . $e->getMessage() ); } return $user_model; } /** * Get all meta_data, all keys of a user it * * @return stdClass|null * @throws Exception */ public function get_all_metadata() { } /** * Get meta value by key. * * @param string $key * @param mixed $default_value * * @return false|mixed */ public function get_meta_value_by_key( string $key, $default_value = false ) { if ( $this->meta_data instanceof stdClass && isset( $this->meta_data->{$key} ) ) { return $this->meta_data->{$key}; } $value = get_user_meta( $this->ID, $key, true ); if ( empty( $value ) ) { $value = $default_value; } $this->meta_data->{$key} = $value; return $value; } /** * Set meta value by key. * * @param string $key * @param $value * * @return void * @since 4.2.7.2 * @version 1.0.0 */ public function set_meta_value_by_key( string $key, $value ) { $this->meta_data->{$key} = $value; update_user_meta( $this->ID, $key, $value ); } /** * Retrieve the pretty slug used instead of user_name. * * This value is used to build links such as instructor links and user profile links. * If a pretty slug has not been generated yet, it falls back to user_name when * $fallback_to_username is true. * * @param bool $fallback_to_username Whether to fall back to username if no pretty slug exists. * * @return string */ /*public function get_pretty_slug( bool $fallback_to_username = true ): string { $slug = sanitize_title( (string) $this->get_meta_value_by_key( self::META_KEY_USER_SLUG, '' ) ); if ( '' !== $slug || ! $fallback_to_username ) { return $slug; } return $this->get_username(); }*/ /** * Get slug link of user. * Get from column user_nicename of table wp_users * * @return string * @since 4.3.6 * @version 1.0.0 */ public function get_slug_link(): string { return (string) $this->user_nicename; } /** * Update pretty slug manually. * * @param string $slug * * @return string|WP_Error * @since 4.3.4 * @version 1.0.1 */ public function update_user_nicename( string $slug ) { try { $slug = sanitize_title( wp_unslash( $slug ) ); if ( empty( $slug ) ) { throw new Exception( __( 'Cannot create a user with an empty nicename.' ) ); } elseif ( mb_strlen( $slug ) > 50 ) { throw new Exception( __( 'Nicename may not be longer than 50 characters.' ) ); } $userModelFind = UserService::instance()->get_user_by_slug_link( $slug ); // If not found any user with the slug, or found user is current user, update slug, else throw error. if ( ! $userModelFind ) { $this->user_nicename = $slug; $this->save(); } elseif ( $userModelFind->get_id() !== $this->get_id() ) { // Found another user with the slug, throw error. throw new Exception( sprintf( /* translators: 1: user slug */ esc_html__( 'This user slug "%s" already exists.', 'learnpress' ), $slug ) ); } } catch ( Throwable $e ) { return new WP_Error( 'lp_user_slug_update_failed', $e->getMessage() ); } return $slug; } /** * Get upload profile src. * * @return string */ public function get_image_url(): string { if ( ! empty( $this->image_url ) ) { return $this->image_url; } $profile_picture = $this->get_meta_value_by_key( self::META_KEY_IMAGE, '' ); if ( ! empty( $profile_picture ) ) { // Check if hase slug / at the beginning of the path, if not add it. $slash = substr( $profile_picture, 0, 1 ) === '/' ? '' : '/'; $profile_picture = $slash . $profile_picture; // End check. $upload = learn_press_user_profile_picture_upload_dir(); $file_path = $upload['basedir'] . $profile_picture; if ( file_exists( $file_path ) ) { $this->image_url = $upload['baseurl'] . $profile_picture; } else { // For remote url. $this->image_url = $profile_picture; } } return $this->image_url; } /** * Get upload cover image src. * * @return string * @since 4.2.7.2 * @version 1.0.0 */ public function get_cover_image_url(): string { $cover_image = $this->get_meta_value_by_key( self::META_KEY_COVER_IMAGE, '' ); if ( ! empty( $cover_image ) ) { // Check if hase slug / at the beginning of the path, if not add it. $slash = substr( $cover_image, 0, 1 ) === '/' ? '' : '/'; $cover_image = $slash . $cover_image; // End check. $upload = learn_press_user_profile_picture_upload_dir(); $file_path = $upload['basedir'] . $cover_image; if ( file_exists( $file_path ) ) { return $upload['baseurl'] . $cover_image; } else { // For remote url. return $cover_image; } } return ''; } /** * Set cover image url. * * @param string $url * * @return void * @since 4.2.7.2 * @version 1.0.0 */ public function set_cover_image_url( string $url ) { $this->set_meta_value_by_key( self::META_KEY_COVER_IMAGE, $url ); } /** * Delete cover image. * * @return void * @since 4.2.7.2 * @version 1.0.0 */ public function delete_cover_image() { $upload_dir = learn_press_user_profile_picture_upload_dir(); // Delete old image if exists $image_path = $this->get_meta_value_by_key( UserModel::META_KEY_COVER_IMAGE, '' ); if ( $image_path ) { $path = $upload_dir['basedir'] . '/' . $image_path; if ( file_exists( $path ) ) { LP_WP_Filesystem::instance()->unlink( $path ); } } // Save empty string to database. $this->set_cover_image_url( '' ); } /** * Get display name * * Hook from function get_the_author_meta of WP * * @return string * @uses get_the_author_meta * @version 1.0.1 * @since 4.2.7 */ public function get_display_name(): string { return apply_filters( 'get_the_author_display_name', $this->display_name, $this->get_id(), $this->get_id() ); } /** * Get url instructor. * * @move from LP_User * @return string * @version 1.0.1 * @since 4.2.3 */ public function get_url_instructor(): string { $single_instructor_link = ''; try { $user_name = $this->get_slug_link(); $single_instructor_page_id = learn_press_get_page_id( 'single_instructor' ); if ( ! $single_instructor_page_id ) { return $single_instructor_link; } $single_instructor_link = trailingslashit( trailingslashit( get_page_link( $single_instructor_page_id ) ) . $user_name ); } catch ( Throwable $e ) { error_log( __METHOD__ . ': ' . $e->getMessage() ); } return $single_instructor_link; } /** * Get profile avatar url * 1. Get upload avatar src * 2. If not exists, get form Gravatar * 3. If not exists, get default image * * @return string * @since 4.2.7.2 * @version 1.0.1 */ public function get_avatar_url(): string { $avatar_url = $this->get_upload_avatar_src(); if ( empty( $avatar_url ) ) { // Get form Gravatar. $args = learn_press_get_avatar_thumb_size(); $args = apply_filters( 'learn-press/gravatar/args', $args ); $avatar_url = get_avatar_url( $this->get_id(), $args ); // If not exists, get default avatar. if ( empty( $avatar_url ) ) { $avatar_url = LP_PLUGIN_URL . 'assets/images/avatar-default.png'; } } return $avatar_url; } /** * Get upload avatar src. * * @return string * @since 4.2.7.2 * @version 1.0.0 * @move from get_upload_profile_src method on LP_Profile class */ public function get_upload_avatar_src(): string { $uploaded_avatar_src = ''; $profile_picture = $this->get_meta_value_by_key( self::META_KEY_IMAGE, '' ); if ( $profile_picture ) { // Check if hase slug / at the beginning of the path, if not, add it. $slash = substr( $profile_picture, 0, 1 ) === '/' ? '' : '/'; $profile_picture = $slash . $profile_picture; // End check. $upload = learn_press_user_profile_picture_upload_dir(); $file_path = $upload['basedir'] . $profile_picture; if ( file_exists( $file_path ) ) { $uploaded_avatar_src = $upload['baseurl'] . $profile_picture; } } return apply_filters( 'learn-press/user/upload-avatar-src', $uploaded_avatar_src, $this ); } /** * Get links socials of use on Profile page * Icon is svg * * @move from LP_Abstract_User * @return array * @since 4.2.3 * @version 1.0.2 */ public function get_profile_social(): array { $socials = array(); $extra_info = learn_press_get_user_extra_profile_info( $this->get_id() ); if ( $extra_info ) { foreach ( $extra_info as $k => $v ) { if ( empty( $v ) ) { continue; } switch ( $k ) { case 'facebook': $i = ''; break; case 'twitter': $i = ''; break; case 'linkedin': $i = ''; break; case 'youtube': $i = ''; break; default: $i = sprintf( '', esc_attr( $k ) ); } $icon = apply_filters( 'learn-press/user-profile-social-icon', $i, $k, $this->get_id(), $this ); $socials[ $k ] = sprintf( '%s', esc_url_raw( $v ), $icon ); } } return apply_filters( 'learn-press/user-profile-socials', $socials, $this->get_id(), $this ); } /** * Update data to database. * * If user_item_id is empty, insert new data, else update data. * * @throws Exception * @since 4.2.5 * @version 1.0.1 */ public function save( bool $force_save = false ) { $data = get_object_vars( $this ); // Check if exists user id. if ( empty( $this->ID ) ) { // Insert data. unset( $data['ID'] ); $user_id = wp_insert_user( $data ); } else { // Update data. if ( ! $force_save ) { if ( ! current_user_can( 'edit_user', $this->get_id() ) ) { throw new Exception( __( 'Sorry, you are not allowed to edit this user.' ) ); } } $user_id = wp_update_user( $data ); } if ( is_wp_error( $user_id ) ) { throw new Exception( $user_id->get_error_message() ); } else { $this->ID = $user_id; } $this->clean_caches(); } /** * Clean caches. * * @return void */ public function clean_caches() { // Clear cache. $key_cache = "userModel/find/id/{$this->get_id()}"; $lp_course_cache = new LP_Cache(); $lp_course_cache->clear( $key_cache ); } /** * @return int */ public function get_id(): int { return (int) $this->ID; } /** * Get description of user. * * @return string * @since 4.2.6.9 * @version 1.0.1 */ public function get_description(): string { return get_the_author_meta( 'description', $this->get_id() ); } /** * Get email of user. * * @return string * @since 4.2.7.4 * @version 1.0.0 */ public function get_email(): string { return $this->user_email ?? ''; } /** * Get username of user. * * @return string * @since 4.2.7.4 * @version 1.0.0 */ public function get_username(): string { return $this->user_login ?? ''; } /** * Get statistic info of instructor user * * @param array $params * * @return array * @since 4.1.6 * @version 1.0.7 */ public function get_instructor_statistic( array $params = [] ): array { $statistic = array( 'total_course' => 0, 'published_course' => 0, 'pending_course' => 0, 'total_student' => 0, 'student_completed' => 0, 'student_in_progress' => 0, ); try { $key_cache_first = "instructor/{$this->get_id()}/statistic"; $statistic_cache = LP_Cache::cache_load_first( 'get', $key_cache_first ); if ( $statistic_cache !== false ) { return $statistic_cache; } $user_id = $this->get_id(); $lp_user_items_db = LP_User_Items_DB::getInstance(); $courseJsonDB = CourseJsonDB::getInstance(); // Count total user completed course of author $filter_course = new CourseJsonFilter(); $filter_course->only_fields = array( 'ID' ); $filter_course->post_author = $user_id; $filter_course->post_status = [ 'publish', 'private' ]; $filter_course->return_string_query = true; $query_courses_str = $courseJsonDB::getInstance()->get_courses( $filter_course ); $filter_count_users = new LP_User_Items_Filter(); $filter_count_users->item_type = LP_COURSE_CPT; $filter_count_users->where[] = "AND item_id IN ({$query_courses_str})"; $count_student_has_status = $lp_user_items_db->count_status_by_items( $filter_count_users ); // Count total user in progress course of author // Get total users attend course of author $filter_count_users = $lp_user_items_db->count_user_attend_courses_of_author( $user_id ); $count_users_attend_courses_of_author = $lp_user_items_db->get_user_courses( $filter_count_users ); // Get total courses publish of author $filter_count_courses = $courseJsonDB->count_courses_of_author( $user_id, [ 'publish' ] ); $total_courses_publish_of_author = $courseJsonDB->get_courses( $filter_count_courses ); // Get total courses of author $filter_count_courses = $courseJsonDB->count_courses_of_author( $user_id ); $total_courses_of_author = $courseJsonDB->get_courses( $filter_count_courses ); // Get total courses pending of author $filter_count_courses = $courseJsonDB->count_courses_of_author( $user_id, [ 'pending' ] ); $total_courses_pending_of_author = $courseJsonDB->get_courses( $filter_count_courses ); $statistic['total_course'] = $total_courses_of_author; $statistic['published_course'] = $total_courses_publish_of_author; $statistic['pending_course'] = $total_courses_pending_of_author; $statistic['total_student'] = $count_users_attend_courses_of_author; $statistic['student_completed'] = $count_student_has_status->{LP_COURSE_FINISHED} ?? 0; $statistic['student_in_progress'] = $count_student_has_status->{LP_COURSE_GRADUATION_IN_PROGRESS} ?? 0; $statistic = apply_filters( 'lp/profile/instructor/statistic', $statistic, $this ); // Set cache first. LP_Cache::cache_load_first( 'set', $key_cache_first, $statistic ); } catch ( Throwable $e ) { LP_Debug::error_log( $e ); } return $statistic; } /** * Get statistic info of student user * * @return array * @since 4.1.6 * @version 1.0.0 */ public function get_student_statistic(): array { $statistic = array( 'enrolled_courses' => 0, 'in_progress_course' => 0, 'finished_courses' => 0, 'passed_courses' => 0, 'failed_courses' => 0, ); try { $user_id = $this->get_id(); $lp_user_items_db = LP_User_Items_DB::getInstance(); // Count status $filter = new LP_User_Items_Filter(); $filter->user_id = $user_id; $count_status = $lp_user_items_db->count_status_by_items( $filter ); $total_courses_enrolled = intval( $count_status->{LP_COURSE_PURCHASED} ?? 0 ) + intval( $count_status->{LP_COURSE_ENROLLED} ?? 0 ) + intval( $count_status->{LP_COURSE_FINISHED} ?? 0 ); $statistic['enrolled_courses'] = $total_courses_enrolled; $statistic['in_progress_course'] = $count_status->{LP_COURSE_GRADUATION_IN_PROGRESS} ?? 0; $statistic['finished_courses'] = $count_status->{LP_COURSE_FINISHED} ?? 0; $statistic['passed_courses'] = $count_status->{LP_COURSE_GRADUATION_PASSED} ?? 0; $statistic['failed_courses'] = $count_status->{LP_COURSE_GRADUATION_FAILED} ?? 0; } catch ( Throwable $e ) { LP_Debug::error_log( $e ); } return apply_filters( 'lp/profile/student/statistic', $statistic, $this ); } /** * Check user is instructor or not. * * @return bool * @since 4.2.7.6 * @version 1.0.1 */ public function is_instructor(): bool { $wp_user = new WP_User( $this ); return user_can( $wp_user, self::ROLE_INSTRUCTOR ) || user_can( $wp_user, self::ROLE_ADMINISTRATOR ); } /** * Get quizzes attend of user. * * @param LP_User_Items_Filter|UserItemsFilter $filter * @param int $total_rows * * @return array|int|string|null * @throws Exception * @since 4.2.8.2 * @version 1.0.1 */ public function get_quizzes_attend( $filter, int &$total_rows = 0 ) { $lp_db_user_items = UserItemsDB::getInstance(); $filter->order_by = 'user_item_id'; $filter->order = 'DESC'; $filter->user_id = $this->get_id(); $filter->item_type = LP_QUIZ_CPT; $filter->ref_type = LP_COURSE_CPT; return $lp_db_user_items->get_user_items( $filter, $total_rows ); } /** * Get roles of user. * * @return array * @since 4.3.6 * @version 1.0.0 */ public function get_roles(): array { $user = new WP_User( $this ); return is_array( $user->roles ) ? $user->roles : []; } }