PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 3.6.1
Tutor LMS – eLearning and online course solution v3.6.1
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 / User.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 1 year ago Taxonomies.php 1 year 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
User.php
576 lines
1 <?php
2 /**
3 * Manage user
4 *
5 * @package Tutor\User
6 * @author Themeum <support@themeum.com>
7 * @link https://themeum.com
8 * @since 1.0.0
9 */
10
11 namespace TUTOR;
12
13 use Tutor\Helpers\HttpHelper;
14 use Tutor\Models\UserModel;
15 use Tutor\Traits\JsonResponse;
16
17 if ( ! defined( 'ABSPATH' ) ) {
18 exit;
19 }
20
21 /**
22 * User class
23 *
24 * @since 1.0.0
25 */
26 class User {
27 use JsonResponse;
28
29 const STUDENT = 'subscriber';
30 const INSTRUCTOR = 'tutor_instructor';
31 const ADMIN = 'administrator';
32
33 /**
34 * User meta keys.
35 */
36 const REVIEW_POPUP_META = 'tutor_review_course_popup';
37 const LAST_LOGIN_META = 'tutor_last_login';
38 const TIMEZONE_META = '_tutor_timezone';
39 const PROFILE_PHOTO_META = '_tutor_profile_photo';
40 const PHONE_NUMBER_META = 'phone_number';
41 const COVER_PHOTO_META = '_tutor_cover_photo';
42 const PROFILE_BIO_META = '_tutor_profile_bio';
43 const PROFILE_JOB_TITLE_META = '_tutor_profile_job_title';
44 const TUTOR_STUDENT_META = '_is_tutor_student';
45
46 /**
47 * User model
48 *
49 * @since 3.0.0
50 *
51 * @var UserModel
52 */
53 private $model;
54
55 /**
56 * Registration notice
57 *
58 * @since 1.0.0
59 *
60 * @var boolean
61 */
62 private static $hide_registration_notice = false;
63
64 /**
65 * Register hooks
66 *
67 * @since 1.0.0
68 * @since 2.2.0 $register_hooks param added to resuse the class without hooks register.
69 *
70 * @param bool $register_hooks register hooks.
71 *
72 * @return void
73 */
74 public function __construct( $register_hooks = true ) {
75 $this->model = new UserModel();
76 if ( ! $register_hooks ) {
77 return;
78 }
79
80 add_action( 'edit_user_profile', array( $this, 'edit_user_profile' ) );
81 add_action( 'show_user_profile', array( $this, 'edit_user_profile' ), 10, 1 );
82
83 add_action( 'profile_update', array( $this, 'profile_update' ) );
84 add_action( 'set_user_role', array( $this, 'set_user_role' ), 10, 3 );
85
86 add_action( 'wp_ajax_tutor_user_photo_remove', array( $this, 'tutor_user_photo_remove' ) );
87 add_action( 'wp_ajax_tutor_user_photo_upload', array( $this, 'update_user_photo' ) );
88
89 add_action( 'admin_notices', array( $this, 'show_registration_disabled' ) );
90 add_action( 'admin_init', array( $this, 'hide_notices' ) );
91 add_action( 'wp_login', array( $this, 'update_user_last_login' ), 10, 2 );
92 add_action( 'login_form', array( $this, 'add_timezone_input' ) );
93 add_action( 'wp_login', array( $this, 'set_timezone' ), 10, 2 );
94
95 add_action( 'wp_ajax_tutor_user_list', array( $this, 'ajax_user_list' ) );
96 }
97
98 /**
99 * Get meta key name for review popup.
100 *
101 * @since 2.4.0
102 *
103 * @param int $course_id course id.
104 *
105 * @return string user meta key name.
106 */
107 public static function get_review_popup_meta( $course_id ) {
108 return self::REVIEW_POPUP_META . '_' . $course_id;
109 }
110
111 /**
112 * Check user has provided role.
113 *
114 * @since 2.2.0
115 *
116 * @param string $role role.
117 *
118 * @return boolean
119 */
120 public static function is( string $role ) {
121 return current_user_can( $role );
122 }
123
124 /**
125 * Check user has any role.
126 *
127 * @since 2.2.0
128 * @since 2.6.2 $user_id param added.
129 *
130 * @param array $roles roles.
131 * @param int $user_id user id.
132 *
133 * @return boolean
134 */
135 public static function has_any_role( array $roles, $user_id = 0 ) {
136 $user = get_userdata( tutor_utils()->get_user_id( $user_id ) );
137 if ( empty( $user->roles ) || empty( $roles ) ) {
138 return false;
139 }
140
141 foreach ( $roles as $role ) {
142 if ( in_array( $role, $user->roles, true ) ) {
143 return true;
144 break;
145 }
146 }
147
148 return false;
149 }
150
151 /**
152 * Check user is student.
153 *
154 * @since 2.2.0
155 * @since 2.6.2 $user_id param added.
156 *
157 * @param int $user_id user id.
158 *
159 * @return boolean
160 */
161 public static function is_student( $user_id = 0 ) {
162 $is_tutor_student = get_user_meta( tutor_utils()->get_user_id( $user_id ), self::TUTOR_STUDENT_META, true );
163 return $is_tutor_student ? true : false;
164 }
165
166 /**
167 * Check user is admin.
168 *
169 * @since 2.2.0
170 * @since 3.2.0 user_id param added.
171 *
172 * @param int $user_id user id.
173 *
174 * @return boolean
175 */
176 public static function is_admin( $user_id = 0 ) {
177 return user_can( tutor_utils()->get_user_id( $user_id ), self::ADMIN );
178 }
179
180 /**
181 * Check current user is instructor.
182 *
183 * @since 2.2.0
184 * @since 3.2.0 user_id param added.
185 *
186 * @param int $user_id user id.
187 * @param bool $is_approved instructor is approved or not.
188 *
189 * @return boolean
190 */
191 public static function is_instructor( $user_id = 0, $is_approved = true ) {
192 return tutils()->is_instructor( $user_id, $is_approved );
193 }
194
195 /**
196 * Check current user is only instructor as admin also has instructor role.
197 *
198 * @since 3.2.0
199 *
200 * @param int $user_id user id.
201 * @param bool $is_approved instructor is approved or not.
202 *
203 * @return boolean
204 */
205 public static function is_only_instructor( $user_id = 0, $is_approved = true ) {
206 return ! self::is_admin( $user_id ) && self::is_instructor( $user_id, $is_approved );
207 }
208
209 /**
210 * Profile layouts
211 *
212 * @since 1.0.0
213 *
214 * @var array
215 */
216 private $profile_layout = array(
217 'pp-circle',
218 'pp-rectangle',
219 'no-cp',
220 );
221
222 /**
223 * Include edit user template
224 *
225 * @since 1.0.0
226 *
227 * @param mixed $user user.
228 *
229 * @return void
230 */
231 public function edit_user_profile( $user ) {
232 include tutor()->path . 'views/metabox/user-profile-fields.php';
233 }
234
235 /**
236 * Delete existing user's photo
237 *
238 * @since 1.0.0
239 *
240 * @param int $user_id user id.
241 * @param string $type photo type.
242 *
243 * @return void
244 */
245 private function delete_existing_user_photo( $user_id, $type ) {
246 $meta_key = 'cover_photo' == $type ? '_tutor_cover_photo' : '_tutor_profile_photo';
247 $photo_id = get_user_meta( $user_id, $meta_key, true );
248 is_numeric( $photo_id ) ? wp_delete_attachment( $photo_id, true ) : 0;
249 delete_user_meta( $user_id, $meta_key );
250 }
251
252 /**
253 * User photo remove
254 *
255 * @since 1.0.0
256 *
257 * @return void
258 */
259 public function tutor_user_photo_remove() {
260 tutor_utils()->checking_nonce();
261 $this->delete_existing_user_photo(
262 get_current_user_id(),
263 Input::post( 'photo_type', '' )
264 );
265 }
266
267 /**
268 * User photo update
269 *
270 * @since 1.0.0
271 *
272 * @return void
273 */
274 public function update_user_photo() {
275 tutor_utils()->checking_nonce();
276
277 $user_id = get_current_user_id();
278 $photo_type = Input::post( 'photo_type', '' );
279 $meta_key = 'cover_photo' === $photo_type ? '_tutor_cover_photo' : '_tutor_profile_photo';
280
281 /**
282 * Photo Update from profile
283 */
284 $photo = tutor_utils()->array_get( 'photo_file', $_FILES );
285 $photo_size = tutor_utils()->array_get( 'size', $photo );
286 $photo_type = tutor_utils()->array_get( 'type', $photo );
287
288 if ( $photo_size && strpos( $photo_type, 'image' ) !== false ) {
289 if ( ! function_exists( 'wp_handle_upload' ) ) {
290 require_once ABSPATH . 'wp-admin/includes/file.php';
291 }
292 $upload_overrides = array( 'test_form' => false );
293 $movefile = wp_handle_upload( $photo, $upload_overrides );
294
295 if ( $movefile && ! isset( $movefile['error'] ) ) {
296 $file_path = tutor_utils()->array_get( 'file', $movefile );
297 $file_url = tutor_utils()->array_get( 'url', $movefile );
298 $mime_type = '';
299 if ( file_exists( $file_path ) ) {
300 $image_info = getimagesize( $file_path );
301 $mime_type = is_array( $image_info ) && count( $image_info ) ? $image_info['mime'] : '';
302 }
303
304 $media_id = wp_insert_attachment(
305 array(
306 'guid' => $file_path,
307 'post_mime_type' => $mime_type,
308 'post_title' => preg_replace( '/\.[^.]+$/', '', basename( $file_url ) ),
309 'post_content' => '',
310 'post_status' => 'inherit',
311 ),
312 $file_path,
313 0
314 );
315
316 if ( $media_id ) {
317 // wp_generate_attachment_metadata() won't work if you do not include this file.
318 require_once ABSPATH . 'wp-admin/includes/image.php';
319
320 // Generate and save the attachment metas into the database.
321 wp_update_attachment_metadata( $media_id, wp_generate_attachment_metadata( $media_id, $file_path ) );
322
323 // Update it to user profile.
324 $this->delete_existing_user_photo( $user_id, Input::post( 'photo_type', '' ) );
325 update_user_meta( $user_id, $meta_key, $media_id );
326
327 exit( wp_json_encode( array( 'status' => 'success' ) ) );
328 }
329 }
330 }
331 }
332
333 /**
334 * Get user timezone string.
335 *
336 * @param int|object $user user id or user object. Default: current user.
337 *
338 * @return string user timezone string, fallback site timezone string.
339 */
340 public static function get_user_timezone_string( $user = 0 ) {
341 if ( is_numeric( $user ) ) {
342 $user = get_user_by( 'id', tutor_utils()->get_user_id( $user ) );
343 }
344
345 if ( ! is_a( $user, 'WP_User' ) ) {
346 return wp_timezone_string();
347 }
348
349 $timezone = get_user_meta( $user->ID, self::TIMEZONE_META, true );
350 if ( self::is_admin() || empty( $timezone ) ) {
351 $timezone = wp_timezone_string();
352 }
353
354 return $timezone;
355 }
356
357 /**
358 * Profile update
359 *
360 * @since 1.0.0
361 *
362 * @param int $user_id user id.
363 *
364 * @return void
365 */
366 public function profile_update( $user_id ) {
367 if ( 'tutor_profile_update_by_wp' !== Input::post( 'tutor_action' ) ) {
368 return;
369 }
370
371 $timezone = Input::post( 'timezone', '' );
372 $_tutor_profile_job_title = Input::post( self::PROFILE_JOB_TITLE_META, '' );
373 $_tutor_profile_bio = Input::post( self::PROFILE_BIO_META, '', Input::TYPE_KSES_POST );
374 $_tutor_profile_image = Input::post( self::PROFILE_PHOTO_META, '', Input::TYPE_KSES_POST );
375
376 update_user_meta( $user_id, self::PROFILE_JOB_TITLE_META, $_tutor_profile_job_title );
377 update_user_meta( $user_id, self::PROFILE_BIO_META, $_tutor_profile_bio );
378 update_user_meta( $user_id, self::PROFILE_PHOTO_META, $_tutor_profile_image );
379 update_user_meta( $user_id, self::TIMEZONE_META, $timezone );
380 }
381
382 /**
383 * Set user role
384 *
385 * @since 1.0.0
386 *
387 * @param int $user_id user id.
388 * @param string $role user role.
389 * @param array $old_roles old role.
390 *
391 * @return void
392 */
393 public function set_user_role( $user_id, $role, $old_roles ) {
394 $instructor_role = tutor()->instructor_role;
395
396 if ( $role === $instructor_role || in_array( $instructor_role, $old_roles ) ) {
397 tutor_utils()->add_instructor_role( $user_id );
398 }
399 }
400
401 /**
402 * Hide notices
403 *
404 * @since 1.0.0
405 *
406 * @return void
407 */
408 public function hide_notices() {
409 $hide_notice = Input::get( 'tutor-hide-notice', '' );
410 $is_register_enabled = Input::get( 'tutor-registration', '' );
411 $has_manage_cap = current_user_can( 'manage_options' );
412
413 if ( $has_manage_cap && is_admin() && 'registration' === $hide_notice ) {
414 tutor_utils()->checking_nonce( 'get' );
415
416 if ( 'enable' === $is_register_enabled ) {
417 update_option( 'users_can_register', 1 );
418 } else {
419 self::$hide_registration_notice = true;
420 setcookie( 'tutor_notice_hide_registration', 1, time() + MONTH_IN_SECONDS, tutor()->basepath );
421 }
422 }
423 }
424
425 /**
426 * Show registration disabled
427 *
428 * @since 1.0.0
429 *
430 * @return void
431 */
432 public function show_registration_disabled() {
433 if ( self::$hide_registration_notice ||
434 ( '0' !== get_option( 'users_can_register' ) ) ||
435 isset( $_COOKIE['tutor_notice_hide_registration'] ) ||
436 ! current_user_can( 'manage_options' )
437 ) {
438 return;
439 }
440
441 $hide_url = wp_nonce_url( add_query_arg( 'tutor-hide-notice', 'registration' ), tutor()->nonce_action, tutor()->nonce );
442 ?>
443 <div class="wrap tutor-user-registration-notice-wrapper">
444 <div class="tutor-user-registration-notice">
445 <div>
446 <img src="<?php echo esc_url( tutor()->url . 'assets/images/icon-info-round.svg' ); ?>"/>
447 </div>
448 <div>
449 <?php
450 echo wp_kses(
451 __( 'As membership is turned off, students and instructors will not be able to sign up. <strong>Press Enable</strong> or go to <strong>Settings > General > Membership</strong> and enable "Anyone can register".', 'tutor' ),
452 array( 'strong' => true )
453 );
454 ?>
455 </div>
456 <div>
457 <a href="<?php echo esc_url( add_query_arg( 'tutor-registration', 'enable', $hide_url ) ); ?>">
458 <?php esc_html_e( 'Enable', 'tutor' ); ?>
459 </a>
460 <hr/>
461 <a href="<?php echo esc_url( $hide_url ); ?>">
462 <?php esc_html_e( 'Dismiss', 'tutor' ); ?>
463 </a>
464 </div>
465 </div>
466 </div>
467 <?php
468 }
469
470 /**
471 * Set the user last active timestamp to now.
472 *
473 * @since 2.5.0
474 *
475 * @param string $user_login active user name.
476 * @param \WP_User $user User object data.
477 *
478 * @return void
479 */
480 public function update_user_last_login( $user_login, $user ) {
481 update_user_meta( $user->ID, self::LAST_LOGIN_META, time() );
482 }
483
484 /**
485 * Add timezone input field to login form.
486 *
487 * @since 3.0.0
488 */
489 public function add_timezone_input() {
490 ?>
491 <input type="hidden" name="timezone" value="<?php echo esc_attr( wp_timezone_string() ); ?>" />
492 <script>
493 document.addEventListener('DOMContentLoaded', function() {
494 const timezone = document.querySelector('input[name="timezone"]');
495 if ( timezone) {
496 const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
497 timezone.value = tz
498 }
499 });
500 </script>
501 <?php
502 }
503
504 /**
505 * Set user timezone if not it set.
506 *
507 * @since 3.0.0
508 *
509 * @param string $user_login active user name.
510 * @param \WP_User $user User object data.
511 *
512 * @return void
513 */
514 public function set_timezone( $user_login, $user ) {
515 if ( Input::has( 'timezone' ) ) {
516 $timezone = get_user_meta( $user->ID, self::TIMEZONE_META, true );
517 if ( empty( $timezone ) ) {
518 update_user_meta( $user->ID, self::TIMEZONE_META, Input::post( 'timezone', wp_timezone_string() ) );
519 }
520 }
521 }
522
523 /**
524 * Get user list with pagination & support
525 * search term
526 *
527 * @since 3.0.0
528 *
529 * @return void
530 */
531 public function ajax_user_list() {
532 tutor_utils()->check_nonce();
533
534 $can_access = apply_filters( 'tutor_user_list_access', current_user_can( 'manage_options' ) );
535 if ( ! $can_access ) {
536 $this->json_response( tutor_utils()->error_message( 'forbidden' ), HttpHelper::STATUS_FORBIDDEN );
537 }
538
539 $response = array(
540 'results' => array(),
541 'total_items' => 0,
542 );
543
544 $limit = Input::post( 'limit', 10, Input::TYPE_INT );
545 $offset = Input::post( 'offset', 0, Input::TYPE_INT );
546
547 $args = array(
548 'limit' => $limit,
549 'offset' => $offset,
550 );
551
552 $filter = json_decode( wp_unslash( $_POST['filter'] ?? '{}' ) );//phpcs:ignore
553 if ( ! empty( $filter ) && property_exists( $filter, 'search' ) && ! empty( $filter->search ) ) {
554 $args['search'] = '*' . Input::sanitize( $filter->search ) . '*';
555 $args['search_columns'] = array( 'user_login', 'user_email', 'user_nicename', 'display_name', 'ID' );
556 }
557
558 $user_list = $this->model->get_users_list( $args );
559
560 if ( is_object( $user_list ) ) {
561 foreach ( $user_list->get_results() as $user ) {
562 // Set user avatar.
563 $user->avatar_url = get_avatar_url( $user->ID, array( 'size' => 32 ) );
564 $response['results'][] = $user;
565 }
566
567 $response['total_items'] = $user_list->get_total();
568 }
569
570 $this->json_response(
571 __( 'User list fetched successfully!', 'tutor' ),
572 $response
573 );
574 }
575 }
576