at path:
ROOT
/
wp-content
/
plugins
/
tutor
/
classes
/
Instructors_List.php
run:
R
W
Run
Addons.php
11.79 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Admin.php
26.61 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Ajax.php
17.03 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Announcements.php
2.79 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Assets.php
24.27 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Backend_Page_Trait.php
4.39 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
BaseController.php
1.47 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Config.php
3.16 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Container.php
4.85 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Course.php
94.45 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Course_Embed.php
2.55 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Course_Filter.php
8.68 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Course_List.php
14.68 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Course_Settings_Tabs.php
1.16 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Course_Widget.php
8.2 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Custom_Validation.php
513 By
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Dashboard.php
1.23 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Earnings.php
10.43 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
FormHandler.php
7.16 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Frontend.php
2.94 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Gutenberg.php
4.62 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Icon.php
11.49 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Input.php
9.08 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Instructor.php
13.2 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Instructors_List.php
13.09 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Lesson.php
19.92 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Options_V2.php
67.77 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Permalink.php
2 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Post_types.php
18.3 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Private_Course_Access.php
2.52 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Q_And_A.php
10.78 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Question_Answers_List.php
2.55 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Quiz.php
35.16 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
QuizBuilder.php
12.53 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Quiz_Attempts_List.php
7.28 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
RestAPI.php
7.97 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Reviews.php
3.72 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Rewrite_Rules.php
5.18 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Shortcode.php
14.18 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Singleton.php
1.08 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Student.php
10.44 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Students_List.php
3.03 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Taxonomies.php
8.2 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Template.php
14.52 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Theme_Compatibility.php
683 By
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Tools.php
3.33 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Tools_V2.php
18.56 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Tutor.php
36.45 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
TutorEDD.php
4.69 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Tutor_Base.php
1.48 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Tutor_Setup.php
33.34 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Upgrader.php
12.49 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
User.php
14.9 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Utils.php
270.91 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Video_Stream.php
3.94 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
WhatsNew.php
4.83 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Withdraw.php
9.49 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
Withdraw_Requests_List.php
6.24 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
WooCommerce.php
24.76 KB
2026-04-14 05:34:26
R
W
Run
Delete
Rename
error_log
up
📄
Instructors_List.php
Save
<?php /** * Manage Instructor List * * @package Tutor * @author Themeum <support@themeum.com> * @link https://themeum.com * @since 1.0.0 */ namespace TUTOR; if ( ! defined( 'ABSPATH' ) ) { exit; } use TUTOR\Students_List; use TUTOR\Backend_Page_Trait; use Tutor\Cache\TutorCache; use Tutor\Helpers\QueryHelper; /** * Instructors_List class * * @since 1.0.0 */ class Instructors_List { const INSTRUCTOR_LIST_PAGE = 'tutor-instructors'; const INSTRUCTOR_LIST_CACHE_KEY = 'tutor-instructors-list'; const INSTRUCTOR_COUNT_CACHE_KEY = 'tutor-instructors-count'; /** * Trait for utilities * * @var $page_title */ use Backend_Page_Trait; /** * Bulk Action * * @var $bulk_action */ public $bulk_action = true; /** * Constructor * * @since 1.0.0 * @return void */ public function __construct() { /** * Handle bulk action * * @since 2.0.0 */ add_action( 'wp_ajax_tutor_instructor_bulk_action', array( $this, 'instructor_bulk_action' ) ); } /** * Page title fallback * * @since 3.5.0 * * @param string $name Property name. * * @return string */ public function __get( $name ) { if ( 'page_title' === $name ) { return esc_html__( 'Instructor', 'tutor' ); } } /** * Available tabs that will visible on the right side of page navbar * * @since 2.0.0 * * @param string $search instructor search | optional. * @param string $course_id course id that belong to instructor | optional. * @param string $date user registered date | optional. * * @return array */ public function tabs_key_value( $search = '', $course_id = '', $date = '' ): array { $url = apply_filters( 'tutor_data_tab_base_url', get_pagenum_link() ); $approve = self::count_total_instructors( array( 'approved' ), $search, $course_id, $date, 'approved' ); $pending = self::count_total_instructors( array( 'pending' ), $search, $course_id, $date, 'pending' ); $blocked = self::count_total_instructors( array( 'blocked' ), $search, $course_id, $date, 'blocked' ); $tabs = array( array( 'key' => '', 'title' => __( 'All', 'tutor' ), 'value' => $approve + $pending + $blocked, 'url' => $url . '&data=all', ), array( 'key' => 'approved', 'title' => __( 'Approve', 'tutor' ), 'value' => $approve, 'url' => $url . '&data=approved', ), array( 'key' => 'pending', 'title' => __( 'Pending', 'tutor' ), 'value' => $pending, 'url' => $url . '&data=pending', ), array( 'key' => 'blocked', 'title' => __( 'Block', 'tutor' ), 'value' => $blocked, 'url' => $url . '&data=blocked', ), ); return $tabs; } /** * Prepare bulk actions that will show on dropdown options * * @since 2.0.0 * @return array */ public function prpare_bulk_actions(): array { $actions = array( $this->bulk_action_default(), $this->bulk_action_approved(), $this->bulk_action_pending(), $this->bulk_action_blocked(), ); return $actions; } /** * Handle bulk action for instructor delete * * @since 2.0.0 * @return string JSON response. */ public function instructor_bulk_action() { tutor_utils()->checking_nonce(); // Check if user is privileged. if ( ! current_user_can( 'administrator' ) ) { wp_send_json_error( tutor_utils()->error_message() ); } $action = Input::post( 'bulk-action', '' ); $bulk_ids = Input::post( 'bulk-ids', '' ); Input::has( 'bulkIds' ) ? $bulk_ids = Input::post( 'bulkIds' ) : 0; if ( '' === $action || '' === $bulk_ids ) { return wp_send_json_error(); } if ( 'delete' === $action ) { // Delete user from student_list class. do_action( 'tutor_before_instructor_delete', $bulk_ids ); $response = Students_List::delete_students( $bulk_ids ); do_action( 'tutor_after_instructor_delete', $bulk_ids ); } else { do_action( 'tutor_before_instructor_update', $bulk_ids ); $response = self::update_instructors( $action, $bulk_ids ); do_action( 'tutor_after_instructor_delete', $bulk_ids ); } $message = 'Instructor status updated'; return true === $response ? wp_send_json_success( array( 'status' => $message ) ) : wp_send_json_error(); } /** * Execute bulk action for enrollment list ex: complete | cancel * * @since 2.0.0 * * @param string $status hold status for updating. * @param string $user_ids comma seperated user ids. * * @return bool */ public static function update_instructors( $status, $user_ids ): bool { global $wpdb; $status = sanitize_text_field( $status ); $instructor_table = $wpdb->usermeta; $ids = array_map( 'intval', explode( ',', $user_ids ) ); $in_clause = QueryHelper::prepare_in_clause( $ids ); //phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared $update = $wpdb->query( $wpdb->prepare( "UPDATE {$instructor_table} SET meta_value = %s WHERE user_id IN ($in_clause) AND meta_key = %s", $status, '_tutor_instructor_status' ) ); //phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared // Remove role. if ( 'pending' === $status || 'blocked' === $status ) { $arr = explode( ',', $user_ids ); foreach ( $arr as $instructor_id ) { $instructor_id = (int) sanitize_text_field( $instructor_id ); if ( 'pending' === $status ) { self::remove_instructor_role( $instructor_id, $status ); } else { self::instructor_blockage( $instructor_id ); } } } if ( 'reject' === $status ) { $arr = explode( ',', $user_ids ); foreach ( $arr as $instructor_id ) { $instructor_id = (int) sanitize_text_field( $instructor_id ); self::instructor_rejection( $instructor_id ); } } if ( 'approved' === $status ) { $arr = explode( ',', $user_ids ); foreach ( $arr as $instructor_id ) { $instructor_id = (int) sanitize_text_field( $instructor_id ); self::add_instructor_role( $instructor_id, $status ); } } return false === $update ? false : true; } /** * Get total course. * * @since 1.0.0 * * @param object $item item. * @return void */ public function column_total_course( $item ) { global $wpdb; $course_post_type = tutor()->course_post_type; $total_course = (int) $wpdb->get_var( $wpdb->prepare( "SELECT count(ID) from {$wpdb->posts} WHERE post_author=%d AND post_type=%s ", $item->ID, $course_post_type ) ); echo esc_html( $total_course ); } /** * Initialize instructor_role to a user * * @since 1.0.0 * * @param integer $instructor_id | user id that need to add role. * @param string $status | status that will added with role (approved). * * @return void */ protected static function add_instructor_role( int $instructor_id, string $status ) { $instructor_id = sanitize_text_field( $instructor_id ); $status = sanitize_text_field( $status ); do_action( 'tutor_before_approved_instructor', $instructor_id ); update_user_meta( $instructor_id, '_tutor_instructor_status', $status ); update_user_meta( $instructor_id, '_tutor_instructor_approved', tutor_time() ); $instructor = new \WP_User( $instructor_id ); $instructor->add_role( tutor()->instructor_role ); // TODO: send E-Mail to this user about instructor approval, should via hook. do_action( 'tutor_after_approved_instructor', $instructor_id ); } /** * Initialize instructor_role to a user * * @since 1.0.0 * * @param int $instructor_id | user id that need to add role. * @param string $status | status that will added with role (approved). * * @return void */ protected static function remove_instructor_role( int $instructor_id, string $status ) { $instructor_id = sanitize_text_field( $instructor_id ); $status = sanitize_text_field( $status ); update_user_meta( $instructor_id, '_tutor_instructor_status', $status ); $instructor = new \WP_User( $instructor_id ); $instructor->remove_role( tutor()->instructor_role ); } /** * Instructor blocking function * * @since 2.5.0 * * @param int $instructor_id | user id that need to add role. * @return void */ protected static function instructor_blockage( int $instructor_id ) { $instructor_id = sanitize_text_field( $instructor_id ); do_action( 'tutor_before_blocked_instructor', $instructor_id ); self::remove_instructor_role( $instructor_id, 'blocked' ); do_action( 'tutor_after_blocked_instructor', $instructor_id ); } /** * Instructor rejection function * * @since 2.5.0 * * @param int $instructor_id | user id that need to add role. * @return void */ protected static function instructor_rejection( int $instructor_id ) { $instructor_id = sanitize_text_field( $instructor_id ); do_action( 'tutor_before_rejected_instructor', $instructor_id ); /** * Removed tutor_instructor role and set `try_again` status * for apply again as instructor with show message to applier in frontend. */ self::remove_instructor_role( $instructor_id, 'try_again' ); delete_user_meta( $instructor_id, '_is_tutor_instructor' ); do_action( 'tutor_after_rejected_instructor', $instructor_id ); } /** * Get instructors list * * @since 2.1.7 * * @param array $status instructor status: approved, pending, block. * @param int $offset offset for pagination. * @param int $per_page per page limit. * @param string $search search keyword. * @param string $course_id course id. * @param string $date instructor registration date. * @param string $order sorting order. * * @return wpdb::results */ public static function get_instructors( array $status, $offset, $per_page, $search = '', $course_id = '', $date = '', $order = 'DESC' ) { global $wpdb; $wild = '%'; $search_clause = $wild . $wpdb->esc_like( $search ) . $wild; $course_clause = ''; if ( '' !== $course_id ) { $course_id = (int) $course_id; $course_clause = "AND umeta.meta_value = {$course_id}"; } $order_clause = ''; if ( '' !== $order ) { $is_valid_sql = sanitize_sql_orderby( $order ); if ( $is_valid_sql ) { $order_clause = "ORDER BY user.ID {$order}"; } } $date_clause = '' !== $date ? $wpdb->prepare( 'AND DATE(user.user_registered) = %s', $date ) : ''; $in_clause = QueryHelper::prepare_in_clause( $status ); $query = "SELECT DISTINCT user.*, ins_status.meta_value AS status, ( SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_author = user.ID AND post_type = 'courses' ) total_courses FROM {$wpdb->users} AS user INNER JOIN {$wpdb->usermeta} AS ins_status ON ( user.ID = ins_status.user_id ) AND ins_status.meta_key = '_tutor_instructor_status' LEFT JOIN {$wpdb->usermeta} AS umeta ON umeta.user_id = user.ID AND umeta.meta_key = '_tutor_instructor_course_id' WHERE ins_status.meta_value IN ($in_clause) AND (user.user_email LIKE %s OR user.display_name LIKE %s) {$course_clause} {$date_clause} {$order_clause} LIMIT %d, %d; "; $result = TutorCache::get( self::INSTRUCTOR_LIST_CACHE_KEY ); if ( false === $result ) { TutorCache::set( self::INSTRUCTOR_LIST_CACHE_KEY, //phpcs:disable $result = $wpdb->get_results( $wpdb->prepare( $query, $search_clause, $search_clause, $offset, $per_page ) ) //phpcs:enable ); } return $result; } /** * Count total instructors * * @since 2.1.7 * * @param array $status instructor status: approved, pending, block. * @param string $search search keyword. * @param string $course_id course id. * @param string $date instructor registration date. * @param string $unique_cache_key unique key will be append with * self::INSTRUCTOR_COUNT_CACHE_KEY so that multiple count value could be * stored as unique data. * * @return int count value of instructors */ public static function count_total_instructors( array $status, $search = '', $course_id = '', $date = '', $unique_cache_key = '' ) { global $wpdb; $wild = '%'; $search_clause = $wild . $wpdb->esc_like( $search ) . $wild; $course_clause = ''; if ( '' !== $course_id ) { $course_id = (int) $course_id; $course_clause = "AND umeta.meta_value = {$course_id}"; } $date_clause = '' !== $date ? $wpdb->prepare( 'AND DATE(user.user_registered) = %s', $date ) : ''; $in_clause = QueryHelper::prepare_in_clause( $status ); $query = "SELECT COUNT(DISTINCT user.ID) FROM {$wpdb->users} AS user INNER JOIN {$wpdb->usermeta} AS ins_status ON ( user.ID = ins_status.user_id ) AND ins_status.meta_key = '_tutor_instructor_status' LEFT JOIN {$wpdb->usermeta} AS umeta ON umeta.user_id = user.ID AND umeta.meta_key = '_tutor_instructor_course_id' WHERE ins_status.meta_value IN ($in_clause) AND (user.user_email LIKE %s OR user.display_name LIKE %s) {$course_clause} {$date_clause} "; $result = TutorCache::get( self::INSTRUCTOR_COUNT_CACHE_KEY . $unique_cache_key ); if ( false === $result ) { TutorCache::set( self::INSTRUCTOR_COUNT_CACHE_KEY, //phpcs:disable $result = $wpdb->get_var( $wpdb->prepare( $query, $search_clause, $search_clause ) ) //phpcs:enable ); } return $result; } }