PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 3.9.13
Tutor LMS – eLearning and online course solution v3.9.13
3.9.14 3.9.13 3.9.12 3.9.11 trunk 1.0.0 1.0.0-alpha 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.2.0 1.2.1 1.2.11 1.2.12 1.2.13 1.2.20 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9 1.8.0 1.8.1 1.8.10 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9.0 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.14 1.9.15 1.9.16 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1 2.0.10 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1.0 2.1.1 2.1.10 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.3.0 2.4.0 2.5.0 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 3.0.0 3.0.1 3.0.2 3.1.0 3.2.0 3.2.1 3.2.2 3.2.3 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.7.0 3.7.1 3.7.2 3.7.3 3.7.4 3.8.0 3.8.1 3.8.2 3.8.3 3.9.0 3.9.1 3.9.10 3.9.2 3.9.3 3.9.4 3.9.5 3.9.6 3.9.7 3.9.8 3.9.9
tutor / classes / Instructors_List.php
tutor / classes Last commit date
Addons.php 11 months ago Admin.php 2 months ago Ajax.php 9 months ago Announcements.php 1 year ago Assets.php 2 months ago Backend_Page_Trait.php 1 year ago BaseController.php 1 year ago Config.php 11 months ago Container.php 11 months ago Course.php 2 months ago Course_Embed.php 3 years ago Course_Filter.php 1 year ago Course_List.php 5 months ago Course_Settings_Tabs.php 1 year ago Course_Widget.php 1 year ago Custom_Validation.php 3 years ago Dashboard.php 1 year ago Earnings.php 9 months ago FormHandler.php 2 years ago Frontend.php 1 year ago Gutenberg.php 1 year ago Icon.php 8 months ago Input.php 1 year ago Instructor.php 2 months ago Instructors_List.php 2 months ago Lesson.php 2 weeks ago Options_V2.php 7 months ago Permalink.php 2 years ago Post_types.php 1 year ago Private_Course_Access.php 1 year ago Q_And_A.php 10 months ago Question_Answers_List.php 11 months ago Quiz.php 2 weeks ago QuizBuilder.php 2 weeks ago Quiz_Attempts_List.php 9 months ago RestAPI.php 2 years ago Reviews.php 9 months ago Rewrite_Rules.php 2 years ago Shortcode.php 9 months ago Singleton.php 1 year ago Student.php 2 months ago Students_List.php 1 year ago Taxonomies.php 1 year ago Template.php 9 months ago Theme_Compatibility.php 3 years ago Tools.php 1 year ago Tools_V2.php 3 weeks ago Tutor.php 2 months ago TutorEDD.php 1 year ago Tutor_Base.php 2 years ago Tutor_Setup.php 8 months ago Upgrader.php 9 months ago User.php 4 months ago Utils.php 3 weeks ago Video_Stream.php 3 years ago WhatsNew.php 9 months ago Withdraw.php 1 year ago Withdraw_Requests_List.php 11 months ago WooCommerce.php 7 months ago
Instructors_List.php
489 lines
1 <?php
2 /**
3 * Manage Instructor List
4 *
5 * @package Tutor
6 * @author Themeum <support@themeum.com>
7 * @link https://themeum.com
8 * @since 1.0.0
9 */
10
11 namespace TUTOR;
12
13 if ( ! defined( 'ABSPATH' ) ) {
14 exit;
15 }
16
17 use TUTOR\Students_List;
18 use TUTOR\Backend_Page_Trait;
19 use Tutor\Cache\TutorCache;
20 use Tutor\Helpers\QueryHelper;
21
22 /**
23 * Instructors_List class
24 *
25 * @since 1.0.0
26 */
27 class Instructors_List {
28
29 const INSTRUCTOR_LIST_PAGE = 'tutor-instructors';
30 const INSTRUCTOR_LIST_CACHE_KEY = 'tutor-instructors-list';
31 const INSTRUCTOR_COUNT_CACHE_KEY = 'tutor-instructors-count';
32
33 /**
34 * Trait for utilities
35 *
36 * @var $page_title
37 */
38
39 use Backend_Page_Trait;
40
41 /**
42 * Bulk Action
43 *
44 * @var $bulk_action
45 */
46 public $bulk_action = true;
47
48 /**
49 * Constructor
50 *
51 * @since 1.0.0
52 * @return void
53 */
54 public function __construct() {
55 /**
56 * Handle bulk action
57 *
58 * @since 2.0.0
59 */
60 add_action( 'wp_ajax_tutor_instructor_bulk_action', array( $this, 'instructor_bulk_action' ) );
61 }
62
63 /**
64 * Page title fallback
65 *
66 * @since 3.5.0
67 *
68 * @param string $name Property name.
69 *
70 * @return string
71 */
72 public function __get( $name ) {
73 if ( 'page_title' === $name ) {
74 return esc_html__( 'Instructor', 'tutor' );
75 }
76 }
77
78 /**
79 * Available tabs that will visible on the right side of page navbar
80 *
81 * @since 2.0.0
82 *
83 * @param string $search instructor search | optional.
84 * @param string $course_id course id that belong to instructor | optional.
85 * @param string $date user registered date | optional.
86 *
87 * @return array
88 */
89 public function tabs_key_value( $search = '', $course_id = '', $date = '' ): array {
90 $url = apply_filters( 'tutor_data_tab_base_url', get_pagenum_link() );
91 $approve = self::count_total_instructors( array( 'approved' ), $search, $course_id, $date, 'approved' );
92 $pending = self::count_total_instructors( array( 'pending' ), $search, $course_id, $date, 'pending' );
93 $blocked = self::count_total_instructors( array( 'blocked' ), $search, $course_id, $date, 'blocked' );
94
95 $tabs = array(
96 array(
97 'key' => '',
98 'title' => __( 'All', 'tutor' ),
99 'value' => $approve + $pending + $blocked,
100 'url' => $url . '&data=all',
101 ),
102 array(
103 'key' => 'approved',
104 'title' => __( 'Approve', 'tutor' ),
105 'value' => $approve,
106 'url' => $url . '&data=approved',
107 ),
108 array(
109 'key' => 'pending',
110 'title' => __( 'Pending', 'tutor' ),
111 'value' => $pending,
112 'url' => $url . '&data=pending',
113 ),
114 array(
115 'key' => 'blocked',
116 'title' => __( 'Block', 'tutor' ),
117 'value' => $blocked,
118 'url' => $url . '&data=blocked',
119 ),
120 );
121 return $tabs;
122 }
123
124 /**
125 * Prepare bulk actions that will show on dropdown options
126 *
127 * @since 2.0.0
128 * @return array
129 */
130 public function prpare_bulk_actions(): array {
131 $actions = array(
132 $this->bulk_action_default(),
133 $this->bulk_action_approved(),
134 $this->bulk_action_pending(),
135 $this->bulk_action_blocked(),
136 );
137 return $actions;
138 }
139
140 /**
141 * Handle bulk action for instructor delete
142 *
143 * @since 2.0.0
144 * @return string JSON response.
145 */
146 public function instructor_bulk_action() {
147 tutor_utils()->checking_nonce();
148
149 // Check if user is privileged.
150 if ( ! current_user_can( 'administrator' ) ) {
151 wp_send_json_error( tutor_utils()->error_message() );
152 }
153
154 $action = Input::post( 'bulk-action', '' );
155 $bulk_ids = Input::post( 'bulk-ids', '' );
156
157 Input::has( 'bulkIds' ) ? $bulk_ids = Input::post( 'bulkIds' ) : 0;
158
159 if ( '' === $action || '' === $bulk_ids ) {
160 return wp_send_json_error();
161 }
162 if ( 'delete' === $action ) {
163 // Delete user from student_list class.
164 do_action( 'tutor_before_instructor_delete', $bulk_ids );
165 $response = Students_List::delete_students( $bulk_ids );
166 do_action( 'tutor_after_instructor_delete', $bulk_ids );
167 } else {
168 do_action( 'tutor_before_instructor_update', $bulk_ids );
169 $response = self::update_instructors( $action, $bulk_ids );
170 do_action( 'tutor_after_instructor_delete', $bulk_ids );
171 }
172
173 $message = 'Instructor status updated';
174
175 return true === $response ? wp_send_json_success( array( 'status' => $message ) ) : wp_send_json_error();
176 }
177
178 /**
179 * Execute bulk action for enrollment list ex: complete | cancel
180 *
181 * @since 2.0.0
182 *
183 * @param string $status hold status for updating.
184 * @param string $user_ids comma seperated user ids.
185 *
186 * @return bool
187 */
188 public static function update_instructors( $status, $user_ids ): bool {
189 global $wpdb;
190 $status = sanitize_text_field( $status );
191 $instructor_table = $wpdb->usermeta;
192
193 $ids = array_map( 'intval', explode( ',', $user_ids ) );
194 $in_clause = QueryHelper::prepare_in_clause( $ids );
195
196 //phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
197 $update = $wpdb->query(
198 $wpdb->prepare(
199 "UPDATE {$instructor_table} SET meta_value = %s
200 WHERE user_id IN ($in_clause)
201 AND meta_key = %s",
202 $status,
203 '_tutor_instructor_status'
204 )
205 );
206 //phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
207
208 // Remove role.
209 if ( 'pending' === $status || 'blocked' === $status ) {
210 $arr = explode( ',', $user_ids );
211 foreach ( $arr as $instructor_id ) {
212 $instructor_id = (int) sanitize_text_field( $instructor_id );
213 if ( 'pending' === $status ) {
214 self::remove_instructor_role( $instructor_id, $status );
215 } else {
216 self::instructor_blockage( $instructor_id );
217 }
218 }
219 }
220 if ( 'reject' === $status ) {
221 $arr = explode( ',', $user_ids );
222 foreach ( $arr as $instructor_id ) {
223 $instructor_id = (int) sanitize_text_field( $instructor_id );
224 self::instructor_rejection( $instructor_id );
225 }
226 }
227
228 if ( 'approved' === $status ) {
229 $arr = explode( ',', $user_ids );
230 foreach ( $arr as $instructor_id ) {
231 $instructor_id = (int) sanitize_text_field( $instructor_id );
232 self::add_instructor_role( $instructor_id, $status );
233 }
234 }
235 return false === $update ? false : true;
236 }
237
238 /**
239 * Get total course.
240 *
241 * @since 1.0.0
242 *
243 * @param object $item item.
244 * @return void
245 */
246 public function column_total_course( $item ) {
247 global $wpdb;
248 $course_post_type = tutor()->course_post_type;
249
250 $total_course = (int) $wpdb->get_var(
251 $wpdb->prepare(
252 "SELECT count(ID) from {$wpdb->posts}
253 WHERE post_author=%d AND post_type=%s ",
254 $item->ID,
255 $course_post_type
256 )
257 );
258
259 echo esc_html( $total_course );
260 }
261
262 /**
263 * Initialize instructor_role to a user
264 *
265 * @since 1.0.0
266 *
267 * @param integer $instructor_id | user id that need to add role.
268 * @param string $status | status that will added with role (approved).
269 *
270 * @return void
271 */
272 protected static function add_instructor_role( int $instructor_id, string $status ) {
273 $instructor_id = sanitize_text_field( $instructor_id );
274 $status = sanitize_text_field( $status );
275
276 do_action( 'tutor_before_approved_instructor', $instructor_id );
277
278 update_user_meta( $instructor_id, '_tutor_instructor_status', $status );
279 update_user_meta( $instructor_id, '_tutor_instructor_approved', tutor_time() );
280
281 $instructor = new \WP_User( $instructor_id );
282 $instructor->add_role( tutor()->instructor_role );
283
284 // TODO: send E-Mail to this user about instructor approval, should via hook.
285 do_action( 'tutor_after_approved_instructor', $instructor_id );
286 }
287
288 /**
289 * Initialize instructor_role to a user
290 *
291 * @since 1.0.0
292 *
293 * @param int $instructor_id | user id that need to add role.
294 * @param string $status | status that will added with role (approved).
295 *
296 * @return void
297 */
298 protected static function remove_instructor_role( int $instructor_id, string $status ) {
299 $instructor_id = sanitize_text_field( $instructor_id );
300 $status = sanitize_text_field( $status );
301 update_user_meta( $instructor_id, '_tutor_instructor_status', $status );
302 $instructor = new \WP_User( $instructor_id );
303 $instructor->remove_role( tutor()->instructor_role );
304 }
305 /**
306 * Instructor blocking function
307 *
308 * @since 2.5.0
309 *
310 * @param int $instructor_id | user id that need to add role.
311 * @return void
312 */
313 protected static function instructor_blockage( int $instructor_id ) {
314 $instructor_id = sanitize_text_field( $instructor_id );
315 do_action( 'tutor_before_blocked_instructor', $instructor_id );
316 self::remove_instructor_role( $instructor_id, 'blocked' );
317 do_action( 'tutor_after_blocked_instructor', $instructor_id );
318 }
319 /**
320 * Instructor rejection function
321 *
322 * @since 2.5.0
323 *
324 * @param int $instructor_id | user id that need to add role.
325 * @return void
326 */
327 protected static function instructor_rejection( int $instructor_id ) {
328 $instructor_id = sanitize_text_field( $instructor_id );
329 do_action( 'tutor_before_rejected_instructor', $instructor_id );
330
331 /**
332 * Removed tutor_instructor role and set `try_again` status
333 * for apply again as instructor with show message to applier in frontend.
334 */
335 self::remove_instructor_role( $instructor_id, 'try_again' );
336 delete_user_meta( $instructor_id, '_is_tutor_instructor' );
337
338 do_action( 'tutor_after_rejected_instructor', $instructor_id );
339 }
340
341 /**
342 * Get instructors list
343 *
344 * @since 2.1.7
345 *
346 * @param array $status instructor status: approved, pending, block.
347 * @param int $offset offset for pagination.
348 * @param int $per_page per page limit.
349 * @param string $search search keyword.
350 * @param string $course_id course id.
351 * @param string $date instructor registration date.
352 * @param string $order sorting order.
353 *
354 * @return wpdb::results
355 */
356 public static function get_instructors( array $status, $offset, $per_page, $search = '', $course_id = '', $date = '', $order = 'DESC' ) {
357 global $wpdb;
358
359 $wild = '%';
360
361 $search_clause = $wild . $wpdb->esc_like( $search ) . $wild;
362 $course_clause = '';
363 if ( '' !== $course_id ) {
364 $course_id = (int) $course_id;
365 $course_clause = "AND umeta.meta_value = {$course_id}";
366 }
367
368 $order_clause = '';
369 if ( '' !== $order ) {
370 $is_valid_sql = sanitize_sql_orderby( $order );
371 if ( $is_valid_sql ) {
372 $order_clause = "ORDER BY user.ID {$order}";
373 }
374 }
375
376 $date_clause = '' !== $date ? $wpdb->prepare( 'AND DATE(user.user_registered) = %s', $date ) : '';
377 $in_clause = QueryHelper::prepare_in_clause( $status );
378
379 $query = "SELECT
380 DISTINCT user.*,
381 ins_status.meta_value AS status,
382 (
383 SELECT
384 COUNT(*)
385 FROM {$wpdb->posts}
386 WHERE post_author = user.ID
387 AND post_type = 'courses'
388 ) total_courses
389 FROM {$wpdb->users} AS user
390
391 INNER JOIN {$wpdb->usermeta} AS ins_status
392 ON ( user.ID = ins_status.user_id )
393 AND ins_status.meta_key = '_tutor_instructor_status'
394 LEFT JOIN {$wpdb->usermeta} AS umeta
395 ON umeta.user_id = user.ID
396 AND umeta.meta_key = '_tutor_instructor_course_id'
397 WHERE ins_status.meta_value IN ($in_clause)
398 AND (user.user_email LIKE %s OR user.display_name LIKE %s)
399 {$course_clause}
400 {$date_clause}
401 {$order_clause}
402 LIMIT %d, %d;
403 ";
404 $result = TutorCache::get( self::INSTRUCTOR_LIST_CACHE_KEY );
405 if ( false === $result ) {
406 TutorCache::set(
407 self::INSTRUCTOR_LIST_CACHE_KEY,
408 //phpcs:disable
409 $result = $wpdb->get_results(
410 $wpdb->prepare(
411 $query,
412 $search_clause,
413 $search_clause,
414 $offset,
415 $per_page
416 )
417 )
418 //phpcs:enable
419 );
420 }
421
422 return $result;
423 }
424
425 /**
426 * Count total instructors
427 *
428 * @since 2.1.7
429 *
430 * @param array $status instructor status: approved, pending, block.
431 * @param string $search search keyword.
432 * @param string $course_id course id.
433 * @param string $date instructor registration date.
434 * @param string $unique_cache_key unique key will be append with
435 * self::INSTRUCTOR_COUNT_CACHE_KEY so that multiple count value could be
436 * stored as unique data.
437 *
438 * @return int count value of instructors
439 */
440 public static function count_total_instructors( array $status, $search = '', $course_id = '', $date = '', $unique_cache_key = '' ) {
441 global $wpdb;
442
443 $wild = '%';
444
445 $search_clause = $wild . $wpdb->esc_like( $search ) . $wild;
446 $course_clause = '';
447 if ( '' !== $course_id ) {
448 $course_id = (int) $course_id;
449 $course_clause = "AND umeta.meta_value = {$course_id}";
450 }
451
452 $date_clause = '' !== $date ? $wpdb->prepare( 'AND DATE(user.user_registered) = %s', $date ) : '';
453 $in_clause = QueryHelper::prepare_in_clause( $status );
454
455 $query = "SELECT
456 COUNT(DISTINCT user.ID)
457
458 FROM {$wpdb->users} AS user
459
460 INNER JOIN {$wpdb->usermeta} AS ins_status
461 ON ( user.ID = ins_status.user_id )
462 AND ins_status.meta_key = '_tutor_instructor_status'
463 LEFT JOIN {$wpdb->usermeta} AS umeta
464 ON umeta.user_id = user.ID
465 AND umeta.meta_key = '_tutor_instructor_course_id'
466 WHERE ins_status.meta_value IN ($in_clause)
467 AND (user.user_email LIKE %s OR user.display_name LIKE %s)
468 {$course_clause}
469 {$date_clause}
470 ";
471 $result = TutorCache::get( self::INSTRUCTOR_COUNT_CACHE_KEY . $unique_cache_key );
472 if ( false === $result ) {
473 TutorCache::set(
474 self::INSTRUCTOR_COUNT_CACHE_KEY,
475 //phpcs:disable
476 $result = $wpdb->get_var(
477 $wpdb->prepare(
478 $query,
479 $search_clause,
480 $search_clause
481 )
482 )
483 //phpcs:enable
484 );
485 }
486 return $result;
487 }
488 }
489