Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/masterstudy-lms-learning-management-system/_core/includes/post_type/posts.php
+++ b/masterstudy-lms-learning-management-system/_core/includes/post_type/posts.php
@@ -15,12 +15,6 @@
$post_types = $this->post_types();
foreach ( $post_types as $post_type => $post_type_info ) {
- $current_user = STM_LMS_User::get_current_user( null, true );
-
- if ( ! empty( $current_user['id'] ) && in_array( STM_LMS_Instructor::role(), $current_user['roles'], true ) ) {
- $post_type_info['args']['show_in_menu'] = true;
- }
-
$add_args = ( ! empty( $post_type_info['args'] ) ) ? $post_type_info['args'] : array();
$args = $this->post_type_args(
$this->post_types_labels( $post_type_info['single'], $post_type_info['plural'] ),
--- a/masterstudy-lms-learning-management-system/_core/includes/post_type/taxonomies.php
+++ b/masterstudy-lms-learning-management-system/_core/includes/post_type/taxonomies.php
@@ -70,8 +70,9 @@
'new_item_name' => __( 'New Question category Name', 'masterstudy-lms-learning-management-system' ),
'menu_name' => __( 'Question category', 'masterstudy-lms-learning-management-system' ),
),
- 'show_ui' => true,
- 'show_admin_column' => true,
+ 'show_ui' => false,
+ 'show_in_menu' => false,
+ 'show_admin_column' => false,
'query_var' => true,
),
),
--- a/masterstudy-lms-learning-management-system/_core/includes/user_manager/UserManager.AddUser.php
+++ b/masterstudy-lms-learning-management-system/_core/includes/user_manager/UserManager.AddUser.php
@@ -1,52 +0,0 @@
-<?php
-
-new STM_LMS_User_Manager_Add_User();
-
-class STM_LMS_User_Manager_Add_User {
-
- public function __construct() {
- add_action( 'wp_ajax_stm_lms_dashboard_add_user_to_course', array( $this, 'add_user' ) );
- }
-
- public function add_user() {
- check_ajax_referer( 'stm_lms_dashboard_add_user_to_course', 'nonce' );
-
- $request_body = file_get_contents( 'php://input' );
-
- $data = json_decode( $request_body, true );
-
- if ( empty( $data['email'] ) ) {
- die;
- }
-
- $email = sanitize_text_field( $data['email'] );
- $course_id = absint( $data['course_id'] ?? 0 );
- $user_id = get_current_user_id();
-
- if ( ! is_email( $email ) || empty( $course_id ) || empty( $user_id ) ) {
- wp_send_json(
- array(
- 'status' => 'error',
- 'message' => esc_html__( 'Invalid request.', 'masterstudy-lms-learning-management-system' ),
- )
- );
- }
-
- if ( ! STM_LMS_Course::check_course_author( $course_id, $user_id ) && ! current_user_can( 'edit_post', $course_id ) ) {
- wp_send_json_error(
- array(
- 'message' => esc_html__( 'Unauthorized request.', 'masterstudy-lms-learning-management-system' ),
- ),
- 403
- );
- }
-
- $adding = STM_LMS_Instructor::add_student_to_course( array( $course_id ), array( $email ) );
-
- if ( ! $adding['error'] ) {
- $adding['status'] = 'success';
- }
-
- wp_send_json( $adding );
- }
-}
--- a/masterstudy-lms-learning-management-system/_core/includes/user_manager/UserManager.Course.php
+++ b/masterstudy-lms-learning-management-system/_core/includes/user_manager/UserManager.Course.php
@@ -48,7 +48,7 @@
$avatar_url = get_avatar_url( 'guest@example.com' );
if ( $user ) {
- $avatar_url = get_avatar_url( $user->ID );
+ $avatar_url = STM_LMS_User::get_avatar_url( $user->ID );
}
$avatar_img = "<img src='" . esc_url( $avatar_url ) . "' class='avatar' alt='User Avatar'>";
--- a/masterstudy-lms-learning-management-system/_core/includes/user_manager/UserManager.CourseUser.php
+++ b/masterstudy-lms-learning-management-system/_core/includes/user_manager/UserManager.CourseUser.php
@@ -1,69 +1,9 @@
<?php
use MasterStudyLmsProaddonsassignmentsRepositoriesAssignmentStudentRepository;
-use MasterStudyLmsRepositoriesCurriculumMaterialRepository;
use MasterStudyLmsRepositoriesCurriculumRepository;
-new STM_LMS_User_Manager_Course_User();
-
class STM_LMS_User_Manager_Course_User {
-
- public function __construct() {
- add_action( 'wp_ajax_stm_lms_dashboard_reset_student_progress', array( $this, 'reset_student_progress' ) );
- add_action( 'wp_ajax_stm_lms_dashboard_get_student_progress', array( $this, 'student_progress' ) );
- add_action( 'wp_ajax_stm_lms_dashboard_set_student_item_progress', array( $this, 'set_student_progress' ) );
- }
-
- public function reset_student_progress() {
- check_ajax_referer( 'stm_lms_dashboard_reset_student_progress', 'nonce' );
-
- if ( ! STM_LMS_User_Manager_Interface::isInstructor() ) {
- die;
- }
-
- $request_body = file_get_contents( 'php://input' );
-
- $data = json_decode( $request_body, true );
-
- if ( empty( $data['user_id'] ) || empty( $data['course_id'] ) ) {
- die;
- }
-
- $course_id = intval( $data['course_id'] );
- $student_id = intval( $data['user_id'] );
-
- $curriculum = ( new CurriculumRepository() )->get_curriculum( $course_id );
-
- if ( empty( $curriculum['materials'] ) ) {
- die;
- }
-
- foreach ( $curriculum['materials'] as $material ) {
- switch ( $material['post_type'] ) {
- case 'stm-lessons':
- self::reset_lesson( $student_id, $course_id, $material['post_id'] );
- break;
- case 'stm-assignments':
- self::reset_assignment( $student_id, $course_id, $material['post_id'] );
- break;
- case 'stm-quizzes':
- self::reset_quiz( $student_id, $course_id, $material['post_id'] );
- break;
- }
- }
-
- stm_lms_reset_user_answers( $course_id, $student_id );
- stm_lms_reset_marker_answers( $course_id, $student_id );
-
- $flag_key = 'masterstudy_lms_email_sent_' . (int) $course_id . '_' . (int) $student_id;
-
- update_option( $flag_key, 0 );
-
- STM_LMS_Course::update_course_progress( $student_id, $course_id, true );
-
- wp_send_json( self::_student_progress( $course_id, $student_id ) );
- }
-
// phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore
public static function _student_progress( $course_id, $student_id ) {
$curriculum = ( new CurriculumRepository() )->get_curriculum( $course_id );
@@ -101,80 +41,6 @@
return $curriculum;
}
- public function student_progress() {
- check_ajax_referer( 'stm_lms_dashboard_get_student_progress', 'nonce' );
-
- if ( ! STM_LMS_User_Manager_Interface::isInstructor() ) {
- die;
- }
-
- $request_body = file_get_contents( 'php://input' );
-
- $data = json_decode( $request_body, true );
-
- if ( empty( $data['user_id'] ) || empty( $data['course_id'] ) ) {
- die;
- }
-
- $course_id = intval( $data['course_id'] );
- $student_id = intval( $data['user_id'] );
-
- wp_send_json( self::_student_progress( $course_id, $student_id ) );
- }
-
- public function set_student_progress() {
- check_ajax_referer( 'stm_lms_dashboard_set_student_item_progress', 'nonce' );
-
- if ( ! STM_LMS_User_Manager_Interface::isInstructor() ) {
- die;
- }
-
- $request_body = file_get_contents( 'php://input' );
-
- $data = json_decode( $request_body, true );
-
- if ( empty( $data['user_id'] ) || empty( $data['course_id'] ) || empty( $data['item_id'] ) ) {
- die;
- }
-
- $course_id = intval( $data['course_id'] );
- $student_id = intval( $data['user_id'] );
- $item_id = intval( $data['item_id'] );
- $completed = boolval( $data['completed'] );
-
- /*For various item types*/
- /*Check item in curriculum*/
- $course_materials = ( new CurriculumMaterialRepository() )->get_course_materials( $course_id );
-
- if ( empty( $course_materials ) ) {
- die;
- }
-
- if ( ! in_array( $item_id, $course_materials, true ) ) {
- die;
- }
-
- switch ( get_post_type( $item_id ) ) {
- case 'stm-lessons':
- self::complete_lesson( $student_id, $course_id, $item_id );
- break;
- case 'stm-assignments':
- self::complete_assignment( $student_id, $course_id, $item_id, $completed );
- break;
- case 'stm-quizzes':
- self::complete_quiz( $student_id, $course_id, $item_id, $completed );
- break;
- }
-
- if ( ! $completed ) {
- stm_lms_reset_marker_answers( $course_id, $student_id );
- }
-
- STM_LMS_Course::update_course_progress( $student_id, $course_id );
-
- wp_send_json( self::_student_progress( $course_id, $student_id ) );
- }
-
public static function complete_lesson( $user_id, $course_id, $lesson_id ) {
$user_lesson = stm_lms_get_user_lesson( $user_id, $course_id, $lesson_id );
--- a/masterstudy-lms-learning-management-system/_core/includes/user_manager/UserManager.Courses.php
+++ b/masterstudy-lms-learning-management-system/_core/includes/user_manager/UserManager.Courses.php
@@ -1,37 +0,0 @@
-<?php
-
-new STM_LMS_User_Manager_Courses();
-
-class STM_LMS_User_Manager_Courses {
-
- public function __construct() {
- add_action( 'wp_ajax_stm_lms_dashboard_get_courses_list', array( $this, 'course_list' ) );
- }
-
- public function course_list() {
- check_ajax_referer( 'stm_lms_dashboard_get_courses_list', 'nonce' );
-
- $args = apply_filters( 'stm_lms_archive_filter_args', array( 'posts_per_page' => 4 ) );
-
- $courses = STM_LMS_Instructor::get_courses( $args, true, STM_LMS_User_Manager_Interface::isInstructor() );
-
- $courses['posts'] = array_map(
- function ( $course ) {
- $course_id = $course['id'];
-
- $course['categories'] = stm_lms_get_terms_array( $course_id, 'stm_lms_course_taxonomy', 'name' );
-
- return $course;
- },
- $courses['posts']
- );
-
- wp_send_json( $courses );
- }
-
- public static function published() {
- $courses = wp_count_posts( 'stm-courses' );
-
- return $courses->publish ?? 0;
- }
-}
--- a/masterstudy-lms-learning-management-system/_core/includes/user_manager/UserManager.ImportUsers.php
+++ b/masterstudy-lms-learning-management-system/_core/includes/user_manager/UserManager.ImportUsers.php
@@ -1,106 +0,0 @@
-<?php
-
-new STM_LMS_User_Manager_Import_Users();
-
-class STM_LMS_User_Manager_Import_Users {
-
- public function __construct() {
- add_action(
- 'wp_ajax_stm_lms_dashboard_import_users_to_course',
- array( $this, 'import_users' )
- );
- }
-
- public function import_users() {
- if ( ! current_user_can( 'manage_options' ) ) {
- wp_send_json_error( array( 'message' => 'Forbidden' ), 403 );
- }
-
- check_ajax_referer( 'stm_lms_dashboard_import_users_to_course', 'nonce' );
-
- $request_body = file_get_contents( 'php://input' );
- $data = json_decode( $request_body, true );
-
- $imported_users = $data['users'] ?? array();
- $course_id = (int) ( $data['course_id'] ?? 0 );
-
- if ( ! $course_id || empty( $imported_users ) ) {
- wp_send_json_error( array( 'message' => 'Invalid payload' ), 400 );
- }
-
- $output = array(
- 'not_enrolled_users' => array(),
- 'new_enrolled_users' => array(),
- 'incorrect_email_users' => array(),
- 'before_enrolled_users' => array(),
- );
-
- $course_users = stm_lms_get_course_users( $course_id );
- $enrolled_ids = array();
-
- foreach ( $course_users as $course_user ) {
- $user_id = (int) ( $course_user['user_id'] ?? 0 );
- if ( $user_id ) {
- $enrolled_ids[ $user_id ] = true;
- }
- }
-
- foreach ( $imported_users as $imported_user ) {
- $email = $imported_user['email'] ?? '';
-
- if ( ! is_email( $email ) ) {
- $output['incorrect_email_users'][] = $imported_user;
- continue;
- }
-
- $user = get_user_by( 'email', $email );
-
- if ( $user && isset( $enrolled_ids[ (int) $user->ID ] ) ) {
- $output['before_enrolled_users'][] = $imported_user;
- continue;
- }
-
- $adding_student = STM_LMS_Instructor::add_student_to_course(
- array( $course_id ),
- array( $email )
- );
-
- if ( is_array( $adding_student ) && empty( $adding_student['error'] ) ) {
- $output['new_enrolled_users'][] = $imported_user;
- $this->update_user_names( $email, $imported_user );
- } else {
- $output['not_enrolled_users'][] = $imported_user;
- }
- }
-
- wp_send_json_success( $output );
- }
-
-
- public function update_user_names( $email, $user_data = array() ) {
- $first_name = sanitize_text_field(
- trim( $user_data['first_name'] ?? '' )
- );
- $last_name = sanitize_text_field(
- trim( $user_data['last_name'] ?? '' )
- );
-
- if ( ! $first_name && ! $last_name ) {
- return;
- }
-
- $user = get_user_by( 'email', $email );
-
- if ( ! $user ) {
- return;
- }
-
- wp_update_user(
- array(
- 'ID' => $user->ID,
- 'first_name' => $first_name,
- 'last_name' => $last_name,
- )
- );
- }
-}
--- a/masterstudy-lms-learning-management-system/_core/includes/user_manager/UserManager.Interface.php
+++ b/masterstudy-lms-learning-management-system/_core/includes/user_manager/UserManager.Interface.php
@@ -1,103 +0,0 @@
-<?php
-
-new STM_LMS_User_Manager_Interface();
-
-
-class STM_LMS_User_Manager_Interface {
-
- public function __construct() {
- add_action( 'admin_menu', array( $this, 'dashboard_menu' ) );
-
- add_action( 'wp_enqueue_scripts', array( $this, 'scripts' ) );
- add_action( 'admin_enqueue_scripts', array( $this, 'scripts' ) );
-
- add_action( 'admin_footer', array( $this, 'components' ) );
- add_action( 'wp_footer', array( $this, 'components' ) );
- }
-
- public function dashboard_menu() {
- add_menu_page(
- esc_html__( 'LMS Dashboard', 'masterstudy-lms-learning-management-system' ),
- esc_html__( 'LMS Dashboard', 'masterstudy-lms-learning-management-system' ),
- 'manage_options',
- 'stm-lms-dashboard',
- array( $this, 'dashboard_view' ),
- 'dashicons-clipboard',
- 7
- );
- }
-
- public function dashboard_view() {
- STM_LMS_Templates::show_lms_template( 'dashboard/dashboard' );
- }
-
- public function scripts( $hook ) {
- if ( 'toplevel_page_stm-lms-dashboard' === $hook ) {
- stm_lms_register_style( 'dashboard/dashboard' );
-
- // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.NotInFooter
- wp_register_script( 'vue-router.js', 'https://cdn.jsdelivr.net/npm/vue-router@2.0.0/dist/vue-router.min.js', array(), '2.0.0' );
-
- $components = self::components_list();
-
- foreach ( $components as $component ) {
- stm_lms_register_script( "dashboard/components/{$component}" );
- }
-
- wp_localize_script(
- 'stm-lms-dashboard/components/course',
- 'course_data',
- array(
- 'student_public' => STM_LMS_Options::get_option( 'student_public_profile', true ),
- )
- );
-
- stm_lms_register_script(
- 'dashboard/dashboard',
- array(
- 'vue.js',
- 'vue-resource.js',
- 'vue-router.js',
- ),
- true
- );
- }
- }
-
- public function components() {
- $components = self::components_list();
-
- foreach ( $components as $component ) {
- self::wrap_component( $component );
- }
- }
-
- public function components_list() {
- return array(
- 'home',
- 'navigation',
- 'add_user',
- 'user_data_transfer',
- 'student_assignments',
- 'student_quiz',
- 'back',
- 'courses',
- 'course',
- 'course_user',
- );
- }
-
- public static function wrap_component( $component ) {
- if ( is_admin() ) {
- ?>
- <script type="text/html" id="<?php echo esc_attr( "stm-lms-dashboard-{$component}" ); ?>">
- <?php STM_LMS_Templates::show_lms_template( "dashboard/components/{$component}" ); ?>
- </script>
- <?php
- }
- }
-
- public static function isInstructor() {
- return current_user_can( 'manage_options' );
- }
-}
--- a/masterstudy-lms-learning-management-system/_core/includes/user_manager/UserManager.UserAssignments.php
+++ b/masterstudy-lms-learning-management-system/_core/includes/user_manager/UserManager.UserAssignments.php
@@ -1,84 +0,0 @@
-<?php
-
-new STM_LMS_User_Manager_User_Assignments();
-
-class STM_LMS_User_Manager_User_Assignments {
-
- public function __construct() {
- add_action( 'wp_ajax_stm_lms_dashboard_get_student_assignments', array( $this, 'student_assignments' ) );
- }
-
- public function student_assignments() {
- check_ajax_referer( 'stm_lms_dashboard_get_student_assignments', 'nonce' );
-
- if ( ! STM_LMS_User_Manager_Interface::isInstructor() ) {
- die;
- }
-
- $request_body = file_get_contents( 'php://input' );
-
- $data = json_decode( $request_body, true );
-
- if ( empty( $data['student_id'] ) || empty( $data['assignment_id'] ) ) {
- die;
- }
-
- $course_id = intval( $data['course_id'] );
- $student_id = intval( $data['student_id'] );
- $assignment_id = intval( $data['assignment_id'] );
-
- $args = array(
- 'posts_per_page' => - 1,
- 'post_type' => 'stm-user-assignment',
- 'post_status' => array(
- 'pending',
- 'publish',
- ),
- 'meta_key' => 'try_num',
- 'orderby' => 'meta_value title',
- 'order' => 'ASC',
- 'meta_query' => array(
- 'relation' => 'AND',
- array(
- 'key' => 'assignment_id',
- 'value' => $assignment_id,
- 'compare' => '=',
- ),
- array(
- 'key' => 'student_id',
- 'value' => $student_id,
- 'compare' => '=',
- ),
- ),
- );
-
- $q = new WP_Query( $args );
-
- $posts = array();
-
- if ( $q->have_posts() ) {
- while ( $q->have_posts() ) {
- $q->the_post();
- $id = get_the_ID();
- $post = array();
- $post['id'] = $id;
- $post['post_status'] = get_post_status( $id );
- $post['title'] = get_the_title();
- $post['meta'] = STM_LMS_Helpers::simplify_meta_array( get_post_meta( get_the_ID() ) );
- $post['content'] = get_the_content();
-
- $posts[] = $post;
- }
- }
-
- wp_send_json(
- array(
- 'assignments' => $posts,
- 'title' => get_the_title( $course_id ),
- 'user' => STM_LMS_User::get_current_user( $student_id ),
- 'instructor' => STM_LMS_User::get_current_user( get_post_field( 'post_author', $course_id ), null, true ),
- )
- );
-
- }
-}
--- a/masterstudy-lms-learning-management-system/_core/includes/user_manager/UserManager.UserQuiz.php
+++ b/masterstudy-lms-learning-management-system/_core/includes/user_manager/UserManager.UserQuiz.php
@@ -1,131 +0,0 @@
-<?php
-
-new STM_LMS_User_Manager_User_Quiz();
-
-class STM_LMS_User_Manager_User_Quiz {
-
- public function __construct() {
- add_action( 'wp_ajax_stm_lms_dashboard_get_student_quizzes', array( $this, 'student_quizzes' ) );
- add_action( 'wp_ajax_stm_lms_dashboard_get_student_quiz', array( $this, 'student_quiz' ) );
- }
-
- public function student_quizzes() {
- check_ajax_referer( 'stm_lms_dashboard_get_student_quizzes', 'nonce' );
-
- if ( ! STM_LMS_User_Manager_Interface::isInstructor() ) {
- die;
- }
-
- $request_body = file_get_contents( 'php://input' );
-
- $data = json_decode( $request_body, true );
-
- if ( empty( $data['student_id'] ) || empty( $data['quiz_id'] ) ) {
- die;
- }
-
- $course_id = intval( $data['course_id'] );
- $student_id = intval( $data['student_id'] );
- $quiz_id = intval( $data['quiz_id'] );
-
- $quizzes = stm_lms_get_user_all_course_quizzes( $student_id, $course_id, $quiz_id );
-
- $quizzes = array_map(
- function ( $quiz ) {
- $quiz['title'] = get_the_title( $quiz['quiz_id'] );
-
- return $quiz;
- },
- $quizzes
- );
-
- wp_send_json( $quizzes );
-
- }
-
- public function student_quiz() {
- check_ajax_referer( 'stm_lms_dashboard_get_student_quiz', 'nonce' );
-
- if ( ! STM_LMS_User_Manager_Interface::isInstructor() ) {
- die;
- }
-
- $request_body = file_get_contents( 'php://input' );
-
- $data = json_decode( $request_body, true );
-
- if ( empty( $data['student_id'] ) || empty( $data['quiz_id'] ) ) {
- die;
- }
-
- $course_id = intval( $data['course_id'] );
- $student_id = intval( $data['student_id'] );
- $quiz_id = intval( $data['quiz_id'] );
- $user_quiz_id = intval( $data['user_quiz_id'] );
- $attempt = intval( $data['attempt'] );
-
- $questions = get_post_meta( $quiz_id, 'questions', true );
-
- $args = array(
- 'post_type' => 'stm-questions',
- 'posts_per_page' => - 1,
- 'post__in' => explode( ',', $questions ),
- 'orderby' => 'post__in',
- );
-
- $item_id = $quiz_id;
-
- $q = new WP_Query( $args );
-
- ob_start(); ?>
-
- <link rel="stylesheet" href="<?php echo esc_url( STM_LMS_URL . 'assets/css/parts/quiz.css' ); // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet ?>"/>
- <link rel="stylesheet" href="<?php echo esc_url( STM_LMS_URL . 'assets/css/parts/keywords_question.css' ); // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet ?>"/>
- <link rel="stylesheet" href="<?php echo esc_url( STM_LMS_URL . 'assets/css/parts/item_match_question.css' ); // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet ?>"/>
- <link rel="stylesheet" href="<?php echo esc_url( STM_LMS_URL . 'assets/css/parts/sortable_question_admin.css' ); // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet ?>"/>
- <link rel="stylesheet" href="<?php echo esc_url( STM_LMS_URL . 'assets/css/parts/image_match_question.css' ); // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet ?>"/>
- <link rel="stylesheet" href="<?php echo esc_url( STM_LMS_URL . 'assets/css/parts/fill_the_gap.css' ); // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet ?>"/>
-
- <?php
- if ( $q->have_posts() ) {
- $last_answers = stm_lms_get_quiz_attempt_answers(
- $student_id,
- $quiz_id,
- array(
- 'question_id',
- 'user_answer',
- 'correct_answer',
- 'questions_order',
- ),
- $attempt
- );
-
- $last_answers = STM_LMS_Helpers::set_value_as_key( $last_answers, 'question_id' );
- ?>
-
- <?php if ( empty( $last_answers ) ) { ?>
- <h4 class="empty_quiz"><?php esc_html_e( 'User has no answers on this quiz.', 'masterstudy-lms-learning-management-system' ); ?></h4>
- <?php
- wp_send_json( ob_get_clean() );
- }
-
- $question_index = 0;
-
- while ( $q->have_posts() ) {
-
- $q->the_post();
- $question_index ++;
- $show_answers = true;
- ?>
- <span class="stm-lms-single_quiz__label"></span>
- <?php
- STM_LMS_Templates::show_lms_template(
- 'quiz/question',
- compact( 'item_id', 'last_answers', 'question_index', 'show_answers' )
- );
- }
- }
-
- wp_send_json( ob_get_clean() );
- }
-}
--- a/masterstudy-lms-learning-management-system/_core/includes/user_manager/main.php
+++ b/masterstudy-lms-learning-management-system/_core/includes/user_manager/main.php
@@ -1,10 +1,4 @@
<?php
-require_once STM_LMS_PATH . '/includes/user_manager/UserManager.Interface.php';
-require_once STM_LMS_PATH . '/includes/user_manager/UserManager.Courses.php';
require_once STM_LMS_PATH . '/includes/user_manager/UserManager.Course.php';
require_once STM_LMS_PATH . '/includes/user_manager/UserManager.CourseUser.php';
-require_once STM_LMS_PATH . '/includes/user_manager/UserManager.AddUser.php';
-require_once STM_LMS_PATH . '/includes/user_manager/UserManager.ImportUsers.php';
-require_once STM_LMS_PATH . '/includes/user_manager/UserManager.UserAssignments.php';
-require_once STM_LMS_PATH . '/includes/user_manager/UserManager.UserQuiz.php';
--- a/masterstudy-lms-learning-management-system/_core/init.php
+++ b/masterstudy-lms-learning-management-system/_core/init.php
@@ -3,7 +3,7 @@
define( 'STM_LMS_DIR', __DIR__ );
define( 'STM_LMS_PATH', dirname( STM_LMS_FILE ) );
define( 'STM_LMS_URL', plugin_dir_url( STM_LMS_FILE ) );
-define( 'STM_LMS_VERSION', '3.7.30' );
+define( 'STM_LMS_VERSION', '3.7.31' );
define( 'STM_LMS_DB_VERSION', '3.7.5' );
define( 'STM_LMS_BASE_API_URL', '/wp-json/lms' );
define( 'STM_LMS_LIBRARY', STM_LMS_PATH . '/libraries' );
--- a/masterstudy-lms-learning-management-system/_core/libraries/db/helpers/user_courses.php
+++ b/masterstudy-lms-learning-management-system/_core/libraries/db/helpers/user_courses.php
@@ -313,14 +313,15 @@
if ( empty( $user_ids ) ) {
return array(
- 'data' => array(),
- 'total' => 0,
+ 'data' => array(),
+ 'total' => 0,
'lessons_deleted' => 0,
);
}
- $user_ids = array_map( 'absint', $user_ids );
- $current_user = (int) get_current_user_id();
+ $user_ids = array_map( 'absint', $user_ids );
+ $is_admin = current_user_can( 'administrator' );
+ $author_filter = $is_admin ? '' : 'AND p.post_author = %d';
$courses_table = stm_lms_user_courses_name( $wpdb );
$lessons_table = stm_lms_user_lessons_name( $wpdb );
@@ -328,14 +329,14 @@
$answers_table = stm_lms_user_answers_name( $wpdb );
$placeholders = implode( ',', array_fill( 0, count( $user_ids ), '%d' ) );
- $params = array_merge( $user_ids, array( $current_user ) );
+ $params = $is_admin ? $user_ids : array_merge( $user_ids, array( (int) get_current_user_id() ) );
$delete_quizzes_sql = "
DELETE uq
FROM {$quizzes_table} AS uq
INNER JOIN {$wpdb->posts} AS p ON uq.course_id = p.ID
WHERE uq.user_id IN ( {$placeholders} )
- AND p.post_author = %d
+ {$author_filter}
";
$delete_answers_sql = "
@@ -343,7 +344,7 @@
FROM {$answers_table} AS ua
INNER JOIN {$wpdb->posts} AS p ON ua.course_id = p.ID
WHERE ua.user_id IN ( {$placeholders} )
- AND p.post_author = %d
+ {$author_filter}
";
$select_sql = "
@@ -351,7 +352,7 @@
FROM {$courses_table} AS uc
INNER JOIN {$wpdb->posts} AS p ON uc.course_id = p.ID
WHERE uc.user_id IN ( {$placeholders} )
- AND p.post_author = %d
+ {$author_filter}
";
$delete_lessons_sql = "
@@ -362,7 +363,7 @@
AND ul.course_id = uc.course_id
INNER JOIN {$wpdb->posts} AS p ON uc.course_id = p.ID
WHERE uc.user_id IN ( {$placeholders} )
- AND p.post_author = %d
+ {$author_filter}
";
$delete_courses_sql = "
@@ -370,7 +371,7 @@
FROM {$courses_table} AS uc
INNER JOIN {$wpdb->posts} AS p ON uc.course_id = p.ID
WHERE uc.user_id IN ( {$placeholders} )
- AND p.post_author = %d
+ {$author_filter}
";
$data = $wpdb->get_results(
@@ -524,13 +525,13 @@
// Validate and sanitize orderby parameter to prevent SQL injection
$allowed_orderby_fields = array(
- 'joined' => 'u.user_registered',
- 'enrolled' => 'c.enrolled',
- 'points' => 'p.points',
- 'id' => 'u.ID',
- 'name' => 'u.display_name',
- 'email' => 'u.user_email',
- 'login' => 'u.user_login',
+ 'joined' => 'u.user_registered',
+ 'enrolled' => 'c.enrolled',
+ 'points' => 'p.points',
+ 'id' => 'u.ID',
+ 'name' => 'u.display_name',
+ 'email' => 'u.user_email',
+ 'login' => 'u.user_login',
);
// Default to safe field if orderby is not in whitelist
@@ -680,7 +681,7 @@
}
return array_map(
- fn( $uid) => array(
+ fn( $uid ) => array(
'ID' => $uid,
'courses' => $grouped[ $uid ] ?? array(),
),
--- a/masterstudy-lms-learning-management-system/_core/libraries/support-page-integration.php
+++ b/masterstudy-lms-learning-management-system/_core/libraries/support-page-integration.php
@@ -1,4 +1,12 @@
<?php
+function masterstudy_lms_render_support_page() {
+ if ( ! current_user_can( 'manage_options' ) || ! class_exists( 'STM_Support_Page' ) ) {
+ return;
+ }
+
+ STM_Support_Page::render_support_page( 'masterstudy-lms-learning-management-system' );
+}
+
add_action(
'admin_init',
function() {
--- a/masterstudy-lms-learning-management-system/_core/lms/asset-helpers.php
+++ b/masterstudy-lms-learning-management-system/_core/lms/asset-helpers.php
@@ -0,0 +1,166 @@
+<?php
+
+if ( ! defined( 'ABSPATH' ) ) {
+ exit; // Exit if accessed directly
+}
+
+if ( ! function_exists( 'masterstudy_lms_read_manifest' ) ) {
+ /**
+ * Read Vite manifest for a specific app and cache it in-memory per request.
+ *
+ * @param string $app_slug App assets folder inside assets/react.
+ *
+ * @return array
+ */
+ function masterstudy_lms_read_manifest( string $app_slug ): array {
+ static $manifests = array();
+
+ $app_slug = trim( (string) $app_slug );
+ if ( empty( $app_slug ) || ! preg_match( '/^[a-z0-9_-]+$/', $app_slug ) ) {
+ return array();
+ }
+
+ if ( isset( $manifests[ $app_slug ] ) ) {
+ return $manifests[ $app_slug ];
+ }
+
+ $manifest_path = MS_LMS_PATH . '/assets/react/' . $app_slug . '/manifest.json';
+ if ( file_exists( $manifest_path ) && is_readable( $manifest_path ) ) {
+ $manifest_contents = file_get_contents( $manifest_path ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
+
+ if ( false !== $manifest_contents ) {
+ $decoded = json_decode( (string) $manifest_contents, true );
+
+ if ( is_array( $decoded ) ) {
+ $manifests[ $app_slug ] = $decoded;
+ return $manifests[ $app_slug ];
+ }
+ }
+ }
+
+ $manifest_url = MS_LMS_URL . 'assets/react/' . $app_slug . '/manifest.json';
+ $response = function_exists( 'wp_remote_get' ) ? call_user_func( 'wp_remote_get', $manifest_url ) : false;
+ $decoded = array();
+
+ if ( false !== $response ) {
+ $is_wp_error = function_exists( 'is_wp_error' ) && (bool) is_wp_error( $response );
+ if ( ! $is_wp_error ) {
+ $response_body = function_exists( 'wp_remote_retrieve_body' ) ? wp_remote_retrieve_body( $response ) : '';
+ $decoded = json_decode( (string) $response_body, true );
+ }
+ }
+
+ $manifests[ $app_slug ] = is_array( $decoded ) ? $decoded : array();
+
+ return $manifests[ $app_slug ];
+ }
+}
+
+if ( ! function_exists( 'masterstudy_lms_asset_url_from_manifest_file' ) ) {
+ /**
+ * Convert Vite manifest file path to public plugin URL.
+ *
+ * @param string $app_slug App assets folder inside assets/react.
+ * @param string $file File path from manifest.
+ *
+ * @return string
+ */
+ function masterstudy_lms_asset_url_from_manifest_file( $app_slug, $file ): string {
+ $app_slug = trim( (string) $app_slug );
+ if ( empty( $app_slug ) || ! preg_match( '/^[a-z0-9_-]+$/', $app_slug ) ) {
+ return '';
+ }
+
+ $file = ltrim( preg_replace( '#^static/#', '', (string) $file ), '/' );
+ if ( empty( $file ) ) {
+ return '';
+ }
+
+ $path_parts = explode( '/', 'assets/react/' . $app_slug . '/' . $file );
+ $normalized_path = array();
+
+ foreach ( $path_parts as $path_part ) {
+ if ( '' === $path_part || '.' === $path_part ) {
+ continue;
+ }
+
+ if ( '..' === $path_part ) {
+ if ( count( $normalized_path ) > 2 ) {
+ array_pop( $normalized_path );
+ }
+ continue;
+ }
+
+ $normalized_path[] = $path_part;
+ }
+
+ return rtrim( MS_LMS_URL, '/' ) . '/' . implode( '/', $normalized_path );
+ }
+}
+
+if ( ! function_exists( 'masterstudy_lms_resolve_manifest_assets' ) ) {
+ /**
+ * Resolve entry file and imported chunks from Vite manifest.
+ *
+ * @param string $app_slug App assets folder inside assets/react.
+ * @param string $entry_name Expected entry name (manifest name or file basename).
+ *
+ * @return array|null
+ */
+ function masterstudy_lms_resolve_manifest_assets( string $app_slug, string $entry_name ): ?array {
+ $manifest = masterstudy_lms_read_manifest( $app_slug );
+ if ( empty( $manifest ) || empty( $entry_name ) ) {
+ return null;
+ }
+
+ $entry_key = null;
+ foreach ( $manifest as $key => $meta ) {
+ if ( ! is_array( $meta ) || empty( $meta['isEntry'] ) ) {
+ continue;
+ }
+
+ $manifest_name = isset( $meta['name'] ) ? (string) $meta['name'] : '';
+ $manifest_file = isset( $meta['file'] ) ? basename( (string) $meta['file'], '.js' ) : '';
+ $manifest_file_without_hash = preg_replace( '/.[^.]+$/', '', $manifest_file );
+ if ( $manifest_name === $entry_name || $manifest_file === $entry_name || $manifest_file_without_hash === $entry_name ) {
+ $entry_key = (string) $key;
+ break;
+ }
+ }
+
+ if ( null === $entry_key || empty( $manifest[ $entry_key ]['file'] ) ) {
+ return null;
+ }
+
+ $imports = array();
+ $visited = array();
+ $stack = isset( $manifest[ $entry_key ]['imports'] ) && is_array( $manifest[ $entry_key ]['imports'] )
+ ? $manifest[ $entry_key ]['imports']
+ : array();
+
+ while ( ! empty( $stack ) ) {
+ $import_key = array_pop( $stack );
+ if ( isset( $visited[ $import_key ] ) ) {
+ continue;
+ }
+ $visited[ $import_key ] = true;
+
+ if ( empty( $manifest[ $import_key ]['file'] ) ) {
+ continue;
+ }
+
+ $imports[] = masterstudy_lms_asset_url_from_manifest_file( $app_slug, $manifest[ $import_key ]['file'] );
+
+ if ( isset( $manifest[ $import_key ]['imports'] ) && is_array( $manifest[ $import_key ]['imports'] ) ) {
+ foreach ( $manifest[ $import_key ]['imports'] as $nested_import_key ) {
+ $stack[] = $nested_import_key;
+ }
+ }
+ }
+
+ return array(
+ 'entry_url' => masterstudy_lms_asset_url_from_manifest_file( $app_slug, $manifest[ $entry_key ]['file'] ),
+ 'imports' => array_values( array_unique( $imports ) ),
+ );
+ }
+}
--- a/masterstudy-lms-learning-management-system/_core/lms/classes/course.php
+++ b/masterstudy-lms-learning-management-system/_core/lms/classes/course.php
@@ -131,7 +131,7 @@
$course['for_points'] = $for_points;
$course['subscription_id'] = $subscription_id;
- if ( is_ms_lms_addon_enabled( 'grades' ) && masterstudy_lms_is_course_gradable( $course_id ) ) {
+ if ( is_ms_lms_addon_enabled( 'grades' ) && function_exists( 'masterstudy_lms_is_course_gradable' ) && masterstudy_lms_is_course_gradable( $course_id ) ) {
$course['is_gradable'] = 1;
}
@@ -385,9 +385,15 @@
return array(
'sections' => count( $section_ids ),
- 'lessons' => $materials->count_by_type( $section_ids, 'stm-lessons' ),
- 'quizzes' => $materials->count_by_type( $section_ids, 'stm-quizzes' ),
- 'assignments' => $materials->count_by_type( $section_ids, 'stm-assignments' ),
+ 'lessons' => $materials->count_by_types(
+ $section_ids,
+ array(
+ PostType::LESSON,
+ PostType::GOOGLE_MEET,
+ )
+ ),
+ 'quizzes' => $materials->count_by_type( $section_ids, PostType::QUIZ ),
+ 'assignments' => $materials->count_by_type( $section_ids, PostType::ASSIGNMENT ),
);
}
--- a/masterstudy-lms-learning-management-system/_core/lms/classes/instructors.php
+++ b/masterstudy-lms-learning-management-system/_core/lms/classes/instructors.php
@@ -1,5 +1,6 @@
<?php
+use MasterStudyLmsRepositoriesAdminInstructorRepository;
use MasterStudyLmsRepositoriesCurriculumMaterialRepository;
STM_LMS_Instructor::init();
@@ -42,7 +43,7 @@
add_action( 'pending_to_publish', 'STM_LMS_Instructor::post_published', 10, 2 );
- add_action( 'admin_menu', array( self::class, 'manage_users' ), 10000 );
+ add_action( 'admin_menu', array( self::class, 'manage_instructors' ), 10000 );
add_filter( 'ajax_query_attachments_args', 'STM_LMS_Instructor::restrict_media_to_own' );
@@ -136,7 +137,8 @@
}
if ( 'publish' === $status && ! current_user_can( 'manage_options' ) ) {
- $premoderation = STM_LMS_Options::get_option( 'course_premoderation', false );
+ $premoderation = STM_LMS_Helpers::is_pro()
+ && STM_LMS_Options::get_option( 'course_premoderation', false );
$status = ( $premoderation ) ? 'pending' : 'publish';
}
@@ -237,7 +239,7 @@
break;
case 'lms_course_students':
?>
- <a href="<?php echo esc_url( admin_url( "?page=stm-lms-dashboard#/course/{$post_id}" ) ); ?>" class="button action">
+ <a href="<?php echo esc_url( self::manage_course_students_admin_url( $post_id ) ); ?>" class="button action">
<?php echo esc_html__( 'Manage students', 'masterstudy-lms-learning-management-system' ); ?>
</a>
<?php if ( STM_LMS_Helpers::is_pro_plus() ) { ?>
@@ -327,7 +329,7 @@
}
}
- $co_instructors = array_filter( array_map( 'intval', $co_instructors ) );
+ $co_instructors = array_filter( array_map( 'intval', $co_instructors ) );
$is_course_co_instructor = in_array( (int) $user_id, $co_instructors, true );
}
@@ -534,6 +536,22 @@
$args['post_status'] = sanitize_text_field( $_GET['status'] );
}
+ if ( ! empty( $_GET['post_types'] ) ) {
+ $post_types_param = is_array( $_GET['post_types'] )
+ ? ''
+ : sanitize_text_field( wp_unslash( $_GET['post_types'] ) );
+
+ if ( '' !== $post_types_param ) {
+ $post_types = array_map( 'sanitize_key', explode( ',', (string) $post_types_param ) );
+ $allowed_post_types = array( 'stm-courses', 'stm-course-bundles' );
+ $post_types = array_values( array_intersect( $post_types, $allowed_post_types ) );
+
+ if ( ! empty( $post_types ) ) {
+ $args['post_type'] = $post_types;
+ }
+ }
+ }
+
if ( ! empty( $_GET['coming_soon_bundle'] ) ) {
$args['meta_query'][] = array(
'relation' => 'OR',
@@ -1047,6 +1065,10 @@
return STM_LMS_User::user_page_url() . 'manage-students';
}
+ public static function manage_course_students_admin_url( int $course_id ): string {
+ return admin_url( 'admin.php?page=manage_courses&subpage=manage_course_students&course_id=' . absint( $course_id ) );
+ }
+
public static function add_student_to_course( $raw_courses, $raw_emails ) {
$courses = array();
$emails = array();
@@ -1197,20 +1219,20 @@
return $users;
}
- public static function manage_users() {
+ public static function manage_instructors() {
add_submenu_page(
'stm-lms-settings',
esc_html__( 'Instructors', 'masterstudy-lms-learning-management-system' ),
'<span class="stm-lms-instructors-menu-title">' . esc_html__( 'Instructors', 'masterstudy-lms-learning-management-system' ) . '</span>',
'manage_options',
- 'manage_users',
- array( self::class, 'manage_users_template' ),
+ 'manage_instructors',
+ 'masterstudy_lms_render_admin_react_page',
stm_lms_addons_menu_position()
);
}
- public static function manage_users_template() {
- require_once STM_LMS_PATH . '/settings/manage_users/main.php';
+ public static function manage_instructors_template() {
+ STM_LMS_Templates::show_lms_template( 'components/admin-react-app/main' );
}
public static function get_submissions() {
@@ -1223,86 +1245,21 @@
);
}
- $page = ! empty( $_GET['page'] ) ? intval( $_GET['page'] ) : 1;
- $args = array(
- 'role__in' => array( 'subscriber', 'stm_lms_instructor' ),
- 'paged' => $page,
- 'number' => 20,
- 'orderby' => 'meta_value_num',
- 'order' => 'DESC',
- 'meta_query' => array(
- array(
- 'key' => 'submission_date',
- 'compare' => 'EXISTS',
- ),
- ),
+ $data = ( new AdminInstructorRepository() )->get_instructors(
+ array(
+ 'page' => isset( $_GET['page'] ) ? absint( $_GET['page'] ) : 1,
+ 'per_page' => 20,
+ 'order' => 'DESC',
+ )
);
- $users = new WP_User_Query( $args );
- $date_format = 'M j, Y - H:i';
- $r = array(
- 'total' => 0,
- 'users' => array(),
- 'ai_enabled_for_all' => self::get_is_ai_enabled_for_all(),
+ wp_send_json(
+ array(
+ 'total' => $data['total'],
+ 'users' => $data['instructors'],
+ 'ai_enabled_for_all' => $data['ai_enabled_for_all'],
+ )
);
- if ( ! empty( $users->get_results() ) ) {
- foreach ( $users->get_results() as $user ) {
- $user_id = $user->ID;
- $submission_data = get_user_meta( $user_id, 'become_instructor', true );
-
- $submission_date = get_user_meta( $user_id, 'submission_date', true );
- $degree = ! empty( $submission_data['degree'] ) ? $submission_data['degree'] : esc_html__( 'N/A', 'masterstudy-lms-learning-management-system' );
- $custom_fields = ! empty( $submission_data['fields'] ) && is_array( $submission_data['fields'] ) ? $submission_data['fields'] : array();
- $custom_fields = array_map(
- function( $field ) {
- if ( ! is_array( $field ) ) {
- return array();
- }
-
- $value = $field['value'] ?? '';
- if ( is_array( $value ) ) {
- $value = implode( ', ', array_map( 'sanitize_text_field', $value ) );
- } else {
- $value = is_scalar( $value ) ? sanitize_text_field( (string) $value ) : '';
- }
-
- return array(
- 'label' => isset( $field['label'] ) && is_scalar( $field['label'] ) ? sanitize_text_field( (string) $field['label'] ) : '',
- 'slug' => isset( $field['slug'] ) && is_scalar( $field['slug'] ) ? sanitize_key( (string) $field['slug'] ) : '',
- 'field_name' => isset( $field['field_name'] ) && is_scalar( $field['field_name'] ) ? sanitize_text_field( (string) $field['field_name'] ) : '',
- 'value' => $value,
- );
- },
- $custom_fields
- );
- $expertize = ! empty( $submission_data['expertize'] ) ? $submission_data['expertize'] : esc_html__( 'N/A', 'masterstudy-lms-learning-management-system' );
- $submission_history = get_user_meta( $user_id, 'submission_history', true );
- if ( empty( $submission_history ) || ! is_array( $submission_history ) ) {
- $submission_history = array();
- }
- $user_data = array(
- 'id' => $user_id,
- 'edit_link' => get_edit_user_link( $user_id ),
- 'display_name' => $user->display_name,
- 'user_email' => $user->user_email,
- 'degree' => $degree,
- 'status' => get_user_meta( $user_id, 'submission_status', true ),
- 'expertize' => $expertize,
- 'submission_date' => gmdate( $date_format, $submission_date ),
- 'submission_time' => $submission_date,
- 'submission_history' => $submission_history,
- 'message' => '',
- 'ai_enabled' => get_user_meta( $user_id, 'stm_lms_ai_enabled', true ),
- 'banned' => get_user_meta( $user_id, 'stm_lms_user_banned', true ),
- 'custom_fields' => $custom_fields,
- );
- $r['users'][] = $user_data;
- }
-
- $r['total'] = $users->get_total();
- }
-
- wp_send_json( $r );
}
public static function update_user_status() {
@@ -1315,143 +1272,20 @@
);
}
- $r = array();
- if ( ! empty( $_GET['user_id'] ) && ! empty( $_GET['status'] ) ) {
- $user_id = intval( $_GET['user_id'] );
- $status = sanitize_text_field( $_GET['status'] );
- $admin_message = sanitize_text_field( $_GET['message'] ?? '' );
-
- $submission_history = get_user_meta( $user_id, 'submission_history', true );
- if ( empty( $submission_history ) || ! is_array( $submission_history ) ) {
- $submission_history = array();
- }
- $user = get_user_by( 'ID', $user_id );
- $submission_date = get_user_meta( $user_id, 'submission_date', true );
- $user_email = $user->user_email;
- $user_login = $user->user_login;
- $submission_data = get_user_meta( $user_id, 'become_instructor', true );
- $custom_fields = ! empty( $submission_data['fields'] ) && is_array( $submission_data['fields'] ) ? $submission_data['fields'] : array();
- update_user_meta( $user_id, 'submission_status', sanitize_text_field( $status ) );
- $date_format = 'M j, Y - H:i';
- $email_data = array(
- 'user_login' => STM_LMS_Helpers::masterstudy_lms_get_user_full_name_or_login( $user_id ),
- 'user_id' => $user_id,
- 'admin_message' => $admin_message,
- );
-
- foreach ( $custom_fields as $field ) {
- if ( empty( $field['value'] ) ) {
- continue;
- }
-
- $label = '';
- if ( ! empty( $field['label'] ) ) {
- $label = sanitize_text_field( $field['label'] );
- } elseif ( ! empty( $field['slug'] ) ) {
- $label = sanitize_key( $field['slug'] );
- } elseif ( ! empty( $field['field_name'] ) ) {
- $label = sanitize_text_field( $field['field_name'] );
- }
- $value = $field['value'] ?? '';
- if ( is_array( $value ) ) {
- $value = implode( ', ', array_map( 'sanitize_text_field', $value ) );
- } else {
- $value = is_scalar( $value ) ? sanitize_text_field( (string) $value ) : '';
- }
- $email_data[ $label ] = $value;
- }
-
- if ( 'approved' === $status ) {
- wp_update_user(
- array(
- 'ID' => $user_id,
- 'role' => 'stm_lms_instructor',
- )
- );
-
- $email_data_approve = array(
- 'instructor_name' => STM_LMS_Helpers::masterstudy_lms_get_user_full_name_or_login( $user_id ),
- 'blog_name' => STM_LMS_Helpers::masterstudy_lms_get_site_name(),
- 'login_url' => STM_LMS_Helpers::masterstudy_lms_get_login_url(),
- 'site_url' => MS_LMS_Email_Template_Helpers::link( STM_LMS_Helpers::masterstudy_lms_get_site_url() ),
- 'date' => current_time( 'mysql' ),
- 'admin_comment' => $admin_message,
- );
-
- $template = wp_kses_post(
- 'Hi {{instructor_name}},<br>
- Congratulations! Your application to become an instructor on {{blog_name}} has been approved.<br>
- You can now log in to your instructor account using the following link:<br>
- Login URL: <a href="{{login_url}}" target="_blank">Login URL</a> <br>
- We are excited to have you on board and look forward to your contributions!'
- );
-
- $message = MS_LMS_Email_Template_Helpers::render( $template, $email_data_approve );
-
- $subject = esc_html__( 'Instructor application approved', 'masterstudy-lms-learning-management-system' );
- if ( ! empty( $admin_message ) ) {
- $message .= '<br>' . sanitize_text_field( $admin_message );
- }
-
- STM_LMS_Helpers::send_email(
- $user_email,
- $subject,
- $message,
- 'stm_lms_email_update_user_status_approved',
- $email_data_approve
- );
- } else {
- $email_data_reject = array(
- 'user_login' => STM_LMS_Helpers::masterstudy_lms_get_user_full_name_or_login( $user_id ),
- 'blog_name' => STM_LMS_Helpers::masterstudy_lms_get_site_name(),
- 'site_url' => MS_LMS_Email_Template_Helpers::link( STM_LMS_Helpers::masterstudy_lms_get_site_url() ),
- 'date' => current_time( 'mysql' ),
- 'admin_comment' => $admin_message,
- );
-
- $template = wp_kses_post(
- 'Hi {{user_login}},<br>
- Thank you for your interest in becoming an instructor on {{blog_name}} <br>
- After careful review, we regret to inform you that your application has not been approved at this time.
- We appreciate the time and effort you put into your submission.
- You're welcome to update your application and reapply in the future.
- If you have any questions or would like feedback, feel free to reach out to our team.<br>
- Best regards.'
- );
-
- $message = MS_LMS_Email_Template_Helpers::render( $template, $email_data_reject );
-
- $subject = esc_html__( 'Update on Your Instructor Application', 'masterstudy-lms-learning-management-system' );
-
- if ( ! empty( $admin_message ) ) {
- $message .= '<br>' . sanitize_text_field( $admin_message );
- }
- STM_LMS_Helpers::send_email(
- $user_email,
- $subject,
- $message,
- 'stm_lms_email_update_user_status_rejected',
- $email_data_reject
- );
- }
-
- $submission_info = array(
- 'request_date' => $submission_date,
- 'request_display_date' => gmdate( $date_format, $submission_date ),
- 'status' => $status,
- 'message' => $admin_message,
- 'answer_date' => time(),
- 'answer_display_date' => gmdate( $date_format, time() ),
- 'viewed' => '',
- );
-
- array_unshift( $submission_history, $submission_info );
- update_user_meta( $user_id, 'submission_history', $submission_history );
+ $user_id = isset( $_GET['user_id'] ) ? absint( $_GET['user_id'] ) : 0;
+ $status = isset( $_GET['status'] ) ? sanitize_text_field( $_GET['status'] ) : '';
- $r = $submission_history;
+ if ( ! $user_id || '' === $status ) {
+ wp_send_json( array() );
}
- wp_send_json( $r );
+ $result = ( new AdminInstructorRepository() )->update_status(
+ $user_id,
+ $status,
+ (string) ( $_GET['message'] ?? '' )
+ );
+
+ wp_send_json( null === $result ? array() : $result['submission_history'] );
}
public static function ban_user(): void {
@@ -1465,14 +1299,14 @@
}
$user_id = absint( $_GET['user_id'] ?? 0 );
- if ( ! $user_id || ! get_userdata( $user_id ) || ! current_user_can( 'manage_options' ) ) {
+ if ( ! $user_id || ! current_user_can( 'manage_options' ) ) {
wp_send_json( 'unsaved' );
}
- $banned = 'true' === ( $_GET['banned'] ?? '' );
- update_user_meta( $user_id, 'stm_lms_user_banned', $banned );
+ $banned = rest_sanitize_boolean( $_GET['banned'] ?? false );
+ $saved = ( new AdminInstructorRepository() )->update_ban( $user_id, $banned );
- wp_send_json( 'saved' );
+ wp_send_json( $saved ? 'saved' : 'unsaved' );
}
public static function toggle_user_ai_access() {
@@ -1485,12 +1319,24 @@
);
}
- if ( ! empty( $_GET['user_id'] ) ) {
- $ai_enabled = ! empty( $_GET['ai_enabled'] ) && 'true' === $_GET['ai_enabled'];
- update_user_meta( intval( $_GET['user_id'] ), 'stm_lms_ai_enabled', $ai_enabled );
+ $user_id = absint( $_GET['user_id'] ?? 0 );
+ if ( ! $user_id ) {
+ wp_send_json( 'unsaved' );
}
- wp_send_json( 'saved' );
+ $repository = new AdminInstructorRepository();
+
+ if ( ! $repository->is_ai_lab_available() ) {
+ wp_send_json_error(
+ array( 'message' => 'Forbidden' ),
+ 403
+ );
+ }
+
+ $ai_enabled = rest_sanitize_boolean( $_GET['ai_enabled'] ?? false );
+ $saved = $repository->update_ai_access( $user_id, $ai_enabled );
+
+ wp_send_json( $saved ? 'saved' : 'unsaved' );
}
public static function toggle_users_ai_access() {
@@ -1503,29 +1349,17 @@
);
}
- $ai_enabled = ! empty( $_GET['ai_enabled'] ) && 'true' === $_GET['ai_enabled'];
+ $repository = new AdminInstructorRepository();
- $args = array(
- 'role__in' => array( 'subscriber', 'stm_lms_instructor' ),
- 'number' => -1,
- 'fields' => 'ids',
- 'orderby' => 'meta_value_num',
- 'order' => 'DESC',
- 'meta_query' => array(
- array(
- 'key' => 'submission_date',
- 'compare' => 'EXISTS',
- ),
- ),
- );
- $query = new WP_User_Query( $args );
- $instructors = $query->get_results();
-
- foreach ( $instructors as $instructor_id ) {
- update_user_meta( $instructor_id, 'stm_lms_ai_enabled', $ai_enabled );
+ if ( ! $repository->is_ai_lab_available() ) {
+ wp_send_json_error(
+ array( 'message' => 'Forbidden' ),
+ 403
+ );
}
- update_option( 'stm_lms_ai_enabled_for_all', $ai_enabled );
+ $ai_enabled = rest_sanitize_boolean( $_GET['ai_enabled'] ?? false );
+ $repository->update_all_ai_access( $ai_enabled );
wp_send_json( 'saved' );
}
@@ -1551,11 +1385,14 @@
}
public static function get_is_ai_enabled_for_all() {
- return get_option( 'stm_lms_ai_enabled_for_all', false );
+ return ( new AdminInstructorRepository() )->is_ai_enabled_for_all();
}
public static function has_ai_access( $user_id ) {
- return current_user_can( 'administrator' ) || get_user_meta( $user_id, 'stm_lms_ai_enabled', true );
+ $repository = new AdminInstructorRepository();
+
+ return $repository->is_ai_lab_available()
+ && ( current_user_can( 'administrator' ) || get_user_meta( $user_id, 'stm_lms_ai_enabled', true ) );
}
public static function restrict_media_to_own( $query ) {
--- a/masterstudy-lms-learning-management-system/_core/lms/classes/models/StmLmsPayout.php
+++ b/masterstudy-lms-learning-management-system/_core/lms/classes/models/StmLmsPayout.php
@@ -237,7 +237,7 @@
->where_raw( ' order_items.`payout_id` IS NULL ' )
->where_in( '_order.`post_type`', array( 'shop_order', 'stm-orders' ) )
->where_raw( " ( DATE(_order.post_date) <= DATE('" . gmdate( 'Y-m-d' ) . "') ) " )
- ->where_in( 'course.`post_type`', array( 'stm-courses', 'product' ) )
+ ->where_in( 'course.`post_type`', array( 'stm-courses', 'stm-course-bundles', 'product' ) )
->where_raw( "( ( meta.`meta_key` = 'status' AND meta.`meta_value` = 'completed') OR ( _order.`post_status` = 'wc-completed' ) )" )
->group_by( ' order_items.id ' )
->find();
--- a/masterstudy-lms-learning-management-system/_core/lms/classes/models/StmStatistics.php
+++ b/masterstudy-lms-learning-management-system/_core/lms/classes/models/StmStatistics.php
@@ -10,24 +10,30 @@
public $object;
public function admin_menu() {
- add_action( 'wpcfto_screen_stm_lms_settings_added', array( $this, 'add_order_list' ), 100, 1 );
+ add_action( 'admin_menu', array( $this, 'add_order_list' ), 100001 );
}
public function add_order_list() {
- $hook = add_submenu_page(
+ if ( function_exists( 'masterstudy_lms_resolve_admin_submenu_items' ) ) {
+ $registered_items = masterstudy_lms_resolve_admin_submenu_items( true );
+
+ if ( isset( $registered_items['stm_lms_statistics'] ) ) {
+ return;
+ }
+ }
+
+ add_submenu_page(
'stm-lms-settings',
__( 'Statistics', 'masterstudy-lms-learning-management-system' ),
__( '⤷ Statistics', 'masterstudy-lms-learning-management-system' ),
'manage_options',
'stm_lms_statistics',
- array( $this, 'render_statistics' )
+ 'masterstudy_lms_render_admin_react_page'
);
-
- add_action( "load-$hook", array( $this, 'stm_lms_statistics_screen_option' ) );
}
public function render_statistics() {
- stm_lms_render( STM_LMS_PATH . '/lms/views/statistics/statistics', array(), true );
+ STM_LMS_Templates::show_lms_template( 'components/admin-react-app/main' );
}
public function stm_lms_statistics_screen_option() {
--- a/masterstudy-lms-learning-management-system/_core/lms/classes/order.php
+++ b/masterstudy-lms-learning-management-system/_core/lms/classes/order.php
@@ -128,7 +128,16 @@
$cart_items = array();
$total = 0;
- if ( is_ms_lms_addon_enabled( 'subscriptions' ) ) {
+ $can_load_subscription_plans = STM_LMS_Helpers::is_pro_plus()
+ && is_ms_lms_addon_enabled( 'subscriptions' )
+ && class_exists( 'MasterStudyLmsProAddonsPlusSubscriptionsRepositoriesSubscriptionPlanRepository' )
+ && function_exists( 'stm_lms_subscription_plans_table_name' );
+ $can_load_subscriptions = STM_LMS_Helpers::is_pro_plus()
+ && is_ms_lms_addon_enabled( 'subscriptions' )
+ && class_exists( 'MasterStudyLmsProAddonsPlusSubscriptionsRepositoriesSubscriptionRepository' )
+ && function_exists( 'stm_lms_subscriptions_table_name' );
+
+ if ( $can_load_subscription_plans ) {
if ( isset( $order_meta['subscription_id'] ) && intval( $order_meta['subscription_id'] ) ) {
$order_meta['subscription_order_count'] = ( new SubscriptionPlanRepository() )->get_subscription_orders_with_queue( $order_id, intval( $order_meta['subscription_id'] ) );
}
@@ -161,7 +170,7 @@
$cart_item['image'] = get_the_post_thumbnail( $item_id, 'img-300-225' );
$cart_item['image_url'] = get_the_post_thumbnail_url( $item_id, 'img-300-225' );
$cart_item['image_full'] = get_the_post_thumbnail( $item_id, 'full' );
- } elseif ( is_ms_lms_addon_enabled( 'subscriptions' ) && class_exists( 'MasterStudyLmsProAddonsPlusSubscriptionsRepositoriesSubscriptionPlanRepository' ) ) {
+ } elseif ( $can_load_subscription_plans ) {
$subscription_plan = ( new SubscriptionPlanRepository() )->get( $item_id );
$cart_item['title'] = $subscription_plan['name'] ?? esc_html__( 'N/A', 'masterstudy-lms-learning-management-system' );
$cart_item['subscription_type'] = SubscriptionPlanRepository::get_plan_type( $subscription_plan['type'] ?? '' );
@@ -224,9 +233,9 @@
if ( $is_result_empty || $should_check_for_coupon ) {
$subs_id = get_post_meta( $order_id, 'subscription_id', true );
- if ( null !== $subs_id && '' !== $subs_id && is_ms_lms_addon_enabled( 'subscriptions' ) ) {
+ if ( null !== $subs_id && '' !== $subs_id && $can_load_subscriptions ) {
$get_subscription = ( new SubscriptionRepository() )->get( intval( $subs_id ) );
- $first_order_id = $get_subscription['first_order_id'];
+ $first_order_id = $get_subscription['first_order_id'] ?? 0;
if ( $is_result_empty ) {
$result = get_post_meta( $first_order_id, 'personal_data', true ) ?? array();
--- a/masterstudy-lms-learning-management-system/_core/lms/classes/reviews.php
+++ b/masterstudy-lms-learning-management-system/_core/lms/classes/reviews.php
@@ -150,7 +150,7 @@
continue;
}
$user_name = ( ! empty( $user_data->data->display_name ) ) ? $user_data->data->display_name : $user_data->data->user_nicename;
- $avatar = get_avatar_url( $user );
+ $avatar = STM_LMS_User::get_avatar_url( $user );
if ( ! empty( $user_class['avatar_url'] ) ) {
$avatar = $user_class['avatar_url'];
--- a/masterstudy-lms-learning-management-system/_core/lms/classes/students.php
+++ b/masterstudy-lms-learning-management-system/_core/lms/classes/students.php
@@ -50,8 +50,10 @@
if ( STM_LMS_Helpers::is_pro_plus() && ! empty( $student_id ) ) {
STM_LMS_Templates::show_lms_template( 'account/instructor/enrolled-student' );
- } else {
+ } elseif ( ! empty( $student_id ) ) {
STM_LMS_Templates::show_lms_template( 'account/instructor/parts/students-list' );
+ } else {
+ STM_LMS_Templates::show_lms_template( 'components/admin-react-app/main' );
}
}
}
--- a/masterstudy-lms-learning-management-system/_core/lms/classes/subscriptions.php
+++ b/masterstudy-lms-learning-management-system/_core/lms/classes/subscriptions.php
@@ -200,7 +200,7 @@
$user_course = compact( 'user_id', 'course_id', 'current_lesson_id', 'status', 'progress_percent', 'subscription_id' );
$user_course['start_time'] = time();
- if ( is_ms_lms_addon_enabled( 'grades' ) && masterstudy_lms_is_course_gradable( $course_id ) ) {
+ if ( is_ms_lms_addon_enabled( 'grades' ) && function_exists( 'masterstudy_lms_is_course_gradable' ) && masterstudy_lms_is_course_gradable( $course_id ) ) {
$user_course['is_gradable'] = 1;
}
--- a/masterstudy-lms-learning-management-system/_core/lms/classes/user.php
+++ b/masterstudy-lms-learning-management-system/_core/lms/classes/user.php
@@ -1,7 +1,9 @@
<?php
+use MasterStudyLmsEnumsPricingMode;
use MasterStudyLmsPluginAddons;
use MasterStudyLmsPluginPostType;
use MasterStudyLmsProAddonsPlusSubscriptionsServicesCourseService;
+use MasterStudyLmsRepositoriesPricingRepository;
STM_LMS_User::init();
@@ -753,6 +755,26 @@
}
}
+ public static function get_avatar_url( $user_id, $args = array() ) {
+ $user_id = absint( $user_id );
+
+ if ( empty( $user_id ) ) {
+ return '';
+ }
+
+ $charset = get_bloginfo( 'charset' );
+ if ( empty( $charset ) ) {
+ $charset = 'UTF-8';
+ }
+ $avatar_url = get_user_meta( $user_id, 'stm_lms_user_avatar', true );
+
+ if ( empty( $avatar_url ) ) {
+ $avatar_url = get_avatar_url( $user_id, $args );
+ }
+
+ return esc_url_raw( html_entity_decode( (string) $avatar_url, ENT_QUOTES, $charset ) );
+ }
+
public static function get_current_user( $id = '', $get_role = false, $get_meta = false, $no_avatar = false, $avatar_size = 215, $for_student = false ) {
$user = array(
'id' => 0,
@@ -768,17 +790,17 @@
/*Get Meta*/
$stm_lms_user_avatar = get_user_meta( $current_user->ID, 'stm_lms_user_avatar', true );
if ( ! empty( $stm_lms_user_avatar ) ) {
- $avatar = "<img src='{$stm_lms_user_avatar}' class='avatar photo' width='{$avatar_size}' />";
- $avatar_url = $stm_lms_user_avatar;
+ $avatar = "<img src='{$stm_lms_user_avatar}' class='avatar photo' width='{$avatar_size}' />";
} else {
$avatar = get_avatar( $current_user->ID, $avatar_size );
-
- if ( preg_match( '/src=["']([^"']+)["']/', $avatar, $match ) ) {
- $avatar_url = $match[1]; // Extract the URL directly
- } else {
- $avatar_url = $stm_lms_user_avatar; // Default to empty string if no match found
- }
}
+
+ $avatar_url = self::get_avatar_url(
+ $current_user->ID,
+ array(
+ 'size' => absint( $avatar_size ),
+ )
+ );