PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 3.2.3
Tutor LMS – eLearning and online course solution v3.2.3
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 1 year ago Admin.php 1 year ago Ajax.php 1 year ago Announcements.php 1 year ago Assets.php 1 year ago Backend_Page_Trait.php 1 year ago BaseController.php 1 year ago Course.php 1 year ago Course_Embed.php 3 years ago Course_Filter.php 1 year ago Course_List.php 1 year 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 1 year ago FormHandler.php 2 years ago Frontend.php 1 year ago Gutenberg.php 1 year ago Input.php 1 year ago Instructor.php 1 year ago Instructors_List.php 1 year ago Lesson.php 1 year ago Options_V2.php 1 year ago Permalink.php 2 years ago Post_types.php 1 year ago Private_Course_Access.php 1 year ago Q_And_A.php 1 year ago Question_Answers_List.php 3 years ago Quiz.php 1 year ago QuizBuilder.php 1 year ago Quiz_Attempts_List.php 1 year ago RestAPI.php 2 years ago Reviews.php 3 years ago Rewrite_Rules.php 2 years ago Shortcode.php 1 year ago Singleton.php 1 year ago Student.php 1 year ago Students_List.php 3 years ago Taxonomies.php 3 years ago Template.php 1 year ago Theme_Compatibility.php 3 years ago Tools.php 1 year ago Tools_V2.php 1 year ago Tutor.php 1 year ago TutorEDD.php 1 year ago Tutor_Base.php 2 years ago Tutor_Setup.php 1 year ago Upgrader.php 1 year ago User.php 1 year ago Utils.php 1 year ago Video_Stream.php 3 years ago WhatsNew.php 2 years ago Withdraw.php 1 year ago Withdraw_Requests_List.php 1 year ago WooCommerce.php 1 year ago
Instructors_List.php
482 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 * Page Title
43 *
44 * @var $page_title
45 */
46 public $page_title;
47
48 /**
49 * Bulk Action
50 *
51 * @var $bulk_action
52 */
53 public $bulk_action = true;
54
55 /**
56 * Constructor
57 *
58 * @since 1.0.0
59 * @return void
60 */
61 public function __construct() {
62 $this->page_title = __( 'Instructor', 'tutor' );
63
64 /**
65 * Handle bulk action
66 *
67 * @since 2.0.0
68 */
69 add_action( 'wp_ajax_tutor_instructor_bulk_action', array( $this, 'instructor_bulk_action' ) );
70 }
71
72 /**
73 * Available tabs that will visible on the right side of page navbar
74 *
75 * @since 2.0.0
76 *
77 * @param string $search instructor search | optional.
78 * @param string $course_id course id that belong to instructor | optional.
79 * @param string $date user registered date | optional.
80 *
81 * @return array
82 */
83 public function tabs_key_value( $search = '', $course_id = '', $date = '' ): array {
84 $url = apply_filters( 'tutor_data_tab_base_url', get_pagenum_link() );
85 $approve = self::count_total_instructors( array( 'approved' ), $search, $course_id, $date, 'approved' );
86 $pending = self::count_total_instructors( array( 'pending' ), $search, $course_id, $date, 'pending' );
87 $blocked = self::count_total_instructors( array( 'blocked' ), $search, $course_id, $date, 'blocked' );
88
89 $tabs = array(
90 array(
91 'key' => 'all',
92 'title' => __( 'All', 'tutor' ),
93 'value' => $approve + $pending + $blocked,
94 'url' => $url . '&data=all',
95 ),
96 array(
97 'key' => 'approved',
98 'title' => __( 'Approve', 'tutor' ),
99 'value' => $approve,
100 'url' => $url . '&data=approved',
101 ),
102 array(
103 'key' => 'pending',
104 'title' => __( 'Pending', 'tutor' ),
105 'value' => $pending,
106 'url' => $url . '&data=pending',
107 ),
108 array(
109 'key' => 'blocked',
110 'title' => __( 'Block', 'tutor' ),
111 'value' => $blocked,
112 'url' => $url . '&data=blocked',
113 ),
114 );
115 return $tabs;
116 }
117
118 /**
119 * Prepare bulk actions that will show on dropdown options
120 *
121 * @since 2.0.0
122 * @return array
123 */
124 public function prpare_bulk_actions(): array {
125 $actions = array(
126 $this->bulk_action_default(),
127 $this->bulk_action_approved(),
128 $this->bulk_action_pending(),
129 $this->bulk_action_blocked(),
130 );
131 return $actions;
132 }
133
134 /**
135 * Handle bulk action for instructor delete
136 *
137 * @since 2.0.0
138 * @return string JSON response.
139 */
140 public function instructor_bulk_action() {
141 tutor_utils()->checking_nonce();
142
143 // Check if user is privileged.
144 if ( ! current_user_can( 'administrator' ) ) {
145 wp_send_json_error( tutor_utils()->error_message() );
146 }
147
148 $action = Input::post( 'bulk-action', '' );
149 $bulk_ids = Input::post( 'bulk-ids', '' );
150
151 Input::has( 'bulkIds' ) ? $bulk_ids = Input::post( 'bulkIds' ) : 0;
152
153 if ( '' === $action || '' === $bulk_ids ) {
154 return wp_send_json_error();
155 }
156 if ( 'delete' === $action ) {
157 // Delete user from student_list class.
158 do_action( 'tutor_before_instructor_delete', $bulk_ids );
159 $response = Students_List::delete_students( $bulk_ids );
160 do_action( 'tutor_after_instructor_delete', $bulk_ids );
161 } else {
162 do_action( 'tutor_before_instructor_update', $bulk_ids );
163 $response = self::update_instructors( $action, $bulk_ids );
164 do_action( 'tutor_after_instructor_delete', $bulk_ids );
165 }
166
167 $message = 'Instructor status updated';
168
169 return true === $response ? wp_send_json_success( array( 'status' => $message ) ) : wp_send_json_error();
170 }
171
172 /**
173 * Execute bulk action for enrollment list ex: complete | cancel
174 *
175 * @since 2.0.0
176 *
177 * @param string $status hold status for updating.
178 * @param string $user_ids comma seperated user ids.
179 *
180 * @return bool
181 */
182 public static function update_instructors( $status, $user_ids ): bool {
183 global $wpdb;
184 $status = sanitize_text_field( $status );
185 $instructor_table = $wpdb->usermeta;
186
187 $ids = array_map( 'intval', explode( ',', $user_ids ) );
188 $in_clause = QueryHelper::prepare_in_clause( $ids );
189
190 //phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
191 $update = $wpdb->query(
192 $wpdb->prepare(
193 "UPDATE {$instructor_table} SET meta_value = %s
194 WHERE user_id IN ($in_clause)
195 AND meta_key = %s",
196 $status,
197 '_tutor_instructor_status'
198 )
199 );
200 //phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
201
202 // Remove role.
203 if ( 'pending' === $status || 'blocked' === $status ) {
204 $arr = explode( ',', $user_ids );
205 foreach ( $arr as $instructor_id ) {
206 $instructor_id = (int) sanitize_text_field( $instructor_id );
207 if ( 'pending' === $status ) {
208 self::remove_instructor_role( $instructor_id, $status );
209 } else {
210 self::instructor_blockage( $instructor_id );
211 }
212 }
213 }
214 if ( 'reject' === $status ) {
215 $arr = explode( ',', $user_ids );
216 foreach ( $arr as $instructor_id ) {
217 $instructor_id = (int) sanitize_text_field( $instructor_id );
218 self::instructor_rejection( $instructor_id );
219 }
220 }
221
222 if ( 'approved' === $status ) {
223 $arr = explode( ',', $user_ids );
224 foreach ( $arr as $instructor_id ) {
225 $instructor_id = (int) sanitize_text_field( $instructor_id );
226 self::add_instructor_role( $instructor_id, $status );
227 }
228 }
229 return false === $update ? false : true;
230 }
231
232 /**
233 * Get total course.
234 *
235 * @since 1.0.0
236 *
237 * @param object $item item.
238 * @return void
239 */
240 public function column_total_course( $item ) {
241 global $wpdb;
242 $course_post_type = tutor()->course_post_type;
243
244 $total_course = (int) $wpdb->get_var(
245 $wpdb->prepare(
246 "SELECT count(ID) from {$wpdb->posts}
247 WHERE post_author=%d AND post_type=%s ",
248 $item->ID,
249 $course_post_type
250 )
251 );
252
253 echo esc_html( $total_course );
254 }
255
256 /**
257 * Initialize instructor_role to a user
258 *
259 * @since 1.0.0
260 *
261 * @param integer $instructor_id | user id that need to add role.
262 * @param string $status | status that will added with role (approved).
263 *
264 * @return void
265 */
266 protected static function add_instructor_role( int $instructor_id, string $status ) {
267 $instructor_id = sanitize_text_field( $instructor_id );
268 $status = sanitize_text_field( $status );
269
270 do_action( 'tutor_before_approved_instructor', $instructor_id );
271
272 update_user_meta( $instructor_id, '_tutor_instructor_status', $status );
273 update_user_meta( $instructor_id, '_tutor_instructor_approved', tutor_time() );
274
275 $instructor = new \WP_User( $instructor_id );
276 $instructor->add_role( tutor()->instructor_role );
277
278 // TODO: send E-Mail to this user about instructor approval, should via hook.
279 do_action( 'tutor_after_approved_instructor', $instructor_id );
280 }
281
282 /**
283 * Initialize instructor_role to a user
284 *
285 * @since 1.0.0
286 *
287 * @param int $instructor_id | user id that need to add role.
288 * @param string $status | status that will added with role (approved).
289 *
290 * @return void
291 */
292 protected static function remove_instructor_role( int $instructor_id, string $status ) {
293 $instructor_id = sanitize_text_field( $instructor_id );
294 $status = sanitize_text_field( $status );
295 update_user_meta( $instructor_id, '_tutor_instructor_status', $status );
296 $instructor = new \WP_User( $instructor_id );
297 $instructor->remove_role( tutor()->instructor_role );
298 }
299 /**
300 * Instructor blocking function
301 *
302 * @since 2.5.0
303 *
304 * @param int $instructor_id | user id that need to add role.
305 * @return void
306 */
307 protected static function instructor_blockage( int $instructor_id ) {
308 $instructor_id = sanitize_text_field( $instructor_id );
309 do_action( 'tutor_before_blocked_instructor', $instructor_id );
310 self::remove_instructor_role( $instructor_id, 'blocked' );
311 do_action( 'tutor_after_blocked_instructor', $instructor_id );
312 }
313 /**
314 * Instructor rejection function
315 *
316 * @since 2.5.0
317 *
318 * @param int $instructor_id | user id that need to add role.
319 * @return void
320 */
321 protected static function instructor_rejection( int $instructor_id ) {
322 $instructor_id = sanitize_text_field( $instructor_id );
323 do_action( 'tutor_before_rejected_instructor', $instructor_id );
324
325 /**
326 * Removed tutor_instructor role and set `try_again` status
327 * for apply again as instructor with show message to applier in frontend.
328 */
329 self::remove_instructor_role( $instructor_id, 'try_again' );
330 delete_user_meta( $instructor_id, '_is_tutor_instructor' );
331
332 do_action( 'tutor_after_rejected_instructor', $instructor_id );
333 }
334
335 /**
336 * Get instructors list
337 *
338 * @since 2.1.7
339 *
340 * @param array $status instructor status: approved, pending, block.
341 * @param int $offset offset for pagination.
342 * @param int $per_page per page limit.
343 * @param string $search search keyword.
344 * @param string $course_id course id.
345 * @param string $date instructor registration date.
346 * @param string $order sorting order.
347 *
348 * @return wpdb::results
349 */
350 public static function get_instructors( array $status, $offset, $per_page, $search = '', $course_id = '', $date = '', $order = 'DESC' ) {
351 global $wpdb;
352
353 $wild = '%';
354
355 $search_clause = $wild . $wpdb->esc_like( $search ) . $wild;
356 $course_clause = '';
357 if ( '' !== $course_id ) {
358 $course_id = (int) $course_id;
359 $course_clause = "AND umeta.meta_value = {$course_id}";
360 }
361
362 $order_clause = '';
363 if ( '' !== $order ) {
364 $is_valid_sql = sanitize_sql_orderby( $order );
365 if ( $is_valid_sql ) {
366 $order_clause = "ORDER BY user.ID {$order}";
367 }
368 }
369
370 $date_clause = '' !== $date ? "AND DATE(user.user_registered) = CAST('$date' AS DATE )" : '';
371 $in_clause = QueryHelper::prepare_in_clause( $status );
372
373 $query = "SELECT
374 DISTINCT user.*,
375 ins_status.meta_value AS status,
376 (
377 SELECT
378 COUNT(*)
379 FROM {$wpdb->posts}
380 WHERE post_author = user.ID
381 AND post_type = 'courses'
382 ) total_courses
383 FROM {$wpdb->users} AS user
384
385 INNER JOIN {$wpdb->usermeta} AS ins_status
386 ON ( user.ID = ins_status.user_id )
387 AND ins_status.meta_key = '_tutor_instructor_status'
388 LEFT JOIN {$wpdb->usermeta} AS umeta
389 ON umeta.user_id = user.ID
390 AND umeta.meta_key = '_tutor_instructor_course_id'
391 WHERE ins_status.meta_value IN ($in_clause)
392 AND (user.user_email LIKE %s OR user.display_name LIKE %s)
393 {$course_clause}
394 {$date_clause}
395 {$order_clause}
396 LIMIT %d, %d;
397 ";
398 $result = TutorCache::get( self::INSTRUCTOR_LIST_CACHE_KEY );
399 if ( false === $result ) {
400 TutorCache::set(
401 self::INSTRUCTOR_LIST_CACHE_KEY,
402 //phpcs:disable
403 $result = $wpdb->get_results(
404 $wpdb->prepare(
405 $query,
406 $search_clause,
407 $search_clause,
408 $offset,
409 $per_page
410 )
411 )
412 //phpcs:enable
413 );
414 }
415
416 return $result;
417 }
418
419 /**
420 * Count total instructors
421 *
422 * @since 2.1.7
423 *
424 * @param array $status instructor status: approved, pending, block.
425 * @param string $search search keyword.
426 * @param string $course_id course id.
427 * @param string $date instructor registration date.
428 * @param string $unique_cache_key unique key will be append with
429 * self::INSTRUCTOR_COUNT_CACHE_KEY so that multiple count value could be
430 * stored as unique data.
431 *
432 * @return int count value of instructors
433 */
434 public static function count_total_instructors( array $status, $search = '', $course_id = '', $date = '', $unique_cache_key = '' ) {
435 global $wpdb;
436
437 $wild = '%';
438
439 $search_clause = $wild . $wpdb->esc_like( $search ) . $wild;
440 $course_clause = '';
441 if ( '' !== $course_id ) {
442 $course_id = (int) $course_id;
443 $course_clause = "AND umeta.meta_value = {$course_id}";
444 }
445 $date_clause = '' !== $date ? "AND DATE(user.user_registered) = CAST('$date' AS DATE )" : '';
446 $in_clause = QueryHelper::prepare_in_clause( $status );
447
448 $query = "SELECT
449 COUNT(DISTINCT user.ID)
450
451 FROM {$wpdb->users} AS user
452
453 INNER JOIN {$wpdb->usermeta} AS ins_status
454 ON ( user.ID = ins_status.user_id )
455 AND ins_status.meta_key = '_tutor_instructor_status'
456 LEFT JOIN {$wpdb->usermeta} AS umeta
457 ON umeta.user_id = user.ID
458 AND umeta.meta_key = '_tutor_instructor_course_id'
459 WHERE ins_status.meta_value IN ($in_clause)
460 AND (user.user_email LIKE %s OR user.display_name LIKE %s)
461 {$course_clause}
462 {$date_clause}
463 ";
464 $result = TutorCache::get( self::INSTRUCTOR_COUNT_CACHE_KEY . $unique_cache_key );
465 if ( false === $result ) {
466 TutorCache::set(
467 self::INSTRUCTOR_COUNT_CACHE_KEY,
468 //phpcs:disable
469 $result = $wpdb->get_var(
470 $wpdb->prepare(
471 $query,
472 $search_clause,
473 $search_clause
474 )
475 )
476 //phpcs:enable
477 );
478 }
479 return $result;
480 }
481 }
482