'', 'user_login' => '', 'description' => '', 'first_name' => '', 'last_name' => '', 'nickname' => '', 'display_name' => '', 'date_created' => '', 'date_modified' => '', 'role' => '', 'roles' => array(), ); /** * @var LP_User_CURD */ protected $_curd = null; /** * LP_Abstract_User constructor. * * @param int $the_user * @param array $args */ public function __construct( $the_user = 0, $args = array() ) { parent::__construct( $the_user, $args ); $this->_curd = new LP_User_CURD(); if ( is_numeric( $the_user ) && $the_user > 0 ) { $this->set_id( $the_user ); } elseif ( $the_user instanceof self ) { $this->set_id( absint( $the_user->get_id() ) ); } elseif ( ! empty( $the_user->ID ) ) { $this->set_id( absint( $the_user->ID ) ); } if ( $this->get_id() > 0 ) { $this->load(); } } /** * Load user data from curd */ public function load() { $this->_curd->load( $this ); } /** * Get data for a course user has enrolled. * * @param int $course_id . * * @return LP_User_Item_Course|bool * @version 3.1.3 * @editor tungnx * @modify 4.1.3 */ public function get_course_data( int $course_id = 0 ) { $lp_user_items_db = LP_User_Items_DB::getInstance(); try { if ( ! $course_id ) { $course_id = get_the_ID(); } /*if ( $this instanceof LP_User_Guest ) { throw new Exception( 'User is Guest' ); }*/ $filter = new LP_User_Items_Filter(); $filter->item_id = $course_id; $filter->user_id = $this->get_id(); $last_user_course = $lp_user_items_db->get_last_user_course( $filter ); if ( $last_user_course ) { $object_course_data = new LP_User_Item_Course( $last_user_course ); } else { $object_course_data = false; /** * Todo: some themes still not check false, so still use below code.\ * @editor tungnx 4.1.6.9 */ $object_course_data = new LP_User_Item_Course( $course_id ); } } catch ( Throwable $e ) { $object_course_data = false; } return $object_course_data; } /** * Get user course item. * * @param int $item_id * @param int $course_id * @param string $field - Optional. Value of field to return. * * @return LP_User_Item_Quiz|LP_User_Item|bool */ public function get_item_data( $item_id, $course_id, $field = '' ) { $user_item = $this->get_user_item( $item_id, $course_id ); switch ( $field ) { case 'end_time': return $user_item->get_end_time(); } return $user_item; } /** * Get data for a item user started in table user-items * * @param int $item_id * @param int $course_id * * @return LP_User_Item_Quiz|LP_User_Item|bool */ public function get_user_item( $item_id, $course_id ) { $data = false; $course_data = $this->get_course_data( $course_id ); if ( $course_data ) { $data = $course_data->get_item( $item_id ); } return $data; } /** * Return TRUE if user has used function for checking the question. * * @param int $question_id * @param int $quiz_id * @param int $course_id * * @return mixed * @since 3.0.0 */ public function has_checked_question( $question_id, $quiz_id, $course_id = 0 ) { $checked = false; if ( $this->get_quiz_data( $quiz_id, $course_id ) ) { $data = $this->get_quiz_data( $quiz_id, $course_id ); $checked = $data->has_checked_question( $question_id ); } return apply_filters( 'learn-press/user/checked-question', $checked, $question_id, $quiz_id, $course_id, $this->get_id() ); } /** * Magic function to get user data * * @param $key * * @return bool */ public function __get( $key ) { $return = false; if ( strtolower( $key ) !== 'id' ) { _deprecated_argument( __CLASS__ . '::' . $key, '3.0.0' ); } if ( ! empty( $this->user->data->{$key} ) ) { $return = $this->user->data->{$key}; } else { if ( isset( $this->{$key} ) ) { $return = $this->{$key}; } elseif ( strpos( $key, '_lp_' ) === false ) { $key = '_lp_' . $key; $return = get_user_meta( $this->get_id(), $key, true ); if ( ! empty( $value ) ) { $this->$key = $return; } } } return $return; } /** * Check if a course is exists then return it's ID. * Try to get it from global. * * @param int $course_id * @param string $return * * @return bool|false|int|LP_Course */ protected function _get_course( $course_id, $return = 'id' ) { // if $course_id is not passed then try to get it from global if ( ! $course_id && learn_press_is_course() ) { $course_id = get_the_ID(); } // Validate course $course = learn_press_get_course( $course_id ); if ( $course ) { switch ( $return ) { case 'id': return $course_id; case 'object': return $course; } } return false; } /** * * @param int $item_id * @param int $course_id * * @return bool * * @since 3.0.0 */ protected function _verify_course_item( $item_id, $course_id = 0 ) { $course = $this->_get_course( $course_id, 'object' ); if ( false !== $course ) { return $course->has_item( $item_id ) ? $course_id : false; } return false; } /** * Return TRUE if an item has a status. * * @param array $statuses * @param int $item_id * @param int $course_id * * @return mixed * * @since 3.0.0 */ public function has_item_status( $statuses, $item_id, $course_id ) { settype( $statuses, 'array' ); $status = $this->get_item_status( $item_id, $course_id ); //Todo: tungnx //$status = $this->getItemStatus( $item_id, $course_id ); return apply_filters( 'learn-press/user-has-item-status', in_array( $status, $statuses ), $statuses, $item_id, $course_id, $this->get_id() ); } /** * Get all records of an item. * * @param int $item_id * @param int $course_id * @param bool $return_last * * @return bool|mixed */ public function get_item_archive( $item_id, $course_id = 0, $return_last = false ) { $records = LP_Object_Cache::get( 'course-item-' . $this->get_id() . '-' . $course_id . '-' . $item_id, 'lp-user-course-items' ); if ( $records ) { // $records = array_filter( $records ); } if ( $return_last && is_array( $records ) ) { $records = reset( $records ); } return $records; } /** * Count number of rows for an item in user-items * * @param int $item_id * @param int $course_id * * @return int * @editor tungnx * @modify 4.1.3 - comment - not user */ /*public function count_item_archive( $item_id, $course_id = 0 ) { $count = 0; if ( $items = $this->get_item_archive( $item_id, $course_id ) ) { $count = sizeof( $items ); } return $count; }*/ /** * Check quiz can retake? * * @param [type] $quiz_id * @param [type] $course_id * * @return boolean */ public function has_retake_quiz( $quiz_id, $course_id ): bool { $user_quiz = $this->get_item_data( $quiz_id, $course_id ); $flag = false; if ( $user_quiz ) { $retaken = $user_quiz->get_retaken_count(); $retake_config = get_post_meta( $quiz_id, '_lp_retake_count', true ); if ( $retake_config == '-1' ) { // For no limit $flag = true; } elseif ( absint( $retaken ) < absint( $retake_config ) ) { $flag = true; } } return apply_filters( 'lp/quiz/can-retake', $flag ); } /** * Get quiz status for the user * * @param int $quiz_id * @param int $course_id * * @return mixed */ public function get_quiz_status( $quiz_id, $course_id = 0 ) { return $this->get_item_status( $quiz_id, $course_id ); } /** * Get quiz status for the user * * @param int $lesson_id * @param int $course_id * * @return mixed */ public function get_lesson_status( $lesson_id, $course_id = 0 ) { return $this->get_item_status( $lesson_id, $course_id ); } /** * @param int $item_id * @param int $course_id * @param bool $last * * @return mixed * @since 3.0.0 */ public function get_item( $item_id, $course_id = 0, $last = false ) { if ( ! $course_id ) { $course_id = get_the_ID(); } if ( ! $course_id ) { return false; } $course_data = $this->get_course_data( $course_id ); if ( $course_data ) { return $course_data->get_item( $item_id ); } return false; } /** * @param int $item_id * @param int $course_id * * @return mixed * @since 3.0.0 * @version 1.0.1 * @editor tungnx * @modify 4.1.4.1 */ public function get_item_grade( $item_id, $course_id = 0 ) { if ( ! $course_id ) { $course_id = get_the_ID(); } $grade = false; $course_data = $this->get_course_data( $course_id ); if ( $course_data ) { $grade = $course_data->get_item_result( $item_id, 'grade' ); } return apply_filters( 'learn-press/user-item-grade', $grade, $item_id, $this->get_id(), $course_id ); } /** * Get current status of an item for user. * * @param int $item_id * @param int $course_id * * @return bool|mixed */ public function get_item_status( $item_id, $course_id = 0 ) { $status = ''; if ( ! $course_id ) { $course_id = get_the_ID(); } if ( ! $course_id ) { return $status; } $item = $this->get_item( $item_id, $course_id, true ); if ( false !== $item ) { $status = $item['status']; } return apply_filters( 'learn-press/user-item-status', $status, $item_id, $this->get_id(), $course_id ); } /** * To rewrite get_item_status on abstract-lp-user. * * @throws Exception * @author tungnx */ /*public function getItemStatus( $item_id, $course_id ) { $status = LP_User_Items_DB::getInstance()->get_item_status( $item_id, $course_id ); return $status; }*/ /** * Update viewing item data into database. * * @param int $item_id * @param int $course_id * * @return bool * @since 3.0.0 * @version 4.0.1 * @depecated 4.1.6.9 */ /*public function maybe_update_item( $item_id, $course_id ) { $return = false; try { $course_data = $this->get_course_data( $course_id ); if ( $course_data ) { $item = $course_data->get_item( $item_id ); if ( ! $item ) { $item = LP_User_Item::get_item_object( $item_id ); if ( ! $item ) { return $return; } if ( $item instanceof LP_User_Item_Quiz ) { return $return; } $item->set_ref_id( $course_id ); $item->set_parent_id( $course_data->get_user_item_id() ); $return = $item->update(); } } } catch ( Throwable $e ) { error_log( $e->getMessage() ); } return $return; }*/ /** * Get item user has accessed in last time. * * @param int $course_id * @param bool $permalink - Optional. TRUE will return permalink instead of ID. * * @return mixed * @depecated 4.1.6.9 */ public function get_current_item( $course_id, $permalink = false ) { _deprecated_function( __FUNCTION__, '4.1.6.9' ); return 0; /*$course_data = $this->get_course_data( $course_id ); if ( ! $course_data ) { return false; } $course = learn_press_get_course( $course_id ); $id = learn_press_get_user_item_meta( $course_data->get_user_item_id(), '_current_item' ); if ( ! $id || $this->has_completed_item( $id, $course_id ) ) { $items = $course->get_items( '', false ); if ( $items ) { foreach ( $items as $item_id ) { if ( ! $this->has_completed_item( $item_id, $course_id ) ) { $id = $item_id; break; } } if ( ! $id ) { $id = reset( $items ); } } if ( $id ) { learn_press_update_user_item_meta( $course_data->get_user_item_id(), '_current_item', $id ); } } if ( $permalink && $id ) { return apply_filters( 'learn-press/current-course-item-permalink', $course->get_item_link( $id ), $course_id, $this->get_id() ); } else { return apply_filters( 'learn-press/current-course-item', $id, $course_id, $this->get_id() ); }*/ } /** * Get current question's ID/Permalink inside quiz. * * @param int $quiz_id * @param int $course_id * @param bool $permalink * * @return bool|int|string * @depecated 4.1.6.9 */ /*public function get_current_question( $quiz_id, $course_id, $permalink = false ) { _deprecated_function( sprintf( '%s::%s', __CLASS__, __FUNCTION__ ), '4.0.0' ); }*/ /** * Get previous Question * * @param null $quiz_id * @param int $course_id * @param false $permalink * @depecated 4.1.6.9 */ /*public function get_prev_question( $quiz_id = null, $course_id = 0, $permalink = false ) { _deprecated_function( sprintf( '%s::%s', __CLASS__, __FUNCTION__ ), '4.0.0' ); }*/ /** * Get next Question * * @param null $quiz_id * @param int $course_id * @param false $permalink * @depecated 4.1.6.9 */ /*public function get_next_question( $quiz_id = null, $course_id = 0, $permalink = false ) { _deprecated_function( sprintf( '%s::%s', __CLASS__, __FUNCTION__ ), '4.0.0' ); }*/ /** * Checks if has status of a quiz for user * * @param string|array $statuses * @param int $quiz_id * @param int $course_id * @param boolean $force * * @return bool */ public function has_quiz_status( $statuses, $quiz_id, $course_id = 0, $force = false ) { $status = $this->get_quiz_status( $quiz_id, $course_id ); settype( $statuses, 'array' ); return apply_filters( 'learn_press_user_has_quiz_status', in_array( $status, $statuses ), $statuses, $status, $quiz_id, $course_id, $this->get_id() ); } /** * Get current results of a quiz * * @param int $quiz_id * @param int $course_id * @param string $prop * * @return mixed */ public function get_quiz_results( $quiz_id, $course_id = 0, $prop = 'result' ) { $user_quiz = $this->get_item_data( $quiz_id, $course_id ); return $user_quiz ? $user_quiz->get_results( $prop ) : false; } /** * Get current progress of user's quiz. * * @param int $quiz_id * @param int $course_id * * @return LP_User_Item_Quiz|false */ public function get_quiz_data( $quiz_id, $course_id = 0 ) { $result = false; $course_result = $this->get_course_data( $course_id ); if ( $course_result ) { $result = $course_result->get_item( $quiz_id ); } return $result; } /** * Mark question that user has checked. * * @param int $question_id * @param int $quiz_id * @param int $course_id * * @return WP_Error|mixed * @since 3.0.0 * @editor tungnx * @modify 4.1.4.1 - comment - not use */ /*public function check_question( $question_id, $quiz_id, $course_id ) { if ( ! $course = learn_press_get_course( $course_id ) ) { return false; } if ( ! $course->has_item( $quiz_id ) ) { return false; } $quiz = $course->get_item( $quiz_id ); if ( ! $quiz->has_question( $question_id ) ) { return false; } $quiz_data = $this->get_item_data( $quiz_id, $course_id ); return $quiz_data->check_question( $question_id ); }*/ /** * Mark question that user has checked. * * @param int $question_id * @param int $quiz_id * @param int $course_id * * @return WP_Error|mixed * @since 3.0.0 */ public function hint( $question_id, $quiz_id, $course_id ) { $course = learn_press_get_course( $course_id ); if ( ! $course ) { return false; } if ( ! $course->has_item( $quiz_id ) ) { return false; } /** * @var $quiz LP_Quiz */ $quiz = $course->get_item( $quiz_id ); if ( ! $quiz instanceof LP_Course_Item_Quiz ) { return false; } if ( ! $quiz->has_question( $question_id ) ) { return false; } $quiz_data = $this->get_item_data( $quiz_id, $course_id ); $remain = $quiz_data->hint( $question_id ); if ( false === $remain ) { return new WP_Error( 1001, __( 'You can not hint question.', 'learnpress' ) ); } return $remain; } /** * Return true if check answer is enabled. * * @param int $quiz_id * @param int $course_id * * @return bool * @deprecated 4.1.4.1 */ /*public function can_check_answer( $quiz_id, $course_id = 0 ) { _deprecated_function( __FUNCTION__, '4.1.4.1' ); if ( ! $course_id ) { $course_id = get_the_ID(); } if ( $quiz_data = $this->get_item_data( $quiz_id, $course_id ) ) { return $quiz_data->can_check_answer(); } return false; }*/ /** * Return true if check answer is enabled. * * @param int $quiz_id * @param int $course_id * * @return bool * @depecated 4.1.6.9 */ /*public function can_hint_answer( $quiz_id, $course_id = 0 ) { if ( ! $course_id ) { $course_id = get_the_ID(); } if ( $quiz_data = $this->get_item_data( $quiz_id, $course_id ) ) { return $quiz_data->can_hint_answer(); } return false; }*/ public function get_quiz_last_results( $quiz_id ) { $results = $this->get_course_info( $quiz_id ); if ( $results ) { $results = reset( $results ); } return apply_filters( 'learn_press_user_quiz_last_results', $results, $quiz_id, $this ); } /** * Get history of a quiz for an user * * @param int $quiz_id * @param int $course_id * @param int $history_id * @param bool $force * * @return mixed|null|void * @editor tungnx * @modify 4.1.4.1 - comment - not use */ /*public function get_quiz_history( $quiz_id, $course_id = 0, $history_id = null, $force = false ) { $course_id = $this->_get_course( $course_id ); $course = learn_press_get_course( $course_id ); if ( $course ) { $quizzes = $course->get_quizzes( 'ID' ); } else { $quizzes = array(); } $key = $this->get_id() . '-' . $course_id . '-' . $quiz_id; $cached = LP_Cache::get_quiz_history( false, array() ); if ( ( ! array_key_exists( $key, $cached ) || $force ) && $quizzes && in_array( $quiz_id, $quizzes ) ) { global $wpdb; $t1 = $wpdb->learnpress_user_items; $t2 = $wpdb->learnpress_user_itemmeta; $in = array_fill( 0, sizeof( $quizzes ), '%d' ); $prepare_params = array_merge( array( 'lp_quiz', $this->get_id(), $course_id ), $quizzes ); $query = $wpdb->prepare( " SELECT * FROM $t1 uq WHERE uq.item_type = %s AND uq.user_id = %d AND uq.ref_id = %d AND uq.item_id IN(" . join( ',', $in ) . ') ORDER BY uq.user_item_id DESC ', $prepare_params ); $history = array(); foreach ( $quizzes as $_quiz_id ) { $history[ $this->get_id() . '-' . $course_id . '-' . $_quiz_id ] = array(); } if ( $results = $wpdb->get_results( $query ) ) { $item_ids = array(); foreach ( $results as $result ) { $item_ids[] = $result->user_item_id; $cache_key = $this->get_id() . '-' . $course_id . '-' . $result->item_id; if ( empty( $history[ $cache_key ] ) ) { $history[ $cache_key ] = array(); } // limit newest 10 items if ( sizeof( $history[ $cache_key ] ) >= 10 ) { // break; } $history[ $cache_key ][ $result->user_item_id ] = (object) array( 'history_id' => $result->user_item_id, 'start' => $result->start_time, 'end' => $result->end_time, 'status' => $result->status, 'question' => '', 'questions' => array(), 'question_answers' => array(), ); } if ( $item_ids && $meta = $this->_get_quiz_meta( $item_ids ) ) { $maps = array( 'questions' => 'questions', 'current_question' => 'question', 'question_answers' => 'question_answers', 'question_checked' => 'question_checked', ); foreach ( $meta as $k => $v ) { $_key = $this->get_id() . '-' . $course_id . '-' . $v->item_id; if ( empty( $history[ $_key ] ) ) { continue; } if ( empty( $history[ $_key ][ $v->user_item_id ] ) ) { continue; } $obj_key = ! empty( $maps[ $v->meta_key ] ) ? $maps[ $v->meta_key ] : $v->meta_key; if ( ! $obj_key ) { continue; } $history[ $_key ][ $v->user_item_id ]->{$obj_key} = LP_Helper::maybe_unserialize( $v->meta_value ); } } } if ( $history ) { foreach ( $history as $k1 => $v1 ) { if ( empty( $cached[ $k1 ] ) ) { $cached[ $k1 ] = $v1; continue; } foreach ( $v1 as $k2 => $v2 ) { $cached[ $k1 ][ $k2 ] = $v2; } } } LP_Cache::set_quiz_history( $cached ); } return apply_filters( 'learn_press_user_quiz_history', isset( $cached[ $key ] ) ? $cached[ $key ] : array(), $this, $quiz_id ); }*/ /** * @editor tungnx * @modify 4.1.4.1 - comment - not use */ /*private function _get_quiz_meta( $user_item_id ) { global $wpdb; settype( $user_item_id, 'array' ); $in = array_fill( 0, sizeof( $user_item_id ), '%d' ); $query = $wpdb->prepare( " SELECT learnpress_user_item_id as user_item_id, meta_key, meta_value, item_id FROM {$wpdb->prefix}learnpress_user_itemmeta im INNER JOIN {$wpdb->prefix}learnpress_user_items i ON i.user_item_id = im.learnpress_user_item_id WHERE learnpress_user_item_id IN(" . join( ',', $in ) . ') ', $user_item_id ); return $wpdb->get_results( $query ); }*/ /** * @editor tungnx * @modify 4.1.4.1 comment - not use */ /*public function get_current_results( $quiz_id, $course_id = 0 ) { $course_id = $this->_get_course( $course_id ); $history = $this->get_quiz_history( $quiz_id, $course_id ); $current = false; if ( $history ) { $current = reset( $history ); } return $current; }*/ /** * Check if user has at least one role. * * @param array|string $roles * * @return array */ public function has_role( $roles ) { settype( $roles, 'array' ); return array_intersect( $roles, $this->get_roles() ); } /** * Detect the type of user * * @param string|int $type * * @return bool */ public function is( $type ) { $is = false; if ( $type === 'current' ) { $is = $this->is( get_current_user_id() ); } elseif ( is_string( $type ) ) { $name = preg_replace( '!LP_User(_?)!', '', get_class( $this ) ); $is = strtolower( $name ) == strtolower( $type ); } elseif ( is_numeric( $type ) ) { $is = $this->get_id() && ( $this->get_id() == $type ); } return $is; } /** * * Check what the user can do * * @param $role * * @return mixed * @throws Exception */ public function can( $role ) { _deprecated_function( __FUNCTION__, '3.0.8' ); $args = func_get_args(); unset( $args[0] ); $method = 'can_' . preg_replace( '!-!', '_', $role ); $callback = array( $this, $method ); if ( is_callable( $callback ) ) { return call_user_func_array( $callback, $args ); } else { throw new Exception( sprintf( __( 'The role %s for user doesn\'t exist', 'learnpress' ), $role ) ); } } public function can_edit_item( $item_id, $course_id = 0 ) { $return = $this->is_admin(); if ( ! $return ) { $course_id = $this->_get_course( $course_id ); $course_author = learn_press_get_course_user( $course_id ); if ( $course_author && $course_author->get_id() == $this->get_id() ) { $return = true; } } return apply_filters( 'learn_press_user_can_edit_item', $return, $item_id, $course_id, $this->get_id() ); } /** * Check if user can finish course by getting current progress * and compares with course passing condition. * * @param int $course_id * * @return bool * @editor tungnx * @modify 4.1.3 */ public function can_finish_course( int $course_id ) { _deprecated_function( __FUNCTION__, '4.1.3', 'is_course_finished' ); return true; } /** * Check if course has any passed status for an user. * Statuses: depending on value of column `status` in user_items. * - purchased: bought and order is completed, `start_date` and `end_date` is null * - enrolled: value of column `status` in user_items is enrolled * - started: value of column `status` in user_items is started * - enrolled: value of column `status` in user_items is enrolled * * @param int $course_id * @param string|array $statuses * * @return bool * @since 2.0 */ public function has_course_status( $course_id, $statuses ) { $status = $this->get_course_status( $course_id ); if ( is_array( $statuses ) ) { return in_array( $status, $statuses ); } elseif ( is_string( $statuses ) ) { return $statuses == $status; } return false; } public function get_completed_items( $course_id ) { $this->_curd->get_user_items( $this->get_id(), $course_id ); return $this->_curd->get_user_completed_items( $this->get_id(), $course_id ); } /** * Finish course * * @param int $course_id * * @return int|bool */ public function finish_course( int $course_id ) { $return = false; $course = learn_press_get_course( $course_id ); if ( $course ) { $user_course = $this->get_course_data( $course_id ); $result = $user_course->calculate_course_results(); // Save result for course LP_User_Items_Result_DB::instance()->update( $user_course->get_user_item_id(), wp_json_encode( $result ) ); if ( $result['pass'] ) { $graduation = LP_COURSE_GRADUATION_PASSED; } else { $graduation = LP_COURSE_GRADUATION_FAILED; } $user_course->set_graduation( $graduation ); $user_course->save(); $return = $user_course->complete( 'finished' ); if ( $return ) { do_action( 'learn-press/user-course-finished', $course_id, $this->get_id(), $return ); } } return apply_filters( 'learn-press/user-course-finished-data', $return, $course_id, $this->get_id() ); } /** * Check user instructor. * * @return bool */ public function is_instructor(): bool { $roles = $this->get_data( 'roles' ) ? $this->get_data( 'roles' ) : array(); return in_array( LP_TEACHER_ROLE, $roles ); } /** * Check user admin. * * @return bool */ public function is_admin() { $roles = $this->get_data( 'roles' ) ? $this->get_data( 'roles' ) : array(); return in_array( 'administrator', $roles ); } public function can_create_course() { return $this->is_instructor() || $this->is_admin(); } /** * Wrap function to check this user is author of a post. * * @param int $post_id * * @return bool * @since 3.1.0 */ public function is_author_of( $post_id ) { return absint( get_post_field( 'post_author', $post_id ) ) === $this->get_id(); } public function has( $role ) { _deprecated_function( __FUNCTION__, '3.0.8' ); $args = func_get_args(); unset( $args[0] ); $method = 'has_' . preg_replace( '!-!', '_', $role ); $callback = array( $this, $method ); if ( is_callable( $callback ) ) { return call_user_func_array( $callback, $args ); } else { throw new Exception( sprintf( __( 'The role %s for user doesn\'t exist', 'learnpress' ), $role ) ); } } public function get( $role ) { $args = func_get_args(); unset( $args[0] ); $method = 'get_' . preg_replace( '!-!', '_', $role ); $callback = array( $this, $method ); if ( is_callable( $callback ) ) { return call_user_func_array( $callback, $args ); } else { throw new Exception( sprintf( __( 'The role %s for user doesn\'t exist', 'learnpress' ), $role ) ); } } /** * Check user has passed course. * * @param $course_id * * @return mixed */ public function has_passed_course( $course_id ) { $user_course = $this->get_course_data( $course_id ); if ( $user_course && $user_course->is_passed() ) { return true; } else { return false; } } /** * Checks if user has started a quiz * - FALSE if user has not started quiz * - String if user has started quiz (status of quiz) * * @param int $quiz_id * @param int $course_id * * @return mixed */ public function has_started_quiz( $quiz_id, $course_id = 0 ) { $course_id = $this->_get_course( $course_id ); $started = false; $started = $this->has_quiz_status( array( 'started', 'completed' ), $quiz_id, $course_id ); return apply_filters( 'learn_press_user_started_quiz', $started, $quiz_id, $course_id, $this->get_id() ); } /** * Return true if user has completed a quiz * * @param int $quiz_id * @param int $course_id * * @return bool * @depecated 4.1.6.9 */ /*public function has_completed_quiz( $quiz_id, $course_id = 0 ): bool { return $this->get_item_status( $quiz_id, $course_id ) == 'completed'; }*/ /** * Mark a lesson is completed for user * * @param int $lesson_id * @param int $course_id * @param bool $return_wp_error * * @return bool|WP_Error */ public function complete_lesson( $lesson_id, $course_id = 0, $return_wp_error = true ) { global $wpdb; try { do_action( 'learn-press/before-complete-lesson', $lesson_id, $course_id, $this->get_id() ); $course_id = $this->_get_course( $course_id ); $course_data = $this->get_course_data( $course_id ); $result = false; /** * If user has stared a lesson, get user lesson information */ $item = $course_data->get_item( $lesson_id ); if ( $item ) { if ( $item->is_completed() ) { throw new Exception( __( 'You have already completed this lesson.', 'learnpress' ), LP_COMPLETE_ITEM_FAIL ); } // TODO: conflict??? //$time = new LP_Datetime(); $item->set_end_time( current_time( 'mysql', 1 ) ); $item->set_status( 'completed' ); $item->set_graduation( apply_filters( 'learn-press/complete-lesson-graduation', 'passed' ) ); $updated = $item->update( true, true ); if ( is_wp_error( $updated ) ) { return $return_wp_error ? $updated : false; } else { $result = true; } //$result = $this->evaluate_course_results( $this->get_id() ); } do_action( 'learn-press/user-completed-lesson', $lesson_id, $course_id, $this->get_id() ); } catch ( Exception $ex ) { $result = $return_wp_error ? new WP_Error( $ex->getCode(), $ex->getMessage() ) : false; } return $result; } /** * Returns TRUE if user has already completed a lesson * * @param int $lesson_id Lesson id. * @param null $course_id Course id. * * @return bool * @depecated 4.1.6.9 */ public function has_completed_lesson( $lesson_id = 0, $course_id = null ): bool { return 'completed' === $this->get_item_status( $lesson_id, $course_id ); } /** * Return current status of course for user * * @param int $course_id * @param string $field * @param bool $force * * @return mixed */ public function get_course_info( int $course_id, $field = null, $force = false ) { $user_data = $this->get_course_data( $course_id ); if ( $user_data ) { return $user_data->get_results( $field ); } return false; } /** * @param $course_id * * @return int * @depecated 4.1.6.9 */ public function get_course_history_id( $course_id ) { $history = $this->get_course_info( $course_id ); return ! empty( $history['history_id'] ) ? $history['history_id'] : 0; } /** * Get current status of a course for user. * * @param int $course_id * * @return mixed * @editor tungnx * @modify 4.1.3 * @version 1.0.1 */ public function get_course_status( int $course_id ): string { $status = ''; try { $user_data = $this->get_course_data( $course_id ); if ( $user_data ) { $status = $user_data->get_status(); } } catch ( Throwable $e ) { if ( LP_Debug::is_debug() ) { error_log( $e->getMessage() ); } } return apply_filters( 'learn-press/user-course-status', $status, $course_id, $this->get_id() ); } /** * Controls what this user can do with a course. * * 0 => No accessible * 10 => Normal users (like not logged in) * 20 => Author of course * 30 => Admin site * 35 => No require enrollment * 40 => Ordered but not completed * 50 => Order is completed but not enrolled * 60 => User has already enrolled course * 70 => User has already finished course * * @param int $course_id * * @return int * @since 3.1.0 * @editor tungnx * @modify 4.1.3 - comment - not use */ /*public function get_course_access_level( $course_id ) { $access_level = LP_Object_Cache::get( 'course-' . $course_id . '-' . $this->get_id(), 'learn-press/course-access-levels' ); if ( false === $access_level ) { $course = learn_press_get_course( $course_id ); if ( ! $course ) { $access_level = LP_COURSE_ACCESS_LEVEL_0; } elseif ( $this->is_admin() ) { $access_level = LP_COURSE_ACCESS_LEVEL_30; } elseif ( $this->is_author_of( $course_id ) ) { $access_level = LP_COURSE_ACCESS_LEVEL_20; } else { $access_level = LP_COURSE_ACCESS_LEVEL_10; } // Default level $access_level = apply_filters( 'learn-press/course-access-level-default', $access_level, $course_id, $this->get_id() ); $course_data = $this->get_course_data( $course_id ); if ( $course_data && $course_data->get_user_item_id() ) { // if ( $course_data->get_access_level() >= 50 ) { switch ( $course_data->get_status() ) { case 'completed': case 'failed': $access_level = LP_COURSE_ACCESS_LEVEL_60; break; case 'in-progress': case 'enrolled': $access_level = LP_COURSE_ACCESS_LEVEL_70; break; } // } } else { $order = $this->get_course_order( $course_id ); if ( $order ) { switch ( $order->get_status() ) { case 'completed': $access_level = LP_COURSE_ACCESS_LEVEL_50; break; default: $access_level = LP_COURSE_ACCESS_LEVEL_40; } } } LP_Object_Cache::set( 'course-' . $course_id . '-' . $this->get_id(), $access_level, 'learn-press/course-access-levels' ); } return apply_filters( 'learn-press/course-access-level', $access_level, $course_id, $this->get_id() ); }*/ /** * @editor tungnx * @reason comment - not use * @modify 4.1.2 */ /*public function get_item_access_level( $item_id, $course_id ) { $access_level = 0; if ( $course = learn_press_get_course( $course_id ) ) { if ( $course->has_item( $item_id ) ) { if ( 10 < $this->get_course_access_level( $course_id ) ) { $access_level = 10; } else { $item = $course->get_item( $item_id ); if ( $item->is_preview() ) { $access_level = 10; } } } } return apply_filters( 'learn-press/course-item-access-level', $access_level, $item_id, $course_id, $this->get_id() ); }*/ /** * Set new access-level of an user with a course. * * @param int $access_level * @param int $course_id * * @return mixed * @since 3.1.0 * @editor tungnx * @reason comment - not use * @modify 4.1.2 */ /*public function set_course_access_level( $access_level, $course_id ) { if ( $access_level !== $this->get_course_access_level( $course_id ) ) { LP_Object_Cache::set( 'course-' . $course_id . '-' . $this->get_id(), $access_level, 'learn-press/course-access-levels' ); } return $access_level; }*/ /** * Check if user have an access-level. * Consider the passed access-level is max level user have. * * @param int[] $access_level * @param int $course_id * @param string $compare * * @return bool * @since 3.1.0 * @editor tungnx * @modify 4.1.3 - not - use */ /*public function has_course_access_level( $access_level, $course_id, $compare = '<=' ) { $user_access_level = $this->get_course_access_level( $course_id ); switch ( $compare ) { case 'any': settype( $access_level, 'array' ); $has = in_array( $user_access_level, $access_level ); break; default: $has = version_compare( $user_access_level, $access_level ); } return $has; }*/ /** * Check if user has an access-level with a course. * * @param int $access_level * @param int $course_id * * @return bool * @since 3.1.0 * @editor tungnx * @modify 4.1.2 * @reason comment - not use */ /*public function is_access_level( $access_level, $course_id ) { $user_access_level = $this->get_course_access_level( $course_id ); return $user_access_level === $access_level; }*/ /** * Check if user is already ordered a course. * * @param int $course_id * * @return mixed|LP_Order * @editor tungnx * @modify 4.1.3 - comment - not use */ /*public function has_ordered_course( $course_id ) { $return = apply_filters( 'learn-press/user-has-ordered-course', $this->get_course_order( $course_id ), $course_id, $this->get_id() ); // Deprecated since 3.0.0 $return = apply_filters( 'learn_press_user_has_ordered_course', $return, $course_id, $this->get_id() ); return $return; }*/ /** * Get order status of a course. * * @param int $course_id * * @return mixed */ public function get_order_status( $course_id ) { try { $order = $this->get_course_order( $course_id ); if ( ! $order ) { throw new Exception( 'Order not exists' ); } $order_status = apply_filters( 'learn-press/course-order-status', get_post_status( $order->get_id() ), $course_id, $this->get_id() ); } catch ( Throwable $e ) { $order_status = false; } return $order_status; } /** * @param $item * @param int $course_id * @param bool $force * * @return mixed|void */ public function has_completed_item( $item, $course_id = 0, $force = false ) { $course_id = $this->_get_course( $course_id ); $return = false; $item_id = 0; if ( is_numeric( $item ) ) { $item_id = absint( $item ); } else { settype( $item, 'array' ); if ( ! empty( $item['ID'] ) ) { $item_id = absint( $item['ID'] ); } } if ( $item_id ) { if ( empty( $item['item_type'] ) ) { $type = learn_press_get_post_type( $item_id ); } else { $type = $item['item_type']; } if ( ! $type ) { $type = learn_press_get_post_type( $item_id ); } if ( $type == 'lp_lesson' || $type == 'lp_quiz' ) { $return = 'completed' === $this->get_item_status( $item_id, $course_id ); } } return apply_filters( 'learn_press_user_has_completed_item', $return, $item ); } /** * Get the remaining time of a course for the user. * * @param int $course_id * * @return bool|int|string */ public function get_course_remaining_time( $course_id ) { $course = learn_press_get_course( $course_id ); $remain = false; if ( $course && $course->get_id() ) { $course_data = $this->get_course_data( $course_id, true ); if ( $course_data ) { $remain = $course_data->is_exceeded(); } } return $remain > 0 ? learn_press_seconds_to_weeks( $remain ) : false; } /** * Get the order that contains the course. * * @param int $course_id * * @return bool|LP_Order * @editor tungnx * @throws Exception * @version 1.0.2 * @since 4.1.1 */ public function get_course_order( int $course_id ) { $lp_order = false; $lp_order_db = LP_Order_DB::getInstance(); $lp_order_id = $lp_order_db->get_last_lp_order_id_of_user_course( $this->get_id(), $course_id ); if ( $lp_order_id ) { $lp_order = new LP_Order( $lp_order_id ); } return $lp_order; } /** * Enroll this user to a course. * * @param int $course_id * @param int $order_id - Optional. An user can be enrolled to a course * * @return bool|WP_Error * @throws Exception * @since 3.3.0 * @editor tungnx * @version 3.3.1 * @modify 4.1.3 - comment - not use */ // public function enroll_course( int $course_id = 0, int $order_id = 0 ) { // $lp_user_items_db = LP_User_Items_DB::getInstance(); // // try { // /*$user_item_api = new LP_User_Item_CURD(); // $find_query = array( // 'item_id' => $course_id, // 'user_id' => $this->get_id(), // ); // // if ( $order_id ) { // $find_query['ref_id'] = $order_id; // }*/ // // $filter = new LP_User_Items_Filter(); // $filter->user_id = get_current_user_id(); // $filter->item_id = $course_id; // $course_item = $lp_user_items_db->get_last_user_course( $filter ); // // if ( ! $course_item ) { // $course_item = LP_User_Item::get_empty_item(); // } else { // $course_item = (array) $course_item; // } // // $user_id = $this->get_id(); // // $course_item['user_id'] = $user_id; // $course_item['item_id'] = $course_id; // $course_item['item_type'] = learn_press_get_post_type( $course_id ); // $course_item['ref_id'] = $order_id; // $course_item['ref_type'] = ( $order_id != 0 ) ? learn_press_get_post_type( $order_id ) : ''; // $course_item['start_time'] = current_time( 'mysql', true ); // $course_item['access_level'] = 50; // // /** // * @editor tungnx // * @fixed: case no auto enroll // */ // if ( 'yes' == LP_Settings::get_option( 'auto_enroll' ) ) { // $course_item['graduation'] = 'in-progress'; // } // // $user_course = new LP_User_Item_Course( $course_item ); // $user_course->set_status( LP_COURSE_PURCHASED ); // // if ( ! $user_course->update( true ) ) { // throw new Exception( __( 'Update user item error.', 'learnpress' ) ); // } // // /*$user_id = is_user_logged_in() ? $this->get_id() : 0; // // global $wpdb; // $query = $wpdb->prepare( // " // UPDATE {$wpdb->learnpress_user_items} // SET access_level = %d // WHERE user_id = %d // AND item_id = %d // AND user_item_id NOT IN(%d) // ", // 0, // $user_id, // $course_id, // $user_course->get_user_item_id() // ); // $wpdb->query( $query );*/ // // $return = $user_course->get_user_item_id(); // } catch ( Exception $ex ) { // error_log( $ex->getMessage() ); // return false; // } // // return $return; // } /** * Enroll this user to a course. * * @param int $course_id * @param int $order_id * @param bool $force - Optional. Force create db record for preview quiz case * @param bool $wp_error - Optional. TRUE will return WP_Error object if there is an error. * @editor tungnx - comment - not use * @return bool|mixed|WP_Error */ /*public function enroll( $course_id, $order_id, $force = false, $wp_error = false ) { global $wpdb; _deprecated_function( __FUNCTION__, '4.1.0' ); try { $course = learn_press_get_course( $course_id ); $user_id = $this->get_id(); if ( $course->is_required_enroll() && ! $force ) { $order = learn_press_get_order( $order_id ); if ( ! $order ) { throw new Exception( __( 'Failed to enroll course.', 'learnpress' ), 10000 ); } if ( ! $this->can_enroll_course( $course_id ) ) { throw new Exception( __( 'Failed to enroll course.', 'learnpress' ), 10001 ); } if ( ! $this->get_id() ) { throw new Exception( __( 'Please login to enroll course.', 'learnpress' ), 10002 ); } } $return = $this->enroll_course( $course_id, $order_id, false, $wp_error ); return $return; } catch ( Exception $ex ) { return new WP_Error( $ex->getCode(), $ex->getMessage() ); } }*/ /** * @param $question_id * * @return null|string */ public function get_quiz_by_question( $question_id ) { global $wpdb; $query = $wpdb->prepare( " SELECT quiz_id FROM {$wpdb->prefix}learnpress_user_items uq 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 ", 'questions', '%i:' . $wpdb->esc_like( $question_id . '' ) . ';%' ); return $wpdb->get_var( $query ); } /** * @param $question_id * @param null $quiz_id * * @return bool */ public function get_answer_results( $question_id, $quiz_id = null ) { _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '3.0.0' ); $data = false; if ( ! $quiz_id ) { $quiz_id = $this->get_quiz_by_question( $question_id ); } if ( $quiz_id ) { $question = LP_Question::get_question( $question_id ); if ( $question ) { $quiz_results = $this->get_quiz_results( $quiz_id ); if ( ! empty( $quiz_results->question_answers ) ) { $question_answer = array_key_exists( $question_id, $quiz_results->question_answers ) ? $quiz_results->question_answers[ $question_id ] : null; $data = $question->check( $question_answer ); } } } return $data; } /** * @param $question_id * @param null $quiz_id * * @return bool */ public function is_answered_question( $question_id, $quiz_id = null ) { if ( empty( $this->answered_questions ) ) { $this->answered_questions = array(); } if ( ! $quiz_id ) { $quiz_id = $this->get_quiz_by_question( $question_id ); } $results = $this->get_quiz_results( $quiz_id ); $answered = ! empty( $results->question_answers ) ? $results->question_answers : array(); return $answered ? array_key_exists( $question_id, $answered ) : false; } /** * @param array $args * * @return LP_Query_List_Table * @editor tungnx * @deprecated 4.1.6 */ /*public function get_purchased_courses( array $args = array() ): LP_Query_List_Table { $filter = new LP_User_Items_Filter(); $filter->fields = array( 'item_id' ); $filter->user_id = $this->get_id(); $filter->status = $args['status'] ?? ''; $filter->page = $args['paged'] ?? 1; $filter->limit = $args['limit'] ?? $filter->limit; $total_rows = 0; $result_courses = LP_User_Item_Course::get_user_courses( $filter, $total_rows ); $course_ids = LP_Course::get_course_ids( $result_courses, 'item_id' ); $courses = array( 'total' => $total_rows, 'paged' => $filter->page, 'limit' => $filter->limit, 'items' => $course_ids, ); return new LP_Query_List_Table( $courses ); }*/ /** * @return array */ public function get_roles() { return (array) $this->get_data( 'roles' ); } /** * @param $question_id * @param $quiz_id * @param int $course_id * * @return bool */ public function has_checked_answer( $question_id, $quiz_id, $course_id = 0 ) { if ( ! $course_id ) { $course_id = get_the_ID(); } $quiz_data = $this->get_item_data( $quiz_id, $course_id ); return $quiz_data ? $quiz_data->has_checked_question( $question_id ) : false; } /** * @param $question_id * @param $quiz_id * @param int $course_id * * @return bool */ public function has_hinted_answer( $question_id, $quiz_id, $course_id = 0 ) { if ( ! $course_id ) { $course_id = get_the_ID(); } $quiz_data = $this->get_item_data( $quiz_id, $course_id ); return $quiz_data ? $quiz_data->has_hinted_question( $question_id ) : false; } /** * Return TRUE if user is already exists. * * @return bool */ public function is_exists() { return ! ! get_user_by( 'id', $this->get_id() ); } /** * Check if the user is logged in. * * @return bool */ public function is_logged_in() { return $this->get_id() == get_current_user_id(); } /** * Get upload profile src * Option: null: get origin picture, "thumbnail": get thumbnail picture * * @param mixed $size * * @return string */ public function get_upload_profile_src( $size = '' ) { return LP_Profile::instance( $this->get_id() )->get_upload_profile_src( $size ); } /** * @param string $type * @param int $size * @param bool $src_only * * @return false|string */ public function get_profile_picture( $type = '', $size = 96, $src_only = false ) { return LP_Profile::instance( $this->get_id() )->get_profile_picture( $type, $size ); } /** * Get links socials of use on Profile page * * @param int $user_id * @return array */ public function get_profile_socials( int $user_id = 0 ): array { $socials = array(); $extra_info = learn_press_get_user_extra_profile_info( $user_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 'googleplus': $i = ''; break; case 'youtube': $i = ''; break; default: $i = sprintf( '', $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 ); } /** * Check if user can access to a course. * * @param int $course_id * * @return mixed * @editor tungnx * @modify 4.1.3 - comment - not use */ /*public function can_access_course( $course_id ) { $accessible = $this->has_course_access_level( array( LP_COURSE_ACCESS_LEVEL_60, LP_COURSE_ACCESS_LEVEL_70, ), $course_id, 'any' ); $accessible = apply_filters( 'learn-press/user-can-access-course', $accessible, $course_id, $this->get_id() ); return $accessible; }*/ /** * Check course of user has graduation is in-progress * * @param $course_id * @return bool * @throws Exception */ public function is_course_in_progress( $course_id ): bool { $user = learn_press_get_user( $this->get_id() ); $user_course = $user->get_course_data( $course_id ); return $user_course && LP_COURSE_GRADUATION_IN_PROGRESS === $user_course->get_graduation(); } /** * Return TRUE if user can do a quiz * * @param $quiz_id * @param int $course_id * * @return bool * @throws Exception */ public function can_do_quiz( $quiz_id, $course_id = 0 ) { $course = learn_press_get_course( $course_id ); if ( $course->is_required_enroll() ) { $can = $this->has_course_status( $course_id, array( 'enrolled' ) ) && ! $this->has_started_quiz( $quiz_id, $course_id ); } else { $can = ! $this->has_started_quiz( $quiz_id, $course_id ); } return apply_filters( 'learn_press_user_can_do_quiz', $can, $quiz_id, $this->get_id(), $course_id ); } public function evaluate_course_results( $course_id ) { $user_course = $this->get_course_data( $course_id ); return isset( $user_course ) ? $user_course->get_results( 'result' ) : 0; } /** * @editor tungnx * @modify 4.1.4.1 - comment - not use */ /*public function has_reached_passing_condition( $course_id ) { $course = learn_press_get_course( $course_id ); $result = $this->evaluate_course_results( $course_id ); return $return = $result >= $course->get_passing_condition(); }*/ /** * Check if all items in course completed. * * @return boolean * @author Nhamdv */ public function is_completed_all_items( $course_id ) { $course = learn_press_get_course( $course_id ); $course_data = $this->get_course_data( $course_id ); $course_results = $course_data->get_result(); if ( ! isset( $course_results['completed_items'] ) ) { return false; } return $course_results['completed_items'] >= $course->count_items(); } public function get_role() { return $this->is_admin() ? 'admin' : ( $this->is_instructor() ? 'instructor' : 'user' ); } /** * Get user course's grade. * Possible values: * + passed User has finished and passed course. * + failed User has finished but failed. * + in-progress User still is learning course. * * @param $course_id * * @return string|bool */ public function get_course_grade( $course_id ) { $grade = false; $course_data = $this->get_course_data( $course_id ); if ( $course_data ) { $grade = $course_data->get_status( 'graduation' ); } return apply_filters( 'learn-press/user-course-grade', $grade, $this->get_id(), $course_id ); } /** * Check if user is a GUEST by checking the meta _lp_temp_user is exists. * * @return bool */ public function is_guest(): bool { return ! $this->get_id() || ! get_user_by( 'id', $this->get_id() ); } /** * Check if user can edit a post. * * @param int $post_id * * @return bool */ public function can_edit( int $post_id ): bool { if ( $this->get_id() !== get_current_user_id() ) { return false; } return current_user_can( 'edit_post', $post_id ); } /** * Get email of user * * @return string */ public function get_email(): string { return $this->get_data( 'email', '' ); } /** * Return user_login of the user. * * @return string */ public function get_username(): string { return $this->get_data( 'user_login', '' ); } /** * Return user bio information. * * @return string */ public function get_description(): string { return $this->get_data( 'description', '' ); } /** * Return user first name. * * @return string */ public function get_first_name(): string { return $this->get_data( 'first_name', '' ); } /** * Return user last name. * * @return string */ public function get_last_name(): string { return $this->get_data( 'last_name', '' ); } /** * Return user nickname. * * @return string */ public function get_nickname(): string { return $this->get_data( 'nickname', '' ); } /** * Return user display name. * * @return string */ public function get_display_name(): string { return $this->get_data( 'display_name', '' ); } } }