%PDF- %PDF-
Direktori : /var/www/html/ceaa/wp-content/plugins/learnpress/inc/user/ |
Current File : /var/www/html/ceaa/wp-content/plugins/learnpress/inc/user/abstract-lp-user.php |
<?php /** * Class LP_Abstract_User * * @author ThimPress * @package LearnPress/Classes * @version 3.0.0 */ /** * Prevent loading this file directly */ defined( 'ABSPATH' ) || exit(); if ( ! class_exists( 'LP_Abstract_User' ) ) { /** * Class LP_Abstract_User */ class LP_Abstract_User extends LP_Abstract_Object_Data { /** * @var WP_User object */ public $user = false; /** * @var LP_Quiz object */ public $quiz = false; /** * @var array */ static protected $_order_items = array(); /** * @var array */ static protected $_lessons = array(); /** * @var null */ protected $_quiz_history_id = null; /** * @var int */ protected $_FOUND_ROWS = 0; /** * @var array */ protected $_courses = array(); /** * @var array */ protected $_course_items = array(); /** * @var array */ protected static $_users = array(); /** * @var null */ public $profile_picture_src = null; /** * @var null */ public $profile_picture_type = null; /** * @var array */ protected $_data = array( 'email' => '', 'user_login' => '', 'description' => '', 'first_name' => '', 'last_name' => '', 'nickname' => '', 'display_name' => '', 'date_created' => '', 'date_modified' => '', 'role' => '', 'roles' => array() ); /** * @var LP_User_CURL|null */ protected $_curd = null; /** * @var int */ protected static $_loaded = 0; /** * 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(); } self::$_loaded ++; if ( self::$_loaded == 1 ) { add_filter( 'debug_data', array( __CLASS__, 'log' ) ); } } public static function log( $data ) { $data[] = 'LP_User( ' . self::$_loaded . ' )'; return $data; } /** * Load user data from curd */ public function load() { $this->_curd->load( $this ); } /** * Get data for a course user has enrolled. * * @param int|LP_Abstract_Course $course_id * @param bool $check_exists * * @return LP_User_Item_Course|LP_User_Item_Quiz|bool */ public function get_course_data( $course_id, $check_exists = false ) { if ( is_a( $course_id, 'LP_Abstract_Course' ) ) { $course_id = $course_id->get_id(); } if ( ! $course_id ) { $course_id = get_the_ID(); } if ( false === ( $object_course_data = wp_cache_get( 'course-' . $this->get_id() . '-' . $course_id, 'lp-user-course-data' ) ) ) { $this->_curd->read_course( $this->get_id(), $course_id ); if ( false !== ( $course_item = wp_cache_get( 'course-' . $this->get_id() . '-' . $course_id, 'lp-user-courses' ) ) ) { $object_course_data = new LP_User_Item_Course( $course_item ); } else { $object_course_data = new LP_User_Item_Course( $course_id ); } wp_cache_set( 'course-' . $this->get_id() . '-' . $course_id, $object_course_data, 'lp-user-course-data' ); } if ( $object_course_data ) { if ( ! $object_course_data->get_item_id() && $check_exists ) { return false; } } return $object_course_data; } /** * @param int $item_id * @param int $course_id * * @return LP_User_Item_Quiz|LP_User_Item|bool */ public function get_item_data( $item_id, $course_id ) { return $this->get_user_item( $item_id, $course_id ); } /** * @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; if ( $course_data = $this->get_course_data( $course_id ) ) { $data = $course_data->get_item( $item_id ); } return $data; } /** * Return TRUE if user has used function for checking the question. * * @since 3.0.0 * * @param int $question_id * @param int $quiz_id * @param int $course_id * * @return mixed */ public function has_checked_question( $question_id, $quiz_id, $course_id = 0 ) { $checked = false; if ( $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 if ( $course = learn_press_get_course( $course_id ) ) { 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 ) { if ( false !== ( $course = $this->_get_course( $course_id, 'object' ) ) ) { 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 ); 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 = wp_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 */ 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; } /** * Start quiz for the user. * * @param int $quiz_id * @param int $course_id * @param bool $wp_error Optional. Whether to return a WP_Error on failure. Default false. * * @throws Exception * @return mixed|WP_Error */ public function start_quiz( $quiz_id, $course_id = 0, $wp_error = false ) { try { if ( $item_id = learn_press_get_request( 'lp-preview' ) ) { learn_press_add_message( __( 'You cannot start a quiz in preview mode.', 'learnpress' ), 'error' ); wp_redirect( learn_press_get_preview_url( $item_id ) ); exit(); } // Validate course and quiz if ( false === ( $course_id = $this->_verify_course_item( $quiz_id, $course_id ) ) ) { throw new Exception( __( 'Course does not exist or does not contain the quiz', 'learnpress' ), LP_INVALID_QUIZ_OR_COURSE ); } // If user has already finished the course if ( $this->has_finished_course( $course_id ) ) { throw new Exception( __( 'User has already finished the course of this quiz', 'learnpress' ), LP_COURSE_IS_FINISHED ); } // Check if user has already started or completed quiz if ( $this->has_item_status( array( 'started', 'completed' ), $quiz_id, $course_id ) ) { throw new Exception( __( 'User has started or completed quiz', 'learnpress' ), LP_QUIZ_HAS_STARTED_OR_COMPLETED ); } $course = learn_press_get_course( $course_id ); $quiz = learn_press_get_quiz( $quiz_id ); $user = LP_Global::user(); if ( $course->is_required_enroll() && $user->is_guest()/* && ! $quiz->get_preview() */) { throw new Exception( __( 'You have to login for starting quiz.', 'learnpress' ), LP_REQUIRE_LOGIN ); } /** * @see learn_press_hk_before_start_quiz */ $do_start = apply_filters( 'learn-press/before-start-quiz', true, $quiz_id, $course_id, $this->get_id() ); // //@deprecated $do_start = apply_filters( 'learn_press_before_user_start_quiz', $do_start, $quiz_id, $course_id, $this->get_id() ); if ( ! $do_start ) { return false; } if ( ! $return = $this->_insert_quiz_item( $quiz_id, $course_id ) ) { do_action( 'learn-press/user/start-quiz-failed', $quiz_id, $course_id, $this->get_id() ); throw new Exception( __( 'Start quiz failed!', 'learnpress' ), 99 ); } // @deprecated do_action( 'learn_press_user_start_quiz', $return, $quiz_id, $course_id, $this->get_id() ); /** * @since 3.0.0 */ do_action( 'learn-press/user/quiz-started', $quiz_id, $course_id, $this->get_id() ); } catch ( Exception $ex ) { $return = $wp_error ? new WP_Error( $ex->getCode(), $ex->getMessage() ) : false; } return $return; } /** * Finish a quiz for the user and save all data needed * * @param int $quiz_id * @param int $course_id * @param bool $wp_error * * @return mixed */ public function finish_quiz( $quiz_id, $course_id, $wp_error = false ) { if ( ! apply_filters( 'learn_press_before_user_finish_quiz', true, $quiz_id, $course_id, $this->get_id() ) ) { return false; } $return = false; try { // Validate course and quiz if ( false === ( $course_id = $this->_verify_course_item( $quiz_id, $course_id ) ) ) { throw new Exception( __( 'Course is not exists or does not contain the quiz', 'learnpress' ), LP_INVALID_QUIZ_OR_COURSE ); } // If user has already finished the course if ( $this->has_finished_course( $course_id ) ) { throw new Exception( __( 'User has already finished course of this quiz', 'learnpress' ), LP_COURSE_IS_FINISHED ); } // Check if user has already started or completed quiz if ( $this->has_item_status( array( 'completed' ), $quiz_id, $course_id ) ) { throw new Exception( __( 'User has completed quiz', 'learnpress' ), LP_QUIZ_HAS_STARTED_OR_COMPLETED ); } $user_quiz = $this->get_item_data( $quiz_id, $course_id ); $user_quiz->finish(); /** * @deprecated */ do_action( 'learn_press_user_finish_quiz', $quiz_id, $this->get_id() ); do_action( 'learn-press/user/quiz-finished', $quiz_id, $course_id, $this->get_id() ); } catch ( Exception $ex ) { $return = $wp_error ? new WP_Error( $ex->getCode(), $ex->getMessage() ) : false; } return $return; } /** * Retake a quiz for the user * * @param int $quiz_id * @param int $course_id * @param bool $wp_error * * @return bool|WP_Error * * @throws Exception */ public function retake_quiz( $quiz_id, $course_id, $wp_error = false ) { if ( ! apply_filters( 'learn-press/user/before-retake-quiz', true, $quiz_id, $course_id, $this->get_id() ) ) { return false; } $return = false; try { // Validate course and quiz if ( false === ( $course_id = $this->_verify_course_item( $quiz_id, $course_id ) ) ) { throw new Exception( sprintf( __( 'Course does not exist or does not contain the quiz.', 'learnpress' ), __CLASS__, __FUNCTION__ ), LP_INVALID_QUIZ_OR_COURSE ); } // If user has already finished the course if ( $this->has_finished_course( $course_id ) ) { throw new Exception( sprintf( __( 'You can not redo a quiz in a finished course.', 'learnpress' ), __CLASS__, __FUNCTION__ ), LP_COURSE_IS_FINISHED ); } // Check if user has already started or completed quiz if ( ! $this->has_item_status( array( 'completed' ), $quiz_id, $course_id ) ) { throw new Exception( sprintf( __( '%s::%s - User has not completed quiz.', 'learnpress' ), __CLASS__, __FUNCTION__ ), LP_QUIZ_HAS_STARTED_OR_COMPLETED ); } $return = $this->_insert_quiz_item( $quiz_id, $course_id ); $quiz = learn_press_get_quiz( $quiz_id ); if ( $questions = $quiz->get_questions() ) { $user_quiz = $this->get_quiz_data( $quiz_id, $course_id ); $question_id = reset( $questions ); learn_press_update_user_item_meta( $user_quiz->get_user_item_id(), '_current_question', $question_id ); } /** * @since 3.0.0 */ do_action( 'learn-press/user/quiz-redone', $quiz_id, $course_id, $this->get_id() ); } catch ( Exception $ex ) { $return = $wp_error ? new WP_Error( $ex->getCode(), $ex->getMessage() ) : false; do_action( 'learn-press/user/retake-quiz-failure', $quiz_id, $course_id, $this->get_id() ); } return $return; } protected function _insert_quiz_item( $quiz_id, $course_id ) { $course_data = $this->get_course_data( $course_id ); $quiz = learn_press_get_quiz( $quiz_id ); $last_results = $this->get_item_archive( $quiz_id, $course_id, true ); if ( ! $quiz->enable_archive_history() ) { if ( $last_results ) { global $wpdb; $query = $wpdb->prepare( " DELETE FROM {$wpdb->learnpress_user_items} WHERE user_id = %d AND item_id = %d AND user_item_id <> %d ", $this->get_id(), $quiz_id, $last_results['user_item_id'] ); $wpdb->query( $query ); } else { $course_data->update_item_retaken_count( $quiz_id, 0 ); } } if ( $last_results && $last_results['status'] === 'completed' ) { $course_data->update_item_retaken_count( $quiz_id, '+1' ); } $start_time = new LP_Datetime( current_time( 'mysql' ) ); $item_data = array( 'user_id' => $this->get_id(), 'item_id' => $quiz_id, 'start_time' => $start_time->toSql(), 'start_time_gmt' => $start_time->toSql( false ), 'end_time' => '0000-00-00 00:00:00', 'end_time_gmt' => '0000-00-00 00:00:00', 'item_type' => LP_QUIZ_CPT, 'status' => 'started', 'ref_id' => $course_id, 'ref_type' => LP_COURSE_CPT, 'parent_id' => $course_data->get_user_item_id(), 'user_item_id' => 0//insert ); // $last_results = $this->get_item_archive( $quiz_id, $course_id, true ); $set_current_question = false; // If there is no a record if ( ! $last_results ) { $item_data = apply_filters( 'learn-press/insert-user-item-data', $item_data, $quiz_id, $course_id, $this->get_id() ); $set_current_question = true; //learn_press_update_user_item_field( $item_data ); } else { // If there is one record but it's status is not valid then // update it as started if ( in_array( $last_results['status'], array( '', 'viewed' ) ) ) { $last_results['status'] = 'started'; $last_results['start_time'] = $start_time->toSql(); $last_results['start_time_gmt'] = $start_time->toSql( false ); $item_data = apply_filters( 'learn-press/update-user-item-data', $last_results, $quiz_id, $course_id, $this->get_id() ); $set_current_question = true; } } $this->_curd->update_user_item( $this->get_id(), $quiz_id, $item_data, $course_id ); $return = $this->get_item_archive( $quiz_id, $course_id, true ); if ( $return && $set_current_question ) { $quiz = learn_press_get_quiz( $quiz_id ); if ( $first_question = $quiz->get_question_at( 0 ) ) { learn_press_update_user_item_meta( $return['user_item_id'], '_current_question', $first_question ); } } return $return; } public function get_quiz_time_remaining( $quiz_id, $course_id = 0 ) { $course_id = $this->_get_course( $course_id ); $remaining = false; $progress = $this->get_quiz_progress( $quiz_id, $course_id ); if ( $progress && $progress->status != 'completed' ) { $quiz = LP_Quiz::get_quiz( $quiz_id ); $current_time = learn_press_get_current_time(); $progress_start = strtotime( $progress->start, $current_time ); $remaining = intval( $quiz->get_duration() ) + $progress_start - $current_time; } return apply_filters( 'learn_press_user_quiz_time_remaining', $remaining, $quiz_id, $course_id, $this->get_id() ); } public function get_question_answers( $question_id, $quiz_id, $course_id = 0 ) { $course_id = $this->_get_course( $course_id ); $progress = $this->get_quiz_progress( $quiz_id, $course_id ); $question_answers = null; if ( $progress ) { $answers = (array) $progress->quiz_question_answers; if ( array_key_exists( $question_id, $answers ) ) { $question_answers = $answers[ $question_id ]; } } return $question_answers; } /** * 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 * * @since 3.0.0 * * @return mixed */ public function get_item( $item_id, $course_id = 0, $last = false ) { if ( ! $course_id ) { $course_id = get_the_ID(); } $item = false; if ( false !== ( $items = wp_cache_get( 'course-item-' . $this->get_id() . '-' . $course_id . '-' . $item_id, 'lp-user-course-items' ) ) ) { // Only get status of a newest record. if ( $last ) { $item = reset( $items ); } else { $item = $items; } } return $item; } /** * @param int $item_id * @param int $course_id * * @since 3.0.0 * * @return mixed */ 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 && $item_result = $course_data->get_item_result( $item_id, false ) ) { $grade = isset( $item_result['grade'] ) ? $item_result['grade'] : false; } 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 * @param bool $force * * @return bool|mixed */ public function get_item_status( $item_id, $course_id = 0, $force = false ) { // Deprecated third argument if ( func_num_args() >= 3 ) { _deprecated_argument( __FUNCTION__ . ' {$force}', '3.0.0' ); } if ( ! $course_id ) { $course_id = get_the_ID(); } $status = false; if ( false !== ( $item = $this->get_item( $item_id, $course_id, true ) ) ) { $status = $item['status']; } $status = apply_filters( 'learn-press/user-item-status', $status, $item_id, $this->get_id(), $course_id ); /** * @deprecated */ $status = apply_filters( 'learn_press_user_course_item_status', $status, $item_id, $course_id, $this->get_id() ); return $status; } /** * Update viewing item data into database. * @since 3.0.0 * * @param int $item_id * @param int $course_id * * @return bool */ public function maybe_update_item( $item_id, $course_id ) { if ( ! $item_id ) { return false; } if ( ! $course = learn_press_get_course( $course_id ) ) { return false; } if ( ! $course_data = $this->get_course_data( $course_id ) ) { return false; } if ( ! ( $user_course_item_id = $course_data->get_data( 'user_item_id' ) ) ) { return false; } $user_item = $this->get_item( $item_id, $course_id, true ); /** * Update current item id is viewing in course */ if ( $item_id && $item_id != learn_press_get_user_item_meta( $user_course_item_id, '_current_item', true ) ) { learn_press_update_user_item_meta( $user_course_item_id, '_current_item', $item_id ); } if ( $user_item ) { return $user_item['user_item_id']; } global $wpdb; $item = LP_Course_Item::get_item( $item_id ); $time = new LP_Datetime(); $inserted = $wpdb->insert( $wpdb->learnpress_user_items, apply_filters( 'learn-press/default-user-item-data', array( 'user_id' => $this->get_id(), 'item_id' => $item_id, 'item_type' => $item->get_item_type(), 'start_time' => $item->get_post_type() === LP_LESSON_CPT ? $time->toSql() : '0000-00-00 00:00:00', 'start_time_gmt' => $item->get_post_type() === LP_LESSON_CPT ? $time->toSql( false ) : '0000-00-00 00:00:00', 'status' => learn_press_default_user_item_status( $item_id ), 'ref_id' => $course_id, 'ref_type' => LP_COURSE_CPT, 'parent_id' => $course_data->get_data( 'user_item_id' ) ) ) ); if ( $inserted ) { $user_item_id = $wpdb->insert_id; } else { return false; } // Update new changes to cache $items = array( $user_item_id => $this->_curd->get_user_item_by_id( $user_item_id ) ); $cache_name = sprintf( 'course-item-%d-%d-%d', $this->get_id(), $course_id, $item_id ); wp_cache_set( $cache_name, $items, 'lp-user-course-items' ); do_action( 'learn-press/set-viewing-item', $item_id, $course_id, $items[ $user_item_id ] ); return $user_item_id; } /** * 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 */ public function get_current_item( $course_id, $permalink = false ) { if ( ! $course_data = $this->get_course_data( $course_id ) ) { return false; } $course = learn_press_get_course( $course_id ); if ( false == ( $id = learn_press_get_user_item_meta( $course_data->get_user_item_id(), '_current_item', true ) ) ) { if ( $items = $course->get_items( '', false ) ) { 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 */ public function get_current_question( $quiz_id, $course_id, $permalink = false ) { $data = $this->get_course_data( $course_id ); if ( empty( $data[ $quiz_id ] ) ) { return false; } $quiz = learn_press_get_quiz( $quiz_id ); $quiz_item = $data[ $quiz_id ]; $question_id = $quiz_item->get_current_question(); if ( $question_id && $permalink ) { return apply_filters( 'learn-press/current-user-question-permalink', $quiz->get_question_link( $question_id ), $quiz_id, $course_id, $this->get_id() ); } return apply_filters( 'learn-press/current-user-question', $question_id ); } public function get_prev_question( $quiz_id = null, $course_id, $permalink = false ) { if ( ! $quiz_id ) { $quiz_id = $this->get_current_item( $course_id ); } if ( ! $quiz_id ) { return false; } $current = $this->get_current_question( $quiz_id, $course_id ); $quiz = learn_press_get_quiz( $quiz_id ); return $quiz->get_prev_question( $current ); } public function get_next_question( $quiz_id = null, $course_id, $permalink = false ) { if ( ! $quiz_id ) { $quiz_id = $this->get_current_item( $course_id ); } if ( ! $quiz_id ) { return false; } $current = $this->get_current_question( $quiz_id, $course_id ); $quiz = learn_press_get_quiz( $quiz_id ); return $quiz->get_next_question( $current ); } /** * 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, $force ); 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 */ public function get_quiz_data( $quiz_id, $course_id = 0 ) { $result = false; if ( $course_result = $this->get_course_data( $course_id ) ) { $result = $course_result->get_item( $quiz_id ); } return $result; } /** * Mark question that user has checked. * * @since 3.0.0 * * @param int $question_id * @param int $quiz_id * @param int $course_id * * @return WP_Error|mixed */ 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. * * @since 3.0.0 * * @param int $question_id * @param int $quiz_id * @param int $course_id * * @return WP_Error|mixed */ public function hint( $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 ); if ( false === ( $remain = $quiz_data->hint( $question_id ) ) ) { 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 */ public function can_check_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_check_answer(); } return false; } /** * Return true if check answer is enabled. * * @param int $quiz_id * @param int $course_id * * @return bool */ 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 ); } public function get_quiz_info( $quiz_id, $course_id = 0, $field = null ) { $course_id = $this->_get_course( $course_id ); static $quizzes = array(); if ( empty( $quizzes[ $quiz_id ] ) ) { global $wpdb; $table = $wpdb->prefix . 'learnpress_user_items';//{$wpdb->learnpress_user_quizzes} $query = $wpdb->prepare( " SELECT * FROM $table WHERE user_id = %d AND item_id = %d ", $this->get_id(), $quiz_id, '' ); $user_quiz = (array) $wpdb->get_row( $query ); if ( ! empty( $user_quiz['user_quiz_id'] ) ) { $user_quiz['history'] = $this->get_quiz_history( $quiz_id, $course_id ); } $quizzes[ $quiz_id ] = $user_quiz; } if ( $field ) { if ( array_key_exists( $field, $quizzes[ $quiz_id ] ) ) { $info = $quizzes[ $quiz_id ][ $field ]; } else { $info = ''; } return apply_filters( 'learn_press_user_quiz_' . $field, $info, $this ); } else { $info = $quizzes[ $quiz_id ]; return apply_filters( 'learn_press_user_quiz_info', $info, $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 */ 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() );// wp_cache_get( 'user-quiz-history', 'learnpress' ); if ( ( ! array_key_exists( $key, $cached ) || $force ) && $quizzes && in_array( $quiz_id, $quizzes ) ) { global $wpdb; $t1 = $wpdb->learnpress_user_items; //{$wpdb->learnpress_user_quizzes} $t2 = $wpdb->learnpress_user_itemmeta; //{$wpdb->learnpress_user_quizzes} $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 ); } 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 ); } 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; } /** * Get current progress for a quiz * * @param $quiz_id * @param int $course_id * * @return mixed|void */ public function get_quiz_progress( $quiz_id, $course_id = 0 ) { return $this->get_quiz_results( $quiz_id, $course_id ); /** * * if ( !$course_id ) { * $course_id = get_the_ID(); * } * $history = $this->get_quiz_history( $quiz_id, $course_id ); * $progress = false; * if ( $history ) { * $progress = reset( $history ); * } * return apply_filters( 'learn_press_user_quiz_progress', $progress, $quiz_id, $course_id, $this->get_id() ); * **/ } /** * 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() ); } /** * Get current question user doing for a quiz * * @param int $quiz_id * @param int $course_id * * @return mixed|void */ public function get_current_quiz_question( $quiz_id, $course_id = 0 ) { $course_id = $this->_get_course( $course_id ); $question_id = 0; if ( $progress = $this->get_quiz_results( $quiz_id, $course_id ) ) { if ( ! empty( $progress->question ) ) { $question_id = $progress->question; } elseif ( ! empty( $progress->questions ) && is_array( $progress->questions ) ) { $question_id = reset( $progress->questions ); } } if ( ! $question_id ) { $quiz = LP_Quiz::get_quiz( $quiz_id ); if ( $quiz ) { $questions = $quiz->get_questions(); if ( $questions ) { $question = reset( $questions ); $question_id = $question->ID; } } } $user = learn_press_get_current_user(); $history = $user->get_quiz_results( $quiz_id, $course_id, true ); $current_question_id = $history ? learn_press_get_user_item_meta( $history->history_id, 'lp_current_question_after_close', true ) : array(); if ( ! empty( $current_question_id ) ) { $question_id = $current_question_id; } return apply_filters( 'learn_press_user_current_quiz_question', absint( $question_id ), $quiz_id, $course_id, $this->get_id() ); } public function get_finished_courses() { global $wpdb; $query = $wpdb->prepare( " SELECT p.*, uc.start_time, uc.end_time, uc.ref_id FROM {$wpdb->posts} p INNER JOIN {$wpdb->prefix}learnpress_user_items uc ON p.ID = uc.item_id WHERE uc.user_id = %d AND uc.status = %s ", $this->get_id(), 'finished' ); return apply_filters( 'learn_press_user_finished_courses', $wpdb->get_results( $query ) ); } public function save_quiz_question( $question_id, $answer ) { } /** * 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; } /** * Get all a type of post for the user * * @param array $args - actually, it as the same with WP_Query args * * @return array */ public function get_posts( $args = array() ) { settype( $args, 'array' ); $args['author'] = $this->get_id(); $args = apply_filters( 'learn_press_get_user_posts', $args, $this ); $query = new WP_Query( $args ); $posts = array(); if ( $query->have_posts() ) { while ( $query->have_posts() ) { $p = $query->next_post(); $posts[] = $p; } } return $posts; } /** * Get all quizzes of the user * * @param array $args - actually, it as the same with WP_Query args * @param bool * * @return array */ public function get_lessons( $args = array(), $force = false ) { static $lessons = array(); if ( ! $lessons || $force ) { settype( $args, 'array' ); $args['post_type'] = LP_LESSON_CPT; $lessons = $this->get_posts( $args ); } return apply_filters( 'learn_press_get_user_lessons', $lessons ); } /** * * 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 ) ); } } /** * Return true if user can purchase a course * * @param int $course_id * * @return bool */ public function can_purchase_course( $course_id ) { $course = learn_press_get_course( $course_id ); $purchasable = $course->is_purchasable(); if ( $purchasable && $order = $this->has_ordered_course( $course_id ) ) { } // @deprecated $purchasable = apply_filters( 'learn_press_user_can_purchase_course', $purchasable, $this, $course_id ); // since 3.0.0 return apply_filters( 'learn-press/user/can-purchase-course', $purchasable, $this->get_id(), $course_id ); } /** * Return true if user can enroll a course. * * @param int $course_id * * @return bool|string */ public function can_enroll_course( $course_id ) { $course = learn_press_get_course( $course_id ); // Course is published and not reached limitation $can_enroll = ! ! $course && $course->is_publish();// && $course->is_in_stock(); if ( $can_enroll && $course->is_free() && ! $course->is_required_enroll() && ! $course->is_in_stock() ) { $can_enroll = false; } if ( $can_enroll && ! $course->is_free() && ! $this->has_purchased_course( $course_id ) ) { $can_enroll = false; } return apply_filters( 'learn-press/can-enroll-course', $can_enroll, $course_id, $this->get_id() ); } /** * User can view item. * * @param $item_id * @param int $course_id * * @return mixed * @throws Exception */ public function can_view_item( $item_id, $course_id = 0 ) { $return = false; $course_id = $this->_get_course( $course_id ); $course_author = learn_press_get_course_user( $course_id ); if ( $course_author ) { $author_id = $course_author->get_id(); if ( $author_id == $this->get_id() ) { return true; } } switch ( get_post_type( $item_id ) ) { case LP_QUIZ_CPT: $return = $this->can_view_quiz( $item_id, $course_id ); break; case LP_LESSON_CPT: $return = $this->can_view_lesson( $item_id, $course_id ); break; } // @deprecated $return = apply_filters( 'learn_press_user_can_view_item', $return, $item_id, $course_id, $this->get_id() ); return apply_filters( 'learn-press/can-view-item', $return, $item_id, $course_id, $this->get_id() ); } 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() ); } /** * Return true if user can view a lesson * * @param int $lesson_id * @param int $course_id * * @return bool */ public function can_view_lesson( $lesson_id, $course_id = 0 ) { $view = false; // else, find the course of this lesson $course_id = $this->_get_course( $course_id ); // Disable preview lesson when course status is pending if ( get_post_status( $course_id ) == 'pending' ) { $view = false; } else { $lesson = LP_Lesson::get_lesson( $lesson_id ); if ( $course = learn_press_get_course( $course_id ) ) { if ( $this->has_enrolled_course( $course_id ) || $this->has_finished_course( $course_id ) ) { // or user has enrolled course $view = 'enrolled'; } elseif ( $lesson->is_preview() || $this->is_admin() || ( $this->is_instructor() && $course->get_instructor( 'id' ) == $this->get_id() ) ) { $view = 'preview'; } elseif ( ! $course->is_required_enroll() ) { // if course is not required enroll so the lesson is previewable $view = 'no-required-enroll'; } } } // @deprecated $view = apply_filters( 'learn_press_user_view_lesson', $view, $lesson_id, $this->get_id(), $course_id ); return apply_filters( 'learn-press/can-view-lesson', $view, $lesson_id, $this->get_id(), $course_id ); } /** * Return true if user can view a quiz * * @param int $quiz_id * @param int $course_id - optional The course contains quiz * * @return bool */ public function can_view_quiz( $quiz_id, $course_id = 0 ) { $course = false; $view = false; $course_id = $this->_get_course( $course_id ); // Disable preview course when course status is pending if ( get_post_status( $course_id ) == 'pending' ) { $view = false; } else { if ( $course_id ) { $course = learn_press_get_course( $course_id ); } if ( $course ) { $quiz = LP_Quiz::get_quiz( $quiz_id ); if ( $this->has_enrolled_course( $course_id ) || $this->has_finished_course( $course_id ) ) { $view = 'enrolled'; } elseif ( /*$quiz->is_preview() ||*/ $this->is_admin() || ( $this->is_instructor() && $course->get_instructor( 'id' ) == $this->get_id() ) ) { $view = 'preview'; } elseif ( ! $course->is_required_enroll() ) { $view = 'no-required-enroll'; } } } // @deprecated $view = apply_filters( 'learn_press_user_view_quiz', $view, $quiz_id, $this->get_id(), $course_id ); return apply_filters( 'learn-press/can-view-quiz', $view, $quiz_id, $this->get_id(), $course_id ); } /** * Check to see if user can retake a quiz * - FALSE if user CAN NOT retake quiz * - INT (number of remain) if user CAN retake quiz * * @param int $quiz_id * @param int $course_id * * @return bool|int */ public function can_retake_quiz( $quiz_id, $course_id = 0 ) { $can = false; $course = learn_press_get_course( $course_id ); if ( $course && $course->has_item( $quiz_id ) ) { // Check if quiz is already exists if ( $quiz = learn_press_get_quiz( $quiz_id ) ) { $count = $quiz->get_retake_count(); if ( $count > 0 ) { // Number of taken $taken = $this->count_retaken_quiz( $quiz_id, $course_id ); if ( $taken ) { $can = $count - $taken; } else { $can = $count; } $can = absint( $can ); } } } return apply_filters( 'learn_press_user_can_retake_quiz', $can, $quiz_id, $this->get_id(), $course_id ); } public function can_finish_course( $course_id ) { $return = false; if ( $course = learn_press_get_course( $course_id ) ) { $result = $course->evaluate_course_results(); $return = ( $result >= $course->get_passing_condition() ) && $this->has_course_status( $course_id, array( 'enrolled', 'started' ) ); } return apply_filters( 'learn_press_user_can_finish_course', $return, $course_id, $this->get_id() ); } /** * 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 * * @since 2.0 * * @return bool */ 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 ); } /** * Check to see if user can retake a course, if yes return number of times * * @param $course_id * @param bool $force * * @return mixed */ public function can_retake_course( $course_id, $force = false ) { $can = false; if ( $course = learn_press_get_course( $course_id ) ) { $count = $course->get_retake_count(); if ( $count > 0 ) { // Number of taken $taken = $this->count_retaken_course( $course_id, $force ); if ( $taken ) { $can = $count - $taken; } else { $can = $count; } } } return apply_filters( 'learn_press_user_can_retake_course', $can, $course->get_id(), $this->get_id() ); } public function get_incomplete_items( $course_id ) { global $wpdb; $query = $wpdb->prepare( " SELECT user_item_id FROM {$wpdb->learnpress_user_items} WHERE user_id = %d AND (item_id = %d OR ref_id = %d) AND `status` NOT IN(%s, %s) ", $this->get_id(), $course_id, $course_id, 'completed', 'finished' ); $item_ids = $wpdb->get_col( $query ); return apply_filters( 'learn_press_user_incomplete_items', $item_ids, $course_id, $this->get_id() ); } /** * Finish course * * @param int $course_id * * @return int|bool */ public function finish_course( $course_id ) { $return = false; if ( $course = learn_press_get_course( $course_id ) ) { if ( ! $this->can_finish_course( $course_id ) ) { return false; } else { $user_course = $this->get_course_data( $course_id ); $return = $user_course->finish(); if ( $return ) { do_action( 'learn-press/user-course-finished', $course_id, $this->get_id(), $return ); } wp_cache_flush(); } } return apply_filters( 'learn-press/user-course-finished-data', $return, $course_id, $this->get_id() ); } /** * Check user instructor. * * @return bool */ public function is_instructor() { $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 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 ) ); } } /** * Get last order of an user of all courses * * @param bool $last_order * * @return array */ public function get_orders( $last_order = true ) { if ( $last_order ) { if ( false !== ( $cached_last_order = wp_cache_get( 'user-' . $this->get_id(), 'lp-user-last-order' ) ) ) { return $cached_last_order; } } $my_orders = $this->_curd->get_orders( $this->get_id() );// _learn_press_get_user_course_orders( $this->get_id() ); if ( $last_order && $my_orders ) { $last_orders = array(); foreach ( $my_orders as $course_id => $orders ) { $last_orders[ $course_id ] = reset( $orders ); } wp_cache_set( 'user-' . $this->get_id(), $last_orders, 'lp-user-last-order' ); } else { $last_orders = $my_orders; } return $last_orders; } /** * Return true if user has already enrolled course * * @param int $course_id * @param bool $force * * @return bool */ public function has_enrolled_course( $course_id, $force = false ) { $enrolled = 'no'; $cache_key = 'course-' . $this->get_id() . '-' . $course_id; if ( false === ( $enrolled = wp_cache_get( $cache_key, 'enrolled-courses' ) ) ) { // No new order is pending and has already enrolled or finished course if ( 'lp-pending' !== $this->get_order_status( $course_id ) ) { $enrolled = $this->has_course_status( $course_id, array( 'enrolled', 'finished' ) ) ? 'yes' : 'no'; } wp_cache_set( $cache_key, $enrolled, 'enrolled-courses' ); } $enrolled = $enrolled === 'yes' ? true : false; // @deprecated $enrolled = apply_filters( 'learn_press_user_has_enrolled_course', $enrolled, $this, $course_id ); /** * @since 3.0.0 */ return apply_filters( 'learn-press/has-enrolled-course', $enrolled, $this->get_id(), $course_id ); } public function is_activated_course( $course_id ) { $activated = false; if ( $course_data = $this->get_course_data( $course_id ) ) { $activated = $course_data->is_available() && $this->has_purchased_course( $course_id ); } return $activated; } /** * Return true if you has finished a course * * @param int * @param bool * * @return bool */ public function has_finished_course( $course_id, $force = false ) { if ( func_num_args() > 1 ) { _deprecated_argument( '$force', '3.0.0' ); } return apply_filters( 'learn-press/user-has-finished-course', $this->get_course_status( $course_id ) == 'finished', $this, $course_id ); } /** * Check user has passed course. * * @param $course_id * * @return mixed */ public function has_passed_course( $course_id ) { $course = learn_press_get_course( $course_id ); if ( $course ) { $results = $course->evaluate_course_results( $this->get_id() ); } else { $results = 0; } return apply_filters( 'learn_press_user_has_passed_course', $results >= $course->passing_condition ? $results : false, $course_id, $this ); } /** * 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 mixed */ public function has_completed_quiz( $quiz_id, $course_id = 0 ) { $completed = $this->get_item_status( $quiz_id, $course_id ) == 'completed'; // @deprecated since 3.0.0 $completed = apply_filters( 'learn_press_user_has_completed_quiz', $completed, $quiz_id, $this ); return apply_filters( 'learn-press/user-completed-quiz', $completed, $quiz_id, $course_id, $this->get_id() ); } /** * @param int $quiz_id * @param int $course_id * @param bool $force * * @return mixed */ public function current_quiz_status( $quiz_id, $course_id = 0, $force = false ) { $course_id = $this->_get_course( $course_id ); global $wpdb; //$key_format = '%d-%d'; $cached = (array) wp_cache_get( 'user-quiz-statuses', 'learnpress' ); if ( ! array_key_exists( $this->get_id() . '-' . $course_id . '-' . $quiz_id, $cached ) || $force ) { $query = $wpdb->prepare( " SELECT uq.item_id as id, uqm.meta_value as `status` FROM {$wpdb->prefix}learnpress_user_itemmeta uqm INNER JOIN {$wpdb->prefix}learnpress_user_items uq ON uq.user_item_id = uqm.learnpress_user_item_id AND uqm.meta_key = %s WHERE uq.user_id = %d ORDER BY user_item_id DESC ", 'status', $this->get_id(), $quiz_id ); $cached[ $this->get_id() . '-' . $quiz_id ] = ''; if ( $items = $wpdb->get_results( $query ) ) { foreach ( $items as $item ) { $cached[ $this->get_id() . '-' . $item->ID ] = $item->status; } } } return $cached[ $this->get_id() . '-' . $quiz_id ]; } /** * Count number of time user has retaken a quiz * * @param int $quiz_id * @param int $course_id * @param bool $force * * @return int */ public function count_retaken_quiz( $quiz_id, $course_id = 0, $force = false ) { $count = false; $course_id = $this->_get_course( $course_id ); if ( ! $course_id || ! $quiz_id ) { return $count; } $count = 0; if ( $course_data = $this->get_course_data( $course_id ) ) { if ( false === ( $count = $course_data->get_item_retaken_count( $quiz_id ) ) ) { //$items = $course_data->get_meta( '_retaken_items' ); //if ( false === $items || ! array_key_exists( $quiz_id, $items ) ) { //settype( $items, 'array' ); $user_item = $this->get_item_data( $quiz_id, $course_id ); if ( $user_item ) { $new_count = $user_item->count_history() - 1; $count = $course_data->update_item_retaken_count( $quiz_id, $new_count ); } //$items[ $quiz_id ] = $count; //$course_data->set_meta( '_retaken_items', $items ); //$course_data->update_meta(); ///} //$count = $items[ $quiz_id ]; } } return apply_filters( 'learn_press_user_count_retaken_quiz', $count, $quiz_id, $course_id, $this->get_id() ); } /** * Count number of time user has retaken a quiz * * @param int $course_id * @param bool $force * * @return int */ public function count_retaken_course( $course_id = 0, $force = false ) { $count = false; $course_id = $this->_get_course( $course_id ); if ( ! $course_id ) { return $count; } if ( $user_course = $this->get_course_data( $course_id ) ) { $count = $user_course->get_retaken_count(); } return $count; } public function retake_course( $course_id ) { if ( ! $this->can_retake_course( $course_id ) ) { return false; } global $wpdb; $result = false; $check = apply_filters( 'learn-press/before-retake-course', true, $course_id, $this->get_id() ); if ( ! $check ) { return false; } if ( $course_data = $this->get_course_data( $course_id ) ) { $course_data->delete_meta_data( array( 'grade', 'via', 'exceeded' ) ); $course_data->set_status( 'enrolled' ); $start_time = new LP_Datetime( current_time( 'mysql' ) ); $course_data->set_start_time( $start_time->toSql() ); $course_data->set_start_time_gmt( $start_time->toSql( false ) ); $course_data->set_end_time( LP_Datetime::getSqlNullDate() ); $course_data->set_end_time_gmt( LP_Datetime::getSqlNullDate() ); if ( $result = $course_data->update() ) { $course_data->increase_retake_count(); /* * Should be deleted all user items when user retake course? */ $wpdb->query( $wpdb->prepare( " DELETE FROM {$wpdb->prefix}learnpress_user_items WHERE parent_id = %d ", $result->user_item_id ) ); do_action( 'learn-press/user/retaken-course', $result, $course_id, $this->get_id() ); } } return $result; } /** * Checks if user has started a lesson * * @param $lesson_id * @param $course_id * * @return null|string */ public function is_exists_lesson( $lesson_id, $course_id ) { global $wpdb; $query = $wpdb->prepare( " SELECT * FROM {$wpdb->prefix}learnpress_user_items WHERE user_id = %d AND ref_id = %d AND item_id = %d ORDER BY user_item_id DESC ", $this->get_id(), $course_id, $lesson_id ); $results = $wpdb->get_row( $query ); if ( $results ) { return $results; } return false; } /** * Mark a lesson is completed for user * * @param $lesson_id * @param int $course_id * * @return bool|WP_Error */ public function complete_lesson( $lesson_id, $course_id = 0 ) { global $wpdb; do_action( 'learn_press_before_user_complete_lesson', $lesson_id, $this ); $course_id = $this->_get_course( $course_id ); if ( $this->can_view_lesson( $lesson_id, $course_id ) == 'preview' ) { return new WP_Error( 'complete-lesson-failed', __( 'You can not complete a preview lesson.', 'learnpress' ) ); } $result = false; /** * If user has stared a lesson, get user lesson information */ if ( $item = $this->is_exists_lesson( $lesson_id, $course_id ) ) { // Update lesson status if it's not 'completed' if ( $item->status !== 'completed' ) { $updated = $wpdb->update( $wpdb->prefix . 'learnpress_user_items', array( 'end_time' => current_time( 'mysql' ), 'status' => 'completed' ), array( 'user_item_id' => $item->user_item_id ), array( '%s', '%s' ), array( '%d' ) ); if ( ! $updated ) { $result = new WP_Error( 'lesson-completed', $wpdb->last_error ); } } else { $result = new WP_Error( 'lesson-completed', __( 'You have already completed this lesson', 'learnpress' ) ); } } else { $wpdb->insert( $wpdb->prefix . 'learnpress_user_items', array( 'user_id' => $this->get_id(), 'item_id' => $lesson_id, 'item_type' => LP_LESSON_CPT, 'ref_id' => $course_id, 'ref_type' => LP_COURSE_CPT, 'start_time' => current_time( 'mysql' ), 'end_time' => current_time( 'mysql' ), 'status' => 'completed', 'parent_id' => learn_press_get_user_item_id( $this->get_id(), $course_id ) ), array( '%d', '%d', '%s', '%d', '%s', '%s', '%s', '%s', '%d' ) ); $updated = $wpdb->insert_id; if ( ! $updated ) { $result = new WP_Error( 'lesson-completed', $wpdb->last_error ); } } if ( ! empty( $updated ) ) { if ( $course = learn_press_get_course( $course_id ) ) { $result = $course->evaluate_course_results( $this->get_id() ); } } do_action( 'learn_press_user_complete_lesson', $lesson_id, $result, $this->get_id() ); return $result; } /** * Returns TRUE if user has already completed a lesson * * @param $lesson_id * @param null $course_id * @param bool $force * * @return mixed|null */ public function has_completed_lesson( $lesson_id, $course_id = null, $force = false ) { $completed = $this->get_item_status( $lesson_id, $course_id ) == 'completed'; return apply_filters( 'learn-press/user-has-completed-lesson', $completed, $lesson_id, $course_id, $this->get_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( $course_id, $field = null, $force = false ) { if ( $data = $this->get_course_data( $course_id ) ) { return $data->get_results( $field ); } return false; } /** * @deprecated * * @param $course_id * * @return mixed */ public function get_course_info2( $course_id ) { _deprecated_function( __FUNCTION__, '3.0.0' ); return $this->get_course_info( $course_id ); } /** * @param $course_id * * @return int */ 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 */ public function get_course_status( $course_id ) { $status = false; if ( false !== ( $data = wp_cache_get( 'course-' . $this->get_id() . '-' . $course_id, 'lp-user-courses' ) ) ) { $status = $data['status']; } else { $course_data = $this->get_course_data( $course_id ); $status = $course_data->get_status(); } return apply_filters( 'learn-press/user-course-status', $status, $course_id, $this->get_id() ); } /** * Evaluate results of a quiz for this user * * @deprecated * * @param $quiz_id * @param $progress * * @return mixed */ public function evaluate_quiz_results( $quiz_id, $progress ) { _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '3.0.0' ); return array(); } /** * Return true if user has already purchased course * and the order is completed. * * @param int $course_id * * @return bool */ public function has_purchased_course( $course_id ) { return apply_filters( 'learn_press_user_has_purchased_course', $this->get_order_status( $course_id ) == 'lp-completed', $course_id, $this->get_id() ); } public function is_locked_course( $course_id ) { $locked = false; if ( $course_item = $this->get_course_data( $course_id ) ) { $locked = 'locked' === learn_press_get_user_item_meta( $course_item->get_user_item_id(), '_status', true ); } return $locked; } /** * Check if user is already ordered a course. * * @param int $course_id * * @return mixed|LP_Order */ 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 ) { //LP_Debug::log_function( __CLASS__ . '::' . __FUNCTION__ ); $order_id = $this->get_course_order( $course_id, false ); $return = apply_filters( 'learn-press/course-order-status', $order_id ? get_post_status( $order_id ) : false, $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() ); //LP_Debug::log_function( __CLASS__ . '::' . __FUNCTION__ ); return $return; } /** * @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 = get_post_type( $item_id ); } else { $type = $item['item_type']; } if ( ! $type ) { $type = get_post_type( $item_id ); } if ( $type == 'lp_lesson' ) { $return = $this->has_completed_lesson( $item_id, $course_id, $force ); } elseif ( $type == 'lp_quiz' ) { $return = $this->has_completed_quiz( $item_id, $course_id, $force ); } } 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() ) { if ( $course_data = $this->get_course_data( $course_id, true ) ) { $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 * @param string $return type of order to return LP_Order|ID * * @return int|LP_Order|mixed */ public function get_course_order( $course_id, $return = 'object' ) { $orders = $this->get_orders(); $order_id = ! empty( $orders[ $course_id ] ) ? $orders[ $course_id ] : false; return $order_id ? ( $return === 'object' ? learn_press_get_order( $order_id ) : $order_id ) : false; } /** * Get the order of an item in a course * Uses this function to verify permission for this user * with an item such as when user view a lesson or quiz * * @param int * @param string type of order to return LP_Order|ID * * @return int */ public function get_item_order( $item_id ) { if ( ! empty( self::$_order_items[ $item_id ] ) ) { return self::$_order_items[ $item_id ]; } return false; } /** * Enroll this user to a course. * * @param int $course_id * @param int $order_id * * @return mixed|WP_Error * @throws Exception */ /** * Enroll this user to a course. * * @param $course_id * @param $order_id * @param bool $force | Force create db record for preview quiz case * * @return bool|mixed|WP_Error */ public function enroll( $course_id, $order_id, $force = false ) { $return = false; try { global $wpdb; $course = learn_press_get_course( $course_id ); $date = new LP_Datetime(); $data = array( 'item_type' => get_post_type( $course_id ), 'status' => 'enrolled', 'ref_id' => $order_id, 'ref_type' => $order_id ? get_post_type( $order_id ) : '', 'parent_id' => 0, 'start_time' => $date->toSql(), 'start_time_gmt' => $date->toSql( false ) ); if ( $course->is_required_enroll() && ! $force ) { if ( ! $order = learn_press_get_order( $order_id ) ) { 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 ); } // $data = array_merge( // array( // 'user_id' => $this->get_id(), // 'item_id' => $course_id, // ), // $data // ); // $wpdb->insert( // $wpdb->learnpress_user_items, // $data, // array( '%d', '%d', '%s', '%s', '%d', '%s', '%d', '%s', '%s' ) // ); // // return $wpdb->insert_id; } else { $data = array_merge( array( 'user_id' => $this->get_id(), 'item_id' => $course_id, ), $data ); } //else { learn_press_remove_message( '', 'error' ); if ( $return = $this->_curd->update_user_item( $this->get_id(), $course_id, $data ) ) { if ( is_user_logged_in() ) { do_action( 'learn-press/user-enrolled-course', $course_id, $this->get_id(), $return ); // @deprecated do_action( 'learn_press_user_enrolled_course', $course_id, $this->get_id(), $return ); } } //} 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 ) { if ( $question = LP_Question::get_question( $question_id ) ) { $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 */ public function get_purchased_courses( $args = array() ) { return $this->_curd->query_purchased_courses( $this->get_id(), $args ); } /** * @return array */ public function get_roles() { return (array) $this->get_data( 'roles' ); } /** * @return int */ public function _get_found_rows() { return $this->_FOUND_ROWS; } /** * @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 = '' ) { $uploaded_profile_src = $this->get_data( 'uploaded_profile_src' ); if ( empty( $uploaded_profile_src ) ) { if ( $profile_picture = $this->get_data( 'profile_picture' ) ) { $upload = learn_press_user_profile_picture_upload_dir(); $file_path = $upload['basedir'] . DIRECTORY_SEPARATOR . $profile_picture; if ( file_exists( $file_path ) ) { $uploaded_profile_src = $upload['baseurl'] . '/' . $profile_picture; // no cache for first time after avatar changed if ( $this->get_data( 'profile_picture_changed' ) == 'yes' ) { $uploaded_profile_src = add_query_arg( 'r', md5( rand( 0, 10 ) / rand( 1, 1000000 ) ), $this->get_data( 'uploaded_profile_src' ) ); delete_user_meta( $this->get_id(), '_lp_profile_picture_changed' ); } } else { $uploaded_profile_src = false; } $this->_set_data( 'uploaded_profile_src', $uploaded_profile_src ); } } return $uploaded_profile_src; } /** * @param string $type * @param int $size * * @return false|string */ public function get_profile_picture( $type = '', $size = 96 ) { if ( $type == 'gravatar' ) { remove_filter( 'pre_get_avatar', 'learn_press_pre_get_avatar_callback', 1, 5 ); } if ( $profile_picture_src = $this->get_upload_profile_src( $size ) ) { $this->profile_picture_src = $profile_picture_src; } $avatar = get_avatar( $this->get_id(), $size, '', '', array( 'gravatar' => false ) ); if ( $type == 'gravatar' ) { add_filter( 'pre_get_avatar', 'learn_press_pre_get_avatar_callback', 1, 5 ); } return $avatar; } /** * @return string */ public function get_profile_picture_src() { $profile_picture_type = $this->profile_picture_type; if ( $profile_picture_type == 'picture' ) { if ( $profile_picture_src = $this->get_upload_profile_src() ) { $this->profile_picture_src = $profile_picture_src; } } else { $avatar_data = get_avatar_data( $this->get_id() ); $this->profile_picture_src = $avatar_data['url']; } return $this->profile_picture_src; } /** * @param $url * @param $id_or_email * @param $args * * @return bool */ public function get_avatar_url( $url, $id_or_email, $args ) { if ( is_numeric( $id_or_email ) && $id_or_email == $this->get_id() ) { $url = $this->get_data( 'profile_picture_src' ); } if ( $id_or_email == $this->get_data( 'user_login' ) ) { $url = $this->get_data( 'profile_picture_src' ); } return $url; } /** * Check if user can access to a course. * * @param int $course_id * * @return mixed */ public function can_access_course( $course_id ) { $return = apply_filters( 'learn-press/user-can-access-course', $this->get_order_status( $course_id ) == 'lp-completed', $course_id, $this->get_id() ); // Deprecated since 3.0.0 $return = apply_filters( 'learn_press_user_can_access_course', $return, $course_id, $this->get_id() ); return $return; } /** * 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 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 * + false All other cases, e.g: not enrolled * * @param $course_id * * @return string|bool */ public function get_course_grade( $course_id ) { $grade = false; if ( $course_data = $this->get_course_data( $course_id ) ) { $grade = $course_data->get_grade(); } 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() { return ! $this->get_id() || ! get_user_by( 'id', $this->get_id() ); } /** * Load course data for the user. * * @param mixed $the_course */ public function read_course( $the_course ) { $this->_curd->read_course( $this->get_id(), $the_course ); } /** * Check if user can edit a post. * * @param int $post_id * * @return bool */ public function can_edit( $post_id ) { if ( $this->get_id() !== get_current_user_id() ) { return false; } return current_user_can( 'edit_post', $post_id ); } /** * @return array|mixed */ public function get_email() { return $this->get_data( 'email' ); } /** * Return user_login of the user. * * @return string */ public function get_username() { return $this->get_data( 'user_login' ); } /** * Return user bio information. * * @return string */ public function get_description() { return $this->get_data( 'description' ); } /** * Return user first name. * * @return string */ public function get_first_name() { return $this->get_data( 'first_name' ); } /** * Return user last name. * * @return string */ public function get_last_name() { return $this->get_data( 'last_name' ); } /** * Return user nickname. * * @return string */ public function get_nickname() { return $this->get_data( 'nickname' ); } /** * Return user display name. * * @return string */ public function get_display_name() { return $this->get_data( 'display_name' ); } } }