PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.9
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.9
4.4.9 4.4.8 4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.9.1 4.3.9 4.3.8 4.3.7 4.1.6.9 4.1.6.9.1 4.1.6.9.2 4.1.6.9.3 4.1.6.9.4 4.1.7 4.1.7.1 4.1.7.2 4.1.7.3 4.1.7.3.1 4.1.7.3.2 All 140 releases
← All changes | inc/jwt/rest-api/version1/class-lp-rest-users-v1-controller.php +1587 -1587 4.3.8 → 4.4.9 View file →
@@ -1,1587 +1,1587 @@
1 -<?php
2 -
3 -use LearnPress\Models\UserModel;
4 -
5 -/**
6 - * REST API for the user.
7 - *
8 - * @package LearnPress/JWT/RESTAPI
9 - * @author Nhamdv <[email protected]>
10 - */
11 -class LP_Jwt_Users_V1_Controller extends LP_REST_Jwt_Controller {
12 - protected $namespace = 'learnpress/v1';
13 -
14 - protected $rest_base = 'users';
15 -
16 - protected $hierarchical = true;
17 -
18 - protected $meta;
19 -
20 - public function __construct() {
21 - $this->meta = new WP_REST_User_Meta_Fields();
22 - }
23 -
24 - public function register_routes() {
25 - register_rest_route(
26 - $this->namespace,
27 - '/' . $this->rest_base,
28 - array(
29 - array(
30 - 'methods' => WP_REST_Server::READABLE,
31 - 'callback' => array( $this, 'get_items' ),
32 - 'permission_callback' => array( $this, 'get_items_permissions_check' ),
33 - 'args' => $this->get_collection_params(),
34 - ),
35 - 'schema' => array( $this, 'get_public_item_schema' ),
36 - )
37 - );
38 -
39 - register_rest_route(
40 - $this->namespace,
41 - '/' . $this->rest_base . '/(?P<id>[\d]+)',
42 - array(
43 - 'args' => array(
44 - 'id' => array(
45 - 'description' => esc_html__( 'A unique identifier for the resource.', 'learnpress' ),
46 - 'type' => 'integer',
47 - ),
48 - ),
49 - array(
50 - 'methods' => WP_REST_Server::READABLE,
51 - 'callback' => array( $this, 'get_item' ),
52 - 'permission_callback' => array( $this, 'get_item_permissions_check' ),
53 - 'args' => array(
54 - 'context' => $this->get_context_param(
55 - array(
56 - 'default' => 'view',
57 - )
58 - ),
59 - ),
60 - ),
61 - array(
62 - 'methods' => WP_REST_Server::EDITABLE,
63 - 'callback' => array( $this, 'update_item' ),
64 - 'permission_callback' => array( $this, 'update_item_permissions_check' ),
65 - 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
66 - ),
67 - 'schema' => array( $this, 'get_public_item_schema' ),
68 - )
69 - );
70 -
71 - register_rest_route(
72 - $this->namespace,
73 - '/' . $this->rest_base . '/reset-password',
74 - array(
75 - 'methods' => WP_REST_Server::EDITABLE,
76 - 'callback' => array( $this, 'reset_password' ),
77 - 'permission_callback' => '__return_true',
78 - 'args' => array(
79 - 'user_login' => array(
80 - 'description' => esc_html__( 'User or Email login.', 'learnpress' ),
81 - 'type' => 'string',
82 - 'required' => true,
83 - ),
84 - ),
85 - )
86 - );
87 -
88 - register_rest_route(
89 - $this->namespace,
90 - '/' . $this->rest_base . '/change-password',
91 - array(
92 - 'methods' => WP_REST_Server::EDITABLE,
93 - 'callback' => array( $this, 'change_password' ),
94 - 'permission_callback' => array( $this, 'update_item_password_permissions' ),
95 - 'args' => array(
96 - 'old_password' => array(
97 - 'description' => esc_html__( 'Old Password', 'learnpress' ),
98 - 'type' => 'string',
99 - 'required' => true,
100 - ),
101 - 'new_password' => array(
102 - 'description' => esc_html__( 'New Password', 'learnpress' ),
103 - 'type' => 'string',
104 - 'required' => true,
105 - ),
106 - ),
107 - )
108 - );
109 -
110 - register_rest_route(
111 - $this->namespace,
112 - '/' . $this->rest_base . '/delete',
113 - array(
114 - 'methods' => WP_REST_Server::EDITABLE,
115 - 'callback' => array( $this, 'delete_account' ),
116 - 'permission_callback' => array( $this, 'update_item_password_permissions' ),
117 - 'args' => array(
118 - 'id' => array(
119 - 'description' => esc_html__( 'User ID', 'learnpress' ),
120 - 'type' => 'integer',
121 - 'required' => true,
122 - ),
123 - 'password' => array(
124 - 'description' => esc_html__( 'Password', 'learnpress' ),
125 - 'type' => 'string',
126 - 'required' => true,
127 - ),
128 - ),
129 - )
130 - );
131 - }
132 -
133 - public function get_items_permissions_check( $request ) {
134 - return true;
135 - }
136 -
137 - public function get_item_permissions_check( $request ) {
138 - $user = $this->get_user( $request['id'] );
139 -
140 - if ( is_wp_error( $user ) ) {
141 - return $user;
142 - }
143 -
144 - if ( ! is_user_logged_in() ) {
145 - return new WP_Error(
146 - 'rest_forbidden',
147 - __( 'Authentication required to access user information.' ),
148 - array( 'status' => rest_authorization_required_code() )
149 - );
150 - }
151 -
152 - $types = get_post_types( array( 'show_in_rest' => true ), 'names' );
153 -
154 - if ( get_current_user_id() === $user->ID ) {
155 - return true;
156 - } elseif ( ! current_user_can( UserModel::ROLE_ADMINISTRATOR ) ) {
157 - return new WP_Error(
158 - 'rest_user_cannot_view',
159 - __( 'Sorry, you are not allowed to list users.' ),
160 - array( 'status' => rest_authorization_required_code() )
161 - );
162 - }
163 -
164 - return true;
165 - }
166 -
167 - /**
168 - * Checks if a given request has access to update a user.
169 - *
170 - * @since 4.7.0
171 - *
172 - * @param WP_REST_Request $request Full details about the request.
173 - * @return true|WP_Error True if the request has access to update the item, WP_Error object otherwise.
174 - */
175 - public function update_item_permissions_check( $request ) {
176 - $user = $this->get_user( $request['id'] );
177 - if ( is_wp_error( $user ) ) {
178 - return $user;
179 - }
180 -
181 - if ( ! empty( $request['roles'] ) ) {
182 - if ( ! current_user_can( 'promote_user', $user->ID ) ) {
183 - return new WP_Error(
184 - 'rest_cannot_edit_roles',
185 - __( 'Sorry, you are not allowed to edit roles of this user.' ),
186 - array( 'status' => rest_authorization_required_code() )
187 - );
188 - }
189 -
190 - $request_params = array_keys( $request->get_params() );
191 - sort( $request_params );
192 - // If only 'id' and 'roles' are specified (we are only trying to
193 - // edit roles), then only the 'promote_user' cap is required.
194 - if ( array( 'id', 'roles' ) === $request_params ) {
195 - return true;
196 - }
197 - }
198 -
199 - if ( ! current_user_can( 'edit_user', $user->ID ) ) {
200 - return new WP_Error(
201 - 'rest_cannot_edit',
202 - __( 'Sorry, you are not allowed to edit this user.' ),
203 - array( 'status' => rest_authorization_required_code() )
204 - );
205 - }
206 -
207 - return true;
208 - }
209 -
210 - public function update_item_password_permissions( $request ) {
211 - $user = wp_get_current_user();
212 -
213 - if ( ! $user ) {
214 - return new WP_Error(
215 - 'rest_cannot_update',
216 - __( 'Sorry, you are not allowed to update this user.' ),
217 - array( 'status' => rest_authorization_required_code() )
218 - );
219 - }
220 -
221 - if ( ! current_user_can( 'edit_user', $user->ID ) ) {
222 - return new WP_Error(
223 - 'rest_cannot_edit',
224 - __( 'Sorry, you are not allowed to edit this user.' ),
225 - array( 'status' => rest_authorization_required_code() )
226 - );
227 - }
228 -
229 - return true;
230 - }
231 -
232 - /**
233 - * Determines if the current user is allowed to make the desired roles change.
234 - *
235 - * @since 4.7.0
236 - *
237 - * @param int $user_id User ID.
238 - * @param array $roles New user roles.
239 - * @return true|WP_Error True if the current user is allowed to make the role change,
240 - * otherwise a WP_Error object.
241 - */
242 - protected function check_role_update( $user_id, $roles ) {
243 - global $wp_roles;
244 -
245 - foreach ( $roles as $role ) {
246 -
247 - if ( ! isset( $wp_roles->role_objects[ $role ] ) ) {
248 - return new WP_Error(
249 - 'rest_user_invalid_role',
250 - /* translators: %s: Role key. */
251 - sprintf( __( 'The role %s does not exist.' ), $role ),
252 - array( 'status' => 400 )
253 - );
254 - }
255 -
256 - $potential_role = $wp_roles->role_objects[ $role ];
257 -
258 - /*
259 - * Don't let anyone with 'edit_users' (admins) edit their own role to something without it.
260 - * Multisite super admins can freely edit their blog roles -- they possess all caps.
261 - */
262 - if ( ! ( is_multisite()
263 - && current_user_can( 'manage_sites' ) )
264 - && get_current_user_id() === $user_id
265 - && ! $potential_role->has_cap( 'edit_users' )
266 - ) {
267 - return new WP_Error(
268 - 'rest_user_invalid_role',
269 - __( 'Sorry, you are not allowed to give users that role.' ),
270 - array( 'status' => rest_authorization_required_code() )
271 - );
272 - }
273 -
274 - // Include user admin functions to get access to get_editable_roles().
275 - require_once ABSPATH . 'wp-admin/includes/user.php';
276 -
277 - // The new role must be editable by the logged-in user.
278 - $editable_roles = get_editable_roles();
279 -
280 - if ( empty( $editable_roles[ $role ] ) ) {
281 - return new WP_Error(
282 - 'rest_user_invalid_role',
283 - __( 'Sorry, you are not allowed to give users that role.' ),
284 - array( 'status' => 403 )
285 - );
286 - }
287 - }
288 -
289 - return true;
290 - }
291 -
292 - public function reset_password( $request ) {
293 - $user_login = $request['user_login'];
294 - $reset = LP_Forms_Handler::retrieve_password( $user_login );
295 -
296 - if ( is_wp_error( $reset ) ) {
297 - return $reset;
298 - } else {
299 - return rest_ensure_response(
300 - array(
301 - 'code' => 'success',
302 - 'message' => esc_html__( 'A link to reset your password has been emailed to you.', 'learnpress' ),
303 - )
304 - );
305 - }
306 - }
307 -
308 - public function delete_account( $request ) {
309 - $user_id = $request['id'];
310 - $password = $request['password'];
311 -
312 - $user = wp_get_current_user();
313 -
314 - if ( ! $user || $user_id !== $user->ID ) {
315 - return new WP_Error(
316 - 'rest_user_invalid_id',
317 - __( 'Invalid user ID.', 'learnpress' ),
318 - array( 'status' => 400 )
319 - );
320 - }
321 -
322 - if ( ! wp_check_password( $password, $user->data->user_pass, $user->ID ) ) {
323 - return new WP_Error(
324 - 'rest_user_invalid_password',
325 - __( 'Invalid password.', 'learnpress' ),
326 - array( 'status' => 400 )
327 - );
328 - }
329 -
330 - if ( ! function_exists( 'wp_delete_user' ) ) {
331 - require_once ABSPATH . 'wp-admin/includes/user.php';
332 - }
333 -
334 - $delete = wp_delete_user( $user_id );
335 -
336 - if ( is_wp_error( $delete ) ) {
337 - return $delete;
338 - } else {
339 - return rest_ensure_response(
340 - array(
341 - 'code' => 'success',
342 - 'message' => esc_html__( 'Your account has been deleted.', 'learnpress' ),
343 - )
344 - );
345 - }
346 - }
347 -
348 - public function change_password( $request ) {
349 - $old_password = $request['old_password'];
350 - $new_password = $request['new_password'];
351 -
352 - $user = wp_get_current_user();
353 -
354 - if ( ! $user || ! $user->ID || ( empty( $old_password ) || empty( $new_password ) ) ) {
355 - return new WP_Error(
356 - 'rest_user_cannot_change_password',
357 - __( 'Sorry, you are not allowed to change password.' ),
358 - array( 'status' => rest_authorization_required_code() )
359 - );
360 - }
361 -
362 - if ( ! wp_check_password( $old_password, $user->user_pass, $user->ID ) ) {
363 - return new WP_Error(
364 - 'rest_user_incorrect_password',
365 - __( 'Your current password is incorrect.' ),
366 - array( 'status' => 403 )
367 - );
368 - }
369 -
370 - if ( apply_filters( 'learnpress_rest_api_user_change_password', true, $user ) ) {
371 - wp_set_password( $new_password, $user->ID );
372 - } else {
373 - return new WP_Error(
374 - 'rest_user_cannot_change_password',
375 - __( 'Sorry, you are not allowed to change password.' ),
376 - array( 'status' => rest_authorization_required_code() )
377 - );
378 - }
379 -
380 - return rest_ensure_response(
381 - array(
382 - 'code' => 'success',
383 - 'message' => esc_html__( 'Your password has been updated. Please log in again to continue!', 'learnpress' ),
384 - )
385 - );
386 - }
387 -
388 - protected function get_user( $id ) {
389 - $error = new WP_Error(
390 - 'rest_user_invalid_id',
391 - __( 'Invalid user ID.' ),
392 - array( 'status' => 404 )
393 - );
394 -
395 - if ( (int) $id <= 0 ) {
396 - return $error;
397 - }
398 -
399 - $user = get_userdata( (int) $id );
400 - if ( empty( $user ) || ! $user->exists() ) {
401 - return $error;
402 - }
403 -
404 - if ( is_multisite() && ! is_user_member_of_blog( $user->ID ) ) {
405 - return $error;
406 - }
407 -
408 - return $user;
409 - }
410 -
411 - /**
412 - * Updates a single user.
413 - *
414 - * @param WP_REST_Request $request Full details about the request.
415 - * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
416 - */
417 - public function update_item( $request ) {
418 - $user = $this->get_user( $request['id'] );
419 - if ( is_wp_error( $user ) ) {
420 - return $user;
421 - }
422 -
423 - $id = $user->ID;
424 -
425 - if ( ! $user ) {
426 - return new WP_Error(
427 - 'rest_user_invalid_id',
428 - __( 'Invalid user ID.' ),
429 - array( 'status' => 404 )
430 - );
431 - }
432 -
433 - $owner_id = email_exists( $request['email'] );
434 -
435 - if ( $owner_id && $owner_id !== $id ) {
436 - return new WP_Error(
437 - 'rest_user_invalid_email',
438 - __( 'Invalid email address.' ),
439 - array( 'status' => 400 )
440 - );
441 - }
442 -
443 - if ( ! empty( $request['username'] ) && $request['username'] !== $user->user_login ) {
444 - return new WP_Error(
445 - 'rest_user_invalid_argument',
446 - __( "Username isn't editable." ),
447 - array( 'status' => 400 )
448 - );
449 - }
450 -
451 - if ( ! empty( $request['slug'] ) && $request['slug'] !== $user->user_nicename && get_user_by( 'slug', $request['slug'] ) ) {
452 - return new WP_Error(
453 - 'rest_user_invalid_slug',
454 - __( 'Invalid slug.' ),
455 - array( 'status' => 400 )
456 - );
457 - }
458 -
459 - if ( ! empty( $request['roles'] ) ) {
460 - $check_permission = $this->check_role_update( $id, $request['roles'] );
461 -
462 - if ( is_wp_error( $check_permission ) ) {
463 - return $check_permission;
464 - }
465 - }
466 -
467 - $user = $this->prepare_item_for_database( $request );
468 -
469 - // Ensure we're operating on the same user we already checked.
470 - $user->ID = $id;
471 -
472 - $user_id = wp_update_user( wp_slash( (array) $user ) );
473 -
474 - if ( is_wp_error( $user_id ) ) {
475 - return $user_id;
476 - }
477 -
478 - $files = $request->get_file_params();
479 -
480 - if ( ! empty( $files['lp_avatar_file'] ) ) {
481 - $file = $files['lp_avatar_file'];
482 -
483 - if ( ! empty( $file['name'] ) ) {
484 - list($width, $height) = getimagesize( $file['tmp_name'] );
485 -
486 - $upload_size = learn_press_get_avatar_thumb_size();
487 -
488 - if ( $width != $upload_size['width'] || $height != $upload_size['height'] ) {
489 - return new WP_Error(
490 - 'rest_user_invalid_avatar_dimensions',
491 - sprintf( __( 'Invalid avatar dimensions. Please upload a new avatar width size %1$1sx%2$2s' ), $upload_size['width'], $upload_size['height'] ),
492 - array( 'status' => 400 )
493 - );
494 - }
495 -
496 - $data = LP_WP_Filesystem::instance()->file_get_contents( $file['tmp_name'] );
497 - $base64 = base64_encode( $data );
498 -
499 - $controller = new LP_REST_Profile_Controller();
500 -
501 - $request->set_param( 'file', $base64 );
502 -
503 - $uploaded_avatar = $controller->upload_avatar( $request );
504 - }
505 - }
506 -
507 - if ( ! empty( $request['avatar_url'] ) ) {
508 - $controller = new LP_REST_Profile_Controller();
509 -
510 - $request->set_param( 'file', $request['avatar_url'] );
511 -
512 - $uploaded_avatar = $controller->upload_avatar( $request );
513 - }
514 -
515 - $user = get_user_by( 'id', $user_id );
516 -
517 - do_action( 'lp_rest_insert_user', $user, $request, false );
518 -
519 - if ( ! empty( $request['roles'] ) ) {
520 - array_map( array( $user, 'add_role' ), $request['roles'] );
521 - }
522 -
523 - $schema = $this->get_item_schema();
524 -
525 - if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) {
526 - $meta_update = $this->meta->update_value( $request['meta'], $user_id );
527 -
528 - if ( is_wp_error( $meta_update ) ) {
529 - return $meta_update;
530 - }
531 - }
532 -
533 - $user = get_user_by( 'id', $user_id );
534 - $fields_update = $this->update_additional_fields_for_object( $user, $request );
535 -
536 - if ( is_wp_error( $fields_update ) ) {
537 - return $fields_update;
538 - }
539 -
540 - $request->set_param( 'context', 'edit' );
541 -
542 - do_action( 'lp_rest_after_insert_user', $user, $request, false );
543 -
544 - $response = $this->prepare_item_for_response( $user, $request );
545 - $response = rest_ensure_response( $response );
546 -
547 - return $response;
548 - }
549 -
550 - /**
551 - * Prepares a single user for creation or update.
552 - *
553 - * @param WP_REST_Request $request Request object.
554 - * @return object User object.
555 - */
556 - protected function prepare_item_for_database( $request ) {
557 - $prepared_user = new stdClass();
558 -
559 - $schema = $this->get_item_schema();
560 -
561 - // Required arguments.
562 - if ( isset( $request['email'] ) && ! empty( $schema['properties']['email'] ) ) {
563 - $prepared_user->user_email = $request['email'];
564 - }
565 -
566 - if ( isset( $request['username'] ) && ! empty( $schema['properties']['username'] ) ) {
567 - $prepared_user->user_login = $request['username'];
568 - }
569 -
570 - if ( isset( $request['password'] ) && ! empty( $schema['properties']['password'] ) ) {
571 - $prepared_user->user_pass = $request['password'];
572 - }
573 -
574 - // Optional arguments.
575 - if ( isset( $request['id'] ) ) {
576 - $prepared_user->ID = absint( $request['id'] );
577 - }
578 -
579 - if ( isset( $request['name'] ) && ! empty( $schema['properties']['name'] ) ) {
580 - $prepared_user->display_name = $request['name'];
581 - }
582 -
583 - if ( isset( $request['first_name'] ) && ! empty( $schema['properties']['first_name'] ) ) {
584 - $prepared_user->first_name = $request['first_name'];
585 - }
586 -
587 - if ( isset( $request['last_name'] ) && ! empty( $schema['properties']['last_name'] ) ) {
588 - $prepared_user->last_name = $request['last_name'];
589 - }
590 -
591 - if ( isset( $request['nickname'] ) && ! empty( $schema['properties']['nickname'] ) ) {
592 - $prepared_user->nickname = $request['nickname'];
593 - }
594 -
595 - if ( isset( $request['slug'] ) && ! empty( $schema['properties']['slug'] ) ) {
596 - $prepared_user->user_nicename = $request['slug'];
597 - }
598 -
599 - if ( isset( $request['description'] ) && ! empty( $schema['properties']['description'] ) ) {
600 - $prepared_user->description = $request['description'];
601 - }
602 -
603 - if ( isset( $request['url'] ) && ! empty( $schema['properties']['url'] ) ) {
604 - $prepared_user->user_url = $request['url'];
605 - }
606 -
607 - if ( isset( $request['locale'] ) && ! empty( $schema['properties']['locale'] ) ) {
608 - $prepared_user->locale = $request['locale'];
609 - }
610 -
611 - // Setting roles will be handled outside of this function.
612 - if ( isset( $request['roles'] ) ) {
613 - $prepared_user->role = false;
614 - }
615 -
616 - /**
617 - * Filters user data before insertion via the REST API.
618 - *
619 - * @param object $prepared_user User object.
620 - * @param WP_REST_Request $request Request object.
621 - */
622 - return apply_filters( 'lp_rest_pre_insert_user', $prepared_user, $request );
623 - }
624 -
625 - public function get_overview_tab_contents( $user ) {
626 - $output = array();
627 - $statistic = LP_Profile::instance( $user->get_id )->get_statistic_info();
628 -
629 - $output['statistic'] = array_map( 'absint', $statistic );
630 -
631 - $featured_query = new LP_Course_Query(
632 - array(
633 - 'paginate' => false,
634 - 'featured' => 'yes',
635 - 'return' => 'ids',
636 - 'author' => $user->ID,
637 - )
638 - );
639 -
640 - $output['featured'] = $featured_query->get_courses();
641 -
642 - $latest_query = new LP_Course_Query(
643 - array(
644 - 'paginate' => false,
645 - 'return' => 'ids',
646 - 'author' => $user->get_id(),
647 - 'limit' => '-1',
648 - )
649 - );
650 -
651 - $output['latest'] = $latest_query->get_courses();
652 -
653 - return $output;
654 - }
655 -
656 - public function get_course_tab_contents( $user, $request ) {
657 - $output = array(
658 - 'enrolled' => array(),
659 - 'created' => array(),
660 - );
661 -
662 - $profile = learn_press_get_profile( $user->get_id() );
663 - $filters_enrolled = array(
664 - 'all' => 'all',
665 - 'finished' => 'finished',
666 - 'passed' => 'passed',
667 - 'failed' => 'failed',
668 - 'in-progress' => 'in-progress',
669 - );
670 -
671 - if ( method_exists( $profile, 'query_courses' ) ) {
672 - foreach ( $filters_enrolled as $key => $filter ) {
673 - $query_enrolled = $profile->query_courses(
674 - 'purchased',
675 - array(
676 - 'status' => $filter,
677 - 'limit' => $request['per_page'] ?? '100',
678 - 'paged' => $request['paged'] ?? 1,
679 - )
680 - );
681 -
682 - if ( empty( $query_enrolled->get_items() ) ) {
683 - continue;
684 - }
685 -
686 - $items = $query_enrolled->get_items();
687 - $enrolled_ids = array();
688 - foreach ( $items as $enrolled_item ) {
689 - $course_data = $user->get_course_data( $enrolled_item );
690 -
691 - if ( $course_data ) {
692 - $post = get_post( $enrolled_item );
693 -
694 - $enrolled_ids[] = array(
695 - 'id' => $enrolled_item ?? '',
696 - 'title' => $post->post_title,
697 - 'graduation' => ! empty( $course_data->get_graduation() ) ? $course_data->get_graduation() : '',
698 - 'status' => ! empty( $course_data->get_status() ) ? $course_data->get_status() : '',
699 - 'start_time' => lp_jwt_prepare_date_response( $course_data->get_start_time() ? $course_data->get_start_time()->toSql() : '' ),
700 - 'end_time' => lp_jwt_prepare_date_response( $course_data->get_end_time() ? $course_data->get_end_time()->toSql() : '' ),
701 - 'expiration' => lp_jwt_prepare_date_response( $course_data->get_expiration_time() ? $course_data->get_expiration_time()->toSql() : '' ),
702 - 'results' => $course_data->calculate_course_results(),
703 - );
704 - }
705 - }
706 -
707 - $output['enrolled'][ $key ] = $enrolled_ids;
708 - }
709 - }
710 -
711 - $filters_created = array(
712 - 'all' => '',
713 - 'publish' => 'publish',
714 - 'pending' => 'pending',
715 - );
716 -
717 - if ( method_exists( $profile, 'query_courses' ) ) {
718 - foreach ( $filters_created as $created_key => $filter ) {
719 - $query_created = $profile->query_courses(
720 - 'own',
721 - array(
722 - 'status' => $filter,
723 - 'limit' => $request['per_page'] ?? '100',
724 - 'paged' => $request['paged'] ?? 1,
725 - )
726 - );
727 -
728 - $created_ids = array();
729 - if ( ! empty( $query_created->get_items() ) ) {
730 - foreach ( $query_created->get_items() as $created_item ) {
731 - $created_ids[] = $created_item;
732 - }
733 - }
734 -
735 - $output['created'][ $created_key ] = array_map( 'absint', $created_ids );
736 - }
737 - }
738 -
739 - return $output;
740 - }
741 -
742 - /**
743 - * Get Profile Quiz Tab content
744 - *
745 - * @param [type] $request
746 - * @return void
747 - *
748 - * @author Nhamdv <[email protected]>
749 - */
750 - public function get_quiz_tab_contents( $user, $request ) {
751 - $output = array();
752 -
753 - $user_profile = learn_press_get_user( $request['id'] );
754 - $filters = array(
755 - 'all' => '',
756 - 'finished' => 'completed',
757 - 'passed' => 'passed',
758 - 'failed' => 'failed',
759 - 'in-progress' => 'in-progress',
760 - );
761 -
762 - if ( method_exists( $user_profile, 'get_user_quizzes' ) ) {
763 - foreach ( $filters as $key => $quiz_filter ) {
764 - $filter = new LP_User_Items_Filter();
765 - $filter->user_id = $request['id'];
766 - $filter->limit = 100;
767 - $filter->status = $quiz_filter === 'complete' ? 'complete' : '';
768 - $filter->graduation = $quiz_filter !== 'complete' ? $quiz_filter : '';
769 - $query = $user_profile->get_user_quizzes( $filter );
770 -
771 - $ids = array();
772 - if ( ! empty( $query->get_items() ) ) {
773 - foreach ( $query->get_items() as $item ) {
774 - $ids[] = array(
775 - 'id' => $item->get_id(),
776 - 'result' => $item->get_percent_result() ?? '',
777 - 'graduation' => $item->get_graduation() ?? '',
778 - 'start_time' => $item->get_start_time() ? lp_jwt_prepare_date_response( $item->get_start_time()->toSql( false ) ) : '',
779 - 'end_time' => $item->get_end_time() ? lp_jwt_prepare_date_response( $item->get_end_time()->toSql( false ) ) : '',
780 - 'data' => $filter !== 'in-progress' ? $item->calculate_quiz_result() : array(),
781 - 'attempt' => $filter !== 'in-progress' ? $item->get_attempts() : array(),
782 - );
783 - }
784 - }
785 -
786 - $output[ $key ] = $ids;
787 - }
788 - }
789 -
790 - return $output;
791 - }
792 -
793 - /**
794 - * Get order by user id
795 - *
796 - * @param array $request [id: user ID]
797 - * @return array
798 - *
799 - * @author Nhamdv <[email protected]>
800 - */
801 - public function get_order_content_tab( $user, $request ) {
802 - $output = array();
803 -
804 - $profile = learn_press_get_profile( $request['id'] );
805 -
806 - if ( method_exists( $profile, 'query_orders' ) ) {
807 - $query_orders = $profile->query_orders( array( 'fields' => 'ids' ) );
808 - if ( ! empty( $query_orders->get_items() ) ) {
809 - foreach ( $query_orders->get_items() as $order_id ) {
810 - $order = learn_press_get_order( $order_id );
811 -
812 - $output[ $order_id ] = array(
813 - 'order_key' => $order->get_order_number() ?? '',
814 - 'total' => $order->get_total(),
815 - 'currency' => $order->get_currency(),
816 - 'status' => $order->get_status(),
817 - 'date' => $order->get_order_date( 'timestamp' ) ? lp_jwt_prepare_date_response( get_date_from_gmt( gmdate( 'Y-m-d H:i:s', $order->get_order_date( 'timestamp' ) ), 'Y-m-d H:i:s' ) ) : '',
818 - );
819 - }
820 - }
821 - }
822 -
823 - return $output;
824 - }
825 -
826 - /**
827 - * Retrieves a single user.
828 - *
829 - * @since 4.7.0
830 - *
831 - * @param WP_REST_Request $request Full details about the request.
832 - * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
833 - */
834 - public function get_item( $request ) {
835 - $user = $this->get_user( $request['id'] );
836 -
837 - if ( is_wp_error( $user ) ) {
838 - return $user;
839 - }
840 -
841 - $user = $this->prepare_item_for_response( $user, $request );
842 - $response = rest_ensure_response( $user );
843 -
844 - return $response;
845 - }
846 -
847 - /**
848 - * Retrieves all users.
849 - *
850 - * @since 4.7.0
851 - *
852 - * @param WP_REST_Request $request Full details about the request.
853 - * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
854 - */
855 - public function get_items( $request ) {
856 - // Fixed security, with request ?context=edit
857 - if ( isset( $_REQUEST['context'] ) ) {
858 - die();
859 - }
860 -
861 - // Retrieve the list of registered collection query parameters.
862 - $registered = $this->get_collection_params();
863 -
864 - /*
865 - * This array defines mappings between public API query parameters whose
866 - * values are accepted as-passed, and their internal WP_Query parameter
867 - * name equivalents (some are the same). Only values which are also
868 - * present in $registered will be set.
869 - */
870 - $parameter_mappings = array(
871 - 'exclude' => 'exclude',
872 - 'include' => 'include',
873 - 'order' => 'order',
874 - 'per_page' => 'number',
875 - 'search' => 'search',
876 - 'roles' => 'role__in',
877 - 'slug' => 'nicename__in',
878 - );
879 -
880 - $roles = $request->get_param( 'roles' );
881 - if ( ! empty( $roles ) && $roles == [ UserModel::ROLE_ADMINISTRATOR ] ) {
882 - return new WP_Error(
883 - 'rest_forbidden',
884 - __( 'You are not allowed.' ),
885 - array( 'status' => rest_authorization_required_code() )
886 - );
887 - }
888 -
889 - // Always only get instructors and administrators.
890 - $request['roles'] = [ UserModel::ROLE_INSTRUCTOR, UserModel::ROLE_ADMINISTRATOR ];
891 -
892 - $prepared_args = array();
893 -
894 - /*
895 - * For each known parameter which is both registered and present in the request,
896 - * set the parameter's value on the query $prepared_args.
897 - */
898 - foreach ( $parameter_mappings as $api_param => $wp_param ) {
899 - if ( isset( $registered[ $api_param ], $request[ $api_param ] ) ) {
900 - $prepared_args[ $wp_param ] = $request[ $api_param ];
901 - }
902 - }
903 -
904 - if ( isset( $registered['offset'] ) && ! empty( $request['offset'] ) ) {
905 - $prepared_args['offset'] = $request['offset'];
906 - } else {
907 - $prepared_args['offset'] = ( $request['page'] - 1 ) * $prepared_args['number'];
908 - }
909 -
910 - if ( isset( $registered['orderby'] ) ) {
911 - $orderby_possibles = array(
912 - 'id' => 'ID',
913 - 'include' => 'include',
914 - 'name' => 'display_name',
915 - 'registered_date' => 'registered',
916 - 'slug' => 'user_nicename',
917 - 'include_slugs' => 'nicename__in',
918 - 'email' => 'user_email',
919 - 'url' => 'user_url',
920 - );
921 - $prepared_args['orderby'] = $orderby_possibles[ $request['orderby'] ];
922 - }
923 -
924 - if ( isset( $registered['who'] ) && ! empty( $request['who'] ) && 'authors' === $request['who'] ) {
925 - $prepared_args['who'] = 'authors';
926 - }
927 -
928 - if ( ! empty( $prepared_args['search'] ) ) {
929 - $prepared_args['search'] = '*' . $prepared_args['search'] . '*';
930 - }
931 - /**
932 - * Filters WP_User_Query arguments when querying users via the REST API.
933 - *
934 - * @link https://developer.wordpress.org/reference/classes/wp_user_query/
935 - *
936 - * @since 4.7.0
937 - *
938 - * @param array $prepared_args Array of arguments for WP_User_Query.
939 - * @param WP_REST_Request $request The REST API request.
940 - */
941 - $prepared_args = apply_filters( 'rest_user_query', $prepared_args, $request );
942 -
943 - $users = array();
944 - $lp_cache = new LP_Cache();
945 - $key_cache_list_instructors = 'lp_get_instructors';
946 -
947 - // Check cache with cache get instructors.
948 - if ( isset( $prepared_args['role__in'] ) ) {
949 - $users = $lp_cache->get_cache( $key_cache_list_instructors );
950 - $total_users = $lp_cache->get_cache( $key_cache_list_instructors . '/total' );
951 - }
952 -
953 - if ( $users === false ) {
954 - // Query max 10 instructors only.
955 - $prepared_args['number'] = 10;
956 -
957 - $query = new WP_User_Query( $prepared_args );
958 - $users_result = $query->get_results();
959 - $total_users = $query->get_total();
960 -
961 - foreach ( $users_result as $user ) {
962 - $data = $this->prepare_item_for_response( $user, $request );
963 -
964 - $user = $this->prepare_response_for_collection( $data );
965 - unset( $user['custom_register'] );
966 - unset( $user['is_super_admin'] );
967 - $users[] = $user;
968 - }
969 -
970 - // Set cache with cache get instructors.
971 - $lp_cache->set_cache( $key_cache_list_instructors, $users );
972 - $lp_cache->set_cache( $key_cache_list_instructors . '/total', $total_users );
973 - }
974 -
975 - $response = rest_ensure_response( $users );
976 -
977 - // Store pagination values for headers then unset for count query.
978 - $per_page = (int) $prepared_args['number'];
979 - $page = ceil( ( ( (int) $prepared_args['offset'] ) / $per_page ) + 1 );
980 -
981 - $prepared_args['fields'] = 'ID';
982 -
983 - if ( $total_users < 1 ) {
984 - // Out-of-bounds, run the query again without LIMIT for total count.
985 - unset( $prepared_args['number'], $prepared_args['offset'] );
986 - $count_query = new WP_User_Query( $prepared_args );
987 - $total_users = $count_query->get_total();
988 - }
989 -
990 - $response->header( 'X-WP-Total', (int) $total_users );
991 -
992 - $max_pages = ceil( $total_users / $per_page );
993 -
994 - $response->header( 'X-WP-TotalPages', (int) $max_pages );
995 -
996 - $base = add_query_arg( urlencode_deep( $request->get_query_params() ), rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ) );
997 - if ( $page > 1 ) {
998 - $prev_page = $page - 1;
999 -
1000 - if ( $prev_page > $max_pages ) {
1001 - $prev_page = $max_pages;
1002 - }
1003 -
1004 - $prev_link = add_query_arg( 'page', $prev_page, $base );
1005 - $response->link_header( 'prev', $prev_link );
1006 - }
1007 - if ( $max_pages > $page ) {
1008 - $next_page = $page + 1;
1009 - $next_link = add_query_arg( 'page', $next_page, $base );
1010 -
1011 - $response->link_header( 'next', $next_link );
1012 - }
1013 -
1014 - return $response;
1015 - }
1016 -
1017 - /**
1018 - * Prepares a single user output for response.
1019 - *
1020 - * @since 4.7.0
1021 - *
1022 - * @param WP_User $user User object.
1023 - * @param WP_REST_Request $request Request object.
1024 - * @return WP_REST_Response Response object.
1025 - */
1026 - public function prepare_item_for_response( $user, $request ) {
1027 - $context = ! empty( $request['context'] ) ? $request['context'] : 'embed';
1028 - $data = $this->get_users_data( $user, $context, $request );
1029 -
1030 - $data = $this->add_additional_fields_to_object( $data, $request );
1031 - $data = $this->filter_response_by_context( $data, $context );
1032 -
1033 - // Wrap the data in a response object.
1034 - $response = rest_ensure_response( $data );
1035 -
1036 - $response->add_links( $this->prepare_links( $user ) );
1037 -
1038 - return apply_filters( 'lp_rest_prepare_user', $response, $user, $request );
1039 - }
1040 -
1041 - public function get_users_data( $user, $context = 'view' ) {
1042 - $request = func_num_args() >= 2 ? func_get_arg( 2 ) : new WP_REST_Request( '', '', array( 'context' => $context ) );
1043 - $fields = $this->get_fields_for_response( $request );
1044 - $data = array();
1045 -
1046 - foreach ( $fields as $field ) {
1047 - switch ( $field ) {
1048 - case 'id':
1049 - $data['id'] = $user->ID;
1050 - break;
1051 - case 'username':
1052 - if ( current_user_can( 'list_users' ) || current_user_can( 'edit_user', $user->ID ) ) {
1053 - $data['username'] = $user->user_login;
1054 - }
1055 - break;
1056 - case 'name':
1057 - $data['name'] = $user->display_name;
1058 - break;
1059 - case 'first_name':
1060 - $data['first_name'] = $user->first_name;
1061 - break;
1062 - case 'last_name':
1063 - $data['last_name'] = $user->last_name;
1064 - break;
1065 - case 'email':
1066 - if ( current_user_can( 'list_users' ) || current_user_can( 'edit_user', $user->ID ) ) {
1067 - $data['email'] = $user->user_email;
1068 - }
1069 - break;
1070 - case 'url':
1071 - $data['url'] = $user->user_url;
1072 - break;
1073 - case 'description':
1074 - $data['description'] = $user->description;
1075 - break;
1076 - case 'link':
1077 - $data['link'] = get_author_posts_url( $user->ID, $user->user_nicename );
1078 - break;
1079 - case 'locale':
1080 - $data['locale'] = get_user_locale( $user );
1081 - break;
1082 - case 'nickname':
1083 - $data['nickname'] = $user->nickname;
1084 - break;
1085 - case 'slug':
1086 - $data['slug'] = $user->user_nicename;
1087 - break;
1088 - case 'roles':
1089 - $data['roles'] = array_values( $user->roles );
1090 - break;
1091 - case 'registered_date':
1092 - $data['registered_date'] = gmdate( 'c', strtotime( $user->user_registered ) );
1093 - break;
1094 - case 'capabilities':
1095 - $data['capabilities'] = (object) $user->allcaps;
1096 - break;
1097 - case 'extra_capabilities':
1098 - $data['extra_capabilities'] = (object) $user->caps;
1099 - break;
1100 - case 'avatar_url':
1101 - $data['avatar_url'] = $this->get_profile_avatar( $user->ID );
1102 - break;
1103 - case 'avatar_size':
1104 - $data['avatar_size']['width'] = learn_press_get_avatar_thumb_size()['width'];
1105 - $data['avatar_size']['height'] = learn_press_get_avatar_thumb_size()['height'];
1106 - break;
1107 - case 'instructor_data':
1108 - // $data['instructor_data'] = $this->get_instructor_data( $user->ID );
1109 - $data['instructor_data'] = LP_Profile::instance( $user->ID )->get_statistic_info();
1110 - break;
1111 - case 'meta':
1112 - $data['meta'] = $this->meta->get_value( $user->ID, $request );
1113 - break;
1114 - case 'tabs':
1115 - $data['tabs'] = $this->get_lp_data_tabs( $user, $request );
1116 - break;
1117 - case 'custom_register':
1118 - $data['custom_register'] = $this->custom_register( $user );
1119 - break;
1120 - case 'social':
1121 - $data['social'] = $this->get_social_data( $user->ID );
1122 - break;
1123 - }
1124 - }
1125 -
1126 - return $data;
1127 - }
1128 -
1129 - public function get_social_data( $user_id ) {
1130 - return learn_press_get_user_extra_profile_info( $user_id );
1131 - }
1132 -
1133 - /**
1134 - * @since 4.1.4
1135 - * @version 1.0.1
1136 - */
1137 - public function get_profile_avatar( $user_id ): string {
1138 - $user = learn_press_get_user( $user_id );
1139 -
1140 - return $user->get_profile_avatar_url();
1141 - }
1142 -
1143 - /**
1144 - * @editor tungnx
1145 - * @deprecated 4.1.6
1146 - */
1147 - /*
1148 - public function get_instructor_data( $user_id ) {
1149 - $profile = learn_press_get_profile( $user_id );
1150 -
1151 - $output = array();
1152 -
1153 - if ( is_wp_error( $profile ) ) {
1154 - return $output;
1155 - }
1156 -
1157 - $query = $profile->query_courses( 'purchased' );
1158 - $counts = $query['counts'];
1159 -
1160 - $output = array(
1161 - 'enrolled_courses' => isset( $counts['all'] ) ? absint( $counts['all'] ) : 0,
1162 - 'completed_courses' => isset( $counts['finished'] ) ? absint( $counts['finished'] ) : 0,
1163 - 'courses' => absint( count_user_posts( $user_id, LP_COURSE_CPT ) ),
1164 - 'students' => absint( learn_press_count_instructor_users( $user_id ) ),
1165 - );
1166 -
1167 - return $output;
1168 - }*/
1169 -
1170 - /**
1171 - * Get data tabs.
1172 - *
1173 - * @param $user
1174 - * @param $request
1175 - *
1176 - * @return array
1177 - */
1178 - public function get_lp_data_tabs( $user, $request ): array {
1179 - $output = array();
1180 -
1181 - if ( get_current_user_id() === $user->ID || current_user_can( 'list_users' ) ) {
1182 - if ( function_exists( 'learn_press_get_user_profile_tabs' ) ) {
1183 - $tabs = learn_press_get_user_profile_tabs();
1184 -
1185 - $content = array(
1186 - 'overview' => $this->get_overview_tab_contents( $user ),
1187 - 'courses' => $this->get_course_tab_contents( $user, $request ),
1188 - 'quizzes' => $this->get_quiz_tab_contents( $user, $request ),
1189 - 'orders' => $this->get_order_content_tab( $user, $request ),
1190 - );
1191 -
1192 - /**
1193 - * @var LP_Profile_Tab $tab
1194 - */
1195 - foreach ( $tabs->get() as $key => $tab ) {
1196 - $output[ $key ] = array(
1197 - 'title' => $tab->get( 'title' ) ?? '',
1198 - 'slug' => $tab->get( 'slug' ) ?? '',
1199 - 'priority' => $tab->get( 'priority' ) ?? '',
1200 - 'icon' => $tab->get( 'icon' ) ?? '',
1201 - 'content' => $content[ $key ] ?? '',
1202 - );
1203 -
1204 - if ( ! empty( $tab->get( 'sections' ) ) ) {
1205 - foreach ( $tab->get( 'sections' ) as $section_key => $section ) {
1206 - $output[ $key ]['section'][ $section_key ] = array(
1207 - 'title' => $section['title'] ?? '',
1208 - 'slug' => $section['slug'] ?? '',
1209 - 'priority' => $section['priority'] ?? '',
1210 - );
1211 - }
1212 - }
1213 - }
1214 - }
1215 - }
1216 -
1217 - return $output;
1218 - }
1219 -
1220 - /**
1221 - * Display register cutom form in LearnPress Setting
1222 - *
1223 - * @param object $user
1224 - * @return array
1225 - */
1226 - public function custom_register( $user ) {
1227 - $output = array();
1228 -
1229 - if ( function_exists( 'lp_get_user_custom_register_fields' ) ) {
1230 - $custom_fields = LP_Profile::get_register_fields_custom();
1231 - $custom_profile = lp_get_user_custom_register_fields( $user->ID );
1232 -
1233 - if ( $custom_fields ) {
1234 - foreach ( $custom_fields as $field ) {
1235 - $value = $field['id'];
1236 - $output[ $value ] = array(
1237 - 'title' => $field['name'] ?? '',
1238 - 'type' => $field['type'] ?? '',
1239 - 'required' => $field['required'] ?? 'no',
1240 - 'value' => $custom_profile[ $value ] ?? '',
1241 - );
1242 - }
1243 - }
1244 - }
1245 -
1246 - return $output;
1247 - }
1248 -
1249 - /**
1250 - * Prepares links for the user request.
1251 - *
1252 - * @since 4.7.0
1253 - *
1254 - * @param WP_User $user User object.
1255 - * @return array Links for the given user.
1256 - */
1257 - protected function prepare_links( $user ) {
1258 - $links = array(
1259 - 'self' => array(
1260 - 'href' => rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $user->ID ) ),
1261 - ),
1262 - 'collection' => array(
1263 - 'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ),
1264 - ),
1265 - );
1266 -
1267 - return $links;
1268 - }
1269 -
1270 - public function check_username( $value, $request, $param ) {
1271 - $username = (string) $value;
1272 -
1273 - if ( ! validate_username( $username ) ) {
1274 - return new WP_Error(
1275 - 'rest_user_invalid_username',
1276 - __( 'This username is invalid because it uses illegal characters. Please enter a valid username.' ),
1277 - array( 'status' => 400 )
1278 - );
1279 - }
1280 -
1281 - /** This filter is documented in wp-includes/user.php */
1282 - $illegal_logins = (array) apply_filters( 'illegal_user_logins', array() );
1283 -
1284 - if ( in_array( strtolower( $username ), array_map( 'strtolower', $illegal_logins ), true ) ) {
1285 - return new WP_Error(
1286 - 'rest_user_invalid_username',
1287 - __( 'Sorry, that username is not allowed.' ),
1288 - array( 'status' => 400 )
1289 - );
1290 - }
1291 -
1292 - return $username;
1293 - }
1294 -
1295 - /**
1296 - * Check a user password for the REST API.
1297 - *
1298 - * Performs a couple of checks like edit_user() in wp-admin/includes/user.php.
1299 - *
1300 - * @since 4.7.0
1301 - *
1302 - * @param string $value The password submitted in the request.
1303 - * @param WP_REST_Request $request Full details about the request.
1304 - * @param string $param The parameter name.
1305 - * @return string|WP_Error The sanitized password, if valid, otherwise an error.
1306 - */
1307 - public function check_user_password( $value, $request, $param ) {
1308 - $password = (string) $value;
1309 -
1310 - if ( empty( $password ) ) {
1311 - return new WP_Error(
1312 - 'rest_user_invalid_password',
1313 - __( 'Passwords cannot be empty.' ),
1314 - array( 'status' => 400 )
1315 - );
1316 - }
1317 -
1318 - if ( false !== strpos( $password, '\\' ) ) {
1319 - return new WP_Error(
1320 - 'rest_user_invalid_password',
1321 - sprintf(
1322 - /* translators: %s: The '\' character. */
1323 - __( 'Passwords cannot contain the "%s" character.' ),
1324 - '\\'
1325 - ),
1326 - array( 'status' => 400 )
1327 - );
1328 - }
1329 -
1330 - return $password;
1331 - }
1332 -
1333 - public function get_item_schema() {
1334 - $schema = array(
1335 - '$schema' => 'http://json-schema.org/draft-04/schema#',
1336 - 'title' => 'user',
1337 - 'type' => 'object',
1338 - 'properties' => array(
1339 - 'id' => array(
1340 - 'description' => __( 'Unique identifier for the user.' ),
1341 - 'type' => 'integer',
1342 - 'context' => array( 'embed', 'view', 'edit' ),
1343 - 'readonly' => true,
1344 - ),
1345 - 'username' => array(
1346 - 'description' => __( 'Login name for the user.' ),
1347 - 'type' => 'string',
1348 - 'context' => array( 'view', 'edit' ),
1349 - 'required' => true,
1350 - 'arg_options' => array(
1351 - 'sanitize_callback' => array( $this, 'check_username' ),
1352 - ),
1353 - ),
1354 - 'name' => array(
1355 - 'description' => __( 'Display name for the user.' ),
1356 - 'type' => 'string',
1357 - 'context' => array( 'embed', 'view', 'edit' ),
1358 - 'arg_options' => array(
1359 - 'sanitize_callback' => 'sanitize_text_field',
1360 - ),
1361 - ),
1362 - 'first_name' => array(
1363 - 'description' => __( 'First name for the user.' ),
1364 - 'type' => 'string',
1365 - 'context' => array( 'view', 'edit' ),
1366 - 'arg_options' => array(
1367 - 'sanitize_callback' => 'sanitize_text_field',
1368 - ),
1369 - ),
1370 - 'last_name' => array(
1371 - 'description' => __( 'Last name for the user.' ),
1372 - 'type' => 'string',
1373 - 'context' => array( 'view', 'edit' ),
1374 - 'arg_options' => array(
1375 - 'sanitize_callback' => 'sanitize_text_field',
1376 - ),
1377 - ),
1378 - 'email' => array(
1379 - 'description' => __( 'The email address for the user.' ),
1380 - 'type' => 'string',
1381 - 'format' => 'email',
1382 - 'context' => array( 'view', 'edit' ),
1383 - 'required' => true,
1384 - ),
1385 - 'url' => array(
1386 - 'description' => __( 'URL of the user.' ),
1387 - 'type' => 'string',
1388 - 'format' => 'uri',
1389 - 'context' => array( 'embed', 'view', 'edit' ),
1390 - ),
1391 - 'description' => array(
1392 - 'description' => __( 'Description of the user.' ),
1393 - 'type' => 'string',
1394 - 'context' => array( 'embed', 'view', 'edit' ),
1395 - ),
1396 - 'link' => array(
1397 - 'description' => __( 'Author URL of the user.' ),
1398 - 'type' => 'string',
1399 - 'format' => 'uri',
1400 - 'context' => array( 'embed', 'view', 'edit' ),
1401 - 'readonly' => true,
1402 - ),
1403 - 'locale' => array(
1404 - 'description' => __( 'Locale for the user.' ),
1405 - 'type' => 'string',
1406 - 'enum' => array_merge( array( '', 'en_US' ), get_available_languages() ),
1407 - 'context' => array( 'edit' ),
1408 - ),
1409 - 'nickname' => array(
1410 - 'description' => __( 'The nickname for the user.' ),
1411 - 'type' => 'string',
1412 - 'context' => array( 'view', 'edit' ),
1413 - 'arg_options' => array(
1414 - 'sanitize_callback' => 'sanitize_text_field',
1415 - ),
1416 - ),
1417 - 'slug' => array(
1418 - 'description' => __( 'An alphanumeric identifier for the user.' ),
1419 - 'type' => 'string',
1420 - 'context' => array( 'embed', 'view', 'edit' ),
1421 - 'arg_options' => array(
1422 - 'sanitize_callback' => array( $this, 'sanitize_slug' ),
1423 - ),
1424 - ),
1425 - 'registered_date' => array(
1426 - 'description' => __( 'Registration date for the user.' ),
1427 - 'type' => 'string',
1428 - 'format' => 'date-time',
1429 - 'context' => array( 'edit' ),
1430 - 'readonly' => true,
1431 - ),
1432 - 'roles' => array(
1433 - 'description' => __( 'Roles assigned to the user.' ),
1434 - 'type' => 'array',
1435 - 'items' => array(
1436 - 'type' => 'string',
1437 - ),
1438 - 'context' => array( 'edit' ),
1439 - ),
1440 - 'password' => array(
1441 - 'description' => __( 'Password for the user (never included).' ),
1442 - 'type' => 'string',
1443 - 'context' => array(), // Password is never displayed.
1444 - 'required' => true,
1445 - 'arg_options' => array(
1446 - 'sanitize_callback' => array( $this, 'check_user_password' ),
1447 - ),
1448 - ),
1449 - 'capabilities' => array(
1450 - 'description' => __( 'All capabilities assigned to the user.' ),
1451 - 'type' => 'object',
1452 - 'context' => array( 'edit' ),
1453 - 'readonly' => true,
1454 - ),
1455 - 'extra_capabilities' => array(
1456 - 'description' => __( 'Any extra capabilities assigned to the user.' ),
1457 - 'type' => 'object',
1458 - 'context' => array( 'edit' ),
1459 - 'readonly' => true,
1460 - ),
1461 - 'tabs' => array(
1462 - 'description' => __( 'Get all items in user like course, lesson, quiz...' ),
1463 - 'type' => 'array',
1464 - 'context' => array( 'view' ),
1465 - ),
1466 - 'avatar_url' => array(
1467 - 'description' => __( 'URL avatar' ),
1468 - 'type' => 'string',
1469 - 'context' => array( 'view', 'edit' ),
1470 - ),
1471 - 'avatar_size' => array(
1472 - 'description' => __( 'URL avatar size' ),
1473 - 'type' => 'array',
1474 - 'context' => array( 'view' ),
1475 - ),
1476 - 'instructor_data' => array(
1477 - 'description' => __( 'Instructor data' ),
1478 - 'type' => 'array',
1479 - 'context' => array( 'view' ),
1480 - ),
1481 - 'custom_register' => array(
1482 - 'description' => __( 'Get custom register fields.' ),
1483 - 'type' => 'object',
1484 - 'context' => array( 'view' ),
1485 - ),
1486 - 'social' => array(
1487 - 'description' => __( 'Get social fields.' ),
1488 - 'type' => 'object',
1489 - 'context' => array( 'view' ),
1490 - ),
1491 - ),
1492 - );
1493 -
1494 - $schema['properties']['meta'] = $this->meta->get_field_schema();
1495 -
1496 - return $this->add_additional_fields_schema( $schema );
1497 - }
1498 -
1499 - public function get_collection_params() {
1500 - $query_params = parent::get_collection_params();
1501 -
1502 - $query_params['context']['default'] = 'view';
1503 -
1504 - $query_params['exclude'] = array(
1505 - 'description' => __( 'Ensure the result set excludes specific IDs.' ),
1506 - 'type' => 'array',
1507 - 'items' => array(
1508 - 'type' => 'integer',
1509 - ),
1510 - 'default' => array(),
1511 - );
1512 -
1513 - $query_params['include'] = array(
1514 - 'description' => __( 'Limit the result set to specific IDs.' ),
1515 - 'type' => 'array',
1516 - 'items' => array(
1517 - 'type' => 'integer',
1518 - ),
1519 - 'default' => array(),
1520 - );
1521 -
1522 - $query_params['offset'] = array(
1523 - 'description' => __( 'Offset the result set by a specific number of items.' ),
1524 - 'type' => 'integer',
1525 - );
1526 -
1527 - $query_params['order'] = array(
1528 - 'default' => 'asc',
1529 - 'description' => __( 'Sorting attributes in ascending or descending order.' ),
1530 - 'enum' => array( 'asc', 'desc' ),
1531 - 'type' => 'string',
1532 - );
1533 -
1534 - $query_params['orderby'] = array(
1535 - 'default' => 'name',
1536 - 'description' => __( 'Sort collections by the object attribute.' ),
1537 - 'enum' => array(
1538 - 'id',
1539 - 'include',
1540 - 'name',
1541 - 'registered_date',
1542 - 'slug',
1543 - 'include_slugs',
1544 - 'email',
1545 - 'url',
1546 - ),
1547 - 'type' => 'string',
1548 - );
1549 -
1550 - $query_params['slug'] = array(
1551 - 'description' => __( 'Limit result set to users with one or more specific slugs.' ),
1552 - 'type' => 'array',
1553 - 'items' => array(
1554 - 'type' => 'string',
1555 - ),
1556 - );
1557 -
1558 - $query_params['roles'] = array(
1559 - 'description' => __( 'Limit result set to users matching at least one specific role provided. Accepts csv list or single role.' ),
1560 - 'type' => 'array',
1561 - 'items' => array(
1562 - 'type' => 'string',
1563 - ),
1564 - );
1565 -
1566 - $query_params['who'] = array(
1567 - 'description' => __( 'Limit result set to users who are considered authors.' ),
1568 - 'type' => 'string',
1569 - 'enum' => array(
1570 - 'authors',
1571 - ),
1572 - );
1573 -
1574 - /**
1575 - * Filters REST API collection parameters for the users controller.
1576 - *
1577 - * This filter registers the collection parameter, but does not map the
1578 - * collection parameter to an internal WP_User_Query parameter. Use the
1579 - * `rest_user_query` filter to set WP_User_Query arguments.
1580 - *
1581 - * @since 4.7.0
1582 - *
1583 - * @param array $query_params JSON Schema-formatted collection parameters.
1584 - */
1585 - return apply_filters( 'rest_user_collection_params', $query_params );
1586 - }
1587 -}
1 +<?php
2 +
3 +use LearnPress\Models\UserModel;
4 +
5 +/**
6 + * REST API for the user.
7 + *
8 + * @package LearnPress/JWT/RESTAPI
9 + * @author Nhamdv <[email protected]>
10 + */
11 +class LP_Jwt_Users_V1_Controller extends LP_REST_Jwt_Controller {
12 + protected $namespace = 'learnpress/v1';
13 +
14 + protected $rest_base = 'users';
15 +
16 + protected $hierarchical = true;
17 +
18 + protected $meta;
19 +
20 + public function __construct() {
21 + $this->meta = new WP_REST_User_Meta_Fields();
22 + }
23 +
24 + public function register_routes() {
25 + register_rest_route(
26 + $this->namespace,
27 + '/' . $this->rest_base,
28 + array(
29 + array(
30 + 'methods' => WP_REST_Server::READABLE,
31 + 'callback' => array( $this, 'get_items' ),
32 + 'permission_callback' => array( $this, 'get_items_permissions_check' ),
33 + 'args' => $this->get_collection_params(),
34 + ),
35 + 'schema' => array( $this, 'get_public_item_schema' ),
36 + )
37 + );
38 +
39 + register_rest_route(
40 + $this->namespace,
41 + '/' . $this->rest_base . '/(?P<id>[\d]+)',
42 + array(
43 + 'args' => array(
44 + 'id' => array(
45 + 'description' => esc_html__( 'A unique identifier for the resource.', 'learnpress' ),
46 + 'type' => 'integer',
47 + ),
48 + ),
49 + array(
50 + 'methods' => WP_REST_Server::READABLE,
51 + 'callback' => array( $this, 'get_item' ),
52 + 'permission_callback' => array( $this, 'get_item_permissions_check' ),
53 + 'args' => array(
54 + 'context' => $this->get_context_param(
55 + array(
56 + 'default' => 'view',
57 + )
58 + ),
59 + ),
60 + ),
61 + array(
62 + 'methods' => WP_REST_Server::EDITABLE,
63 + 'callback' => array( $this, 'update_item' ),
64 + 'permission_callback' => array( $this, 'update_item_permissions_check' ),
65 + 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
66 + ),
67 + 'schema' => array( $this, 'get_public_item_schema' ),
68 + )
69 + );
70 +
71 + register_rest_route(
72 + $this->namespace,
73 + '/' . $this->rest_base . '/reset-password',
74 + array(
75 + 'methods' => WP_REST_Server::EDITABLE,
76 + 'callback' => array( $this, 'reset_password' ),
77 + 'permission_callback' => '__return_true',
78 + 'args' => array(
79 + 'user_login' => array(
80 + 'description' => esc_html__( 'User or Email login.', 'learnpress' ),
81 + 'type' => 'string',
82 + 'required' => true,
83 + ),
84 + ),
85 + )
86 + );
87 +
88 + register_rest_route(
89 + $this->namespace,
90 + '/' . $this->rest_base . '/change-password',
91 + array(
92 + 'methods' => WP_REST_Server::EDITABLE,
93 + 'callback' => array( $this, 'change_password' ),
94 + 'permission_callback' => array( $this, 'update_item_password_permissions' ),
95 + 'args' => array(
96 + 'old_password' => array(
97 + 'description' => esc_html__( 'Old Password', 'learnpress' ),
98 + 'type' => 'string',
99 + 'required' => true,
100 + ),
101 + 'new_password' => array(
102 + 'description' => esc_html__( 'New Password', 'learnpress' ),
103 + 'type' => 'string',
104 + 'required' => true,
105 + ),
106 + ),
107 + )
108 + );
109 +
110 + register_rest_route(
111 + $this->namespace,
112 + '/' . $this->rest_base . '/delete',
113 + array(
114 + 'methods' => WP_REST_Server::EDITABLE,
115 + 'callback' => array( $this, 'delete_account' ),
116 + 'permission_callback' => array( $this, 'update_item_password_permissions' ),
117 + 'args' => array(
118 + 'id' => array(
119 + 'description' => esc_html__( 'User ID', 'learnpress' ),
120 + 'type' => 'integer',
121 + 'required' => true,
122 + ),
123 + 'password' => array(
124 + 'description' => esc_html__( 'Password', 'learnpress' ),
125 + 'type' => 'string',
126 + 'required' => true,
127 + ),
128 + ),
129 + )
130 + );
131 + }
132 +
133 + public function get_items_permissions_check( $request ) {
134 + return true;
135 + }
136 +
137 + public function get_item_permissions_check( $request ) {
138 + $user = $this->get_user( $request['id'] );
139 +
140 + if ( is_wp_error( $user ) ) {
141 + return $user;
142 + }
143 +
144 + if ( ! is_user_logged_in() ) {
145 + return new WP_Error(
146 + 'rest_forbidden',
147 + __( 'Authentication required to access user information.' ),
148 + array( 'status' => rest_authorization_required_code() )
149 + );
150 + }
151 +
152 + $types = get_post_types( array( 'show_in_rest' => true ), 'names' );
153 +
154 + if ( get_current_user_id() === $user->ID ) {
155 + return true;
156 + } elseif ( ! current_user_can( UserModel::ROLE_ADMINISTRATOR ) ) {
157 + return new WP_Error(
158 + 'rest_user_cannot_view',
159 + __( 'Sorry, you are not allowed to list users.' ),
160 + array( 'status' => rest_authorization_required_code() )
161 + );
162 + }
163 +
164 + return true;
165 + }
166 +
167 + /**
168 + * Checks if a given request has access to update a user.
169 + *
170 + * @since 4.7.0
171 + *
172 + * @param WP_REST_Request $request Full details about the request.
173 + * @return true|WP_Error True if the request has access to update the item, WP_Error object otherwise.
174 + */
175 + public function update_item_permissions_check( $request ) {
176 + $user = $this->get_user( $request['id'] );
177 + if ( is_wp_error( $user ) ) {
178 + return $user;
179 + }
180 +
181 + if ( ! empty( $request['roles'] ) ) {
182 + if ( ! current_user_can( 'promote_user', $user->ID ) ) {
183 + return new WP_Error(
184 + 'rest_cannot_edit_roles',
185 + __( 'Sorry, you are not allowed to edit roles of this user.' ),
186 + array( 'status' => rest_authorization_required_code() )
187 + );
188 + }
189 +
190 + $request_params = array_keys( $request->get_params() );
191 + sort( $request_params );
192 + // If only 'id' and 'roles' are specified (we are only trying to
193 + // edit roles), then only the 'promote_user' cap is required.
194 + if ( array( 'id', 'roles' ) === $request_params ) {
195 + return true;
196 + }
197 + }
198 +
199 + if ( ! current_user_can( 'edit_user', $user->ID ) ) {
200 + return new WP_Error(
201 + 'rest_cannot_edit',
202 + __( 'Sorry, you are not allowed to edit this user.' ),
203 + array( 'status' => rest_authorization_required_code() )
204 + );
205 + }
206 +
207 + return true;
208 + }
209 +
210 + public function update_item_password_permissions( $request ) {
211 + $user = wp_get_current_user();
212 +
213 + if ( ! $user ) {
214 + return new WP_Error(
215 + 'rest_cannot_update',
216 + __( 'Sorry, you are not allowed to update this user.' ),
217 + array( 'status' => rest_authorization_required_code() )
218 + );
219 + }
220 +
221 + if ( ! current_user_can( 'edit_user', $user->ID ) ) {
222 + return new WP_Error(
223 + 'rest_cannot_edit',
224 + __( 'Sorry, you are not allowed to edit this user.' ),
225 + array( 'status' => rest_authorization_required_code() )
226 + );
227 + }
228 +
229 + return true;
230 + }
231 +
232 + /**
233 + * Determines if the current user is allowed to make the desired roles change.
234 + *
235 + * @since 4.7.0
236 + *
237 + * @param int $user_id User ID.
238 + * @param array $roles New user roles.
239 + * @return true|WP_Error True if the current user is allowed to make the role change,
240 + * otherwise a WP_Error object.
241 + */
242 + protected function check_role_update( $user_id, $roles ) {
243 + global $wp_roles;
244 +
245 + foreach ( $roles as $role ) {
246 +
247 + if ( ! isset( $wp_roles->role_objects[ $role ] ) ) {
248 + return new WP_Error(
249 + 'rest_user_invalid_role',
250 + /* translators: %s: Role key. */
251 + sprintf( __( 'The role %s does not exist.' ), $role ),
252 + array( 'status' => 400 )
253 + );
254 + }
255 +
256 + $potential_role = $wp_roles->role_objects[ $role ];
257 +
258 + /*
259 + * Don't let anyone with 'edit_users' (admins) edit their own role to something without it.
260 + * Multisite super admins can freely edit their blog roles -- they possess all caps.
261 + */
262 + if ( ! ( is_multisite()
263 + && current_user_can( 'manage_sites' ) )
264 + && get_current_user_id() === $user_id
265 + && ! $potential_role->has_cap( 'edit_users' )
266 + ) {
267 + return new WP_Error(
268 + 'rest_user_invalid_role',
269 + __( 'Sorry, you are not allowed to give users that role.' ),
270 + array( 'status' => rest_authorization_required_code() )
271 + );
272 + }
273 +
274 + // Include user admin functions to get access to get_editable_roles().
275 + require_once ABSPATH . 'wp-admin/includes/user.php';
276 +
277 + // The new role must be editable by the logged-in user.
278 + $editable_roles = get_editable_roles();
279 +
280 + if ( empty( $editable_roles[ $role ] ) ) {
281 + return new WP_Error(
282 + 'rest_user_invalid_role',
283 + __( 'Sorry, you are not allowed to give users that role.' ),
284 + array( 'status' => 403 )
285 + );
286 + }
287 + }
288 +
289 + return true;
290 + }
291 +
292 + public function reset_password( $request ) {
293 + $user_login = $request['user_login'];
294 + $reset = LP_Forms_Handler::retrieve_password( $user_login );
295 +
296 + if ( is_wp_error( $reset ) ) {
297 + return $reset;
298 + } else {
299 + return rest_ensure_response(
300 + array(
301 + 'code' => 'success',
302 + 'message' => esc_html__( 'A link to reset your password has been emailed to you.', 'learnpress' ),
303 + )
304 + );
305 + }
306 + }
307 +
308 + public function delete_account( $request ) {
309 + $user_id = $request['id'];
310 + $password = $request['password'];
311 +
312 + $user = wp_get_current_user();
313 +
314 + if ( ! $user || $user_id !== $user->ID ) {
315 + return new WP_Error(
316 + 'rest_user_invalid_id',
317 + __( 'Invalid user ID.', 'learnpress' ),
318 + array( 'status' => 400 )
319 + );
320 + }
321 +
322 + if ( ! wp_check_password( $password, $user->data->user_pass, $user->ID ) ) {
323 + return new WP_Error(
324 + 'rest_user_invalid_password',
325 + __( 'Invalid password.', 'learnpress' ),
326 + array( 'status' => 400 )
327 + );
328 + }
329 +
330 + if ( ! function_exists( 'wp_delete_user' ) ) {
331 + require_once ABSPATH . 'wp-admin/includes/user.php';
332 + }
333 +
334 + $delete = wp_delete_user( $user_id );
335 +
336 + if ( is_wp_error( $delete ) ) {
337 + return $delete;
338 + } else {
339 + return rest_ensure_response(
340 + array(
341 + 'code' => 'success',
342 + 'message' => esc_html__( 'Your account has been deleted.', 'learnpress' ),
343 + )
344 + );
345 + }
346 + }
347 +
348 + public function change_password( $request ) {
349 + $old_password = $request['old_password'];
350 + $new_password = $request['new_password'];
351 +
352 + $user = wp_get_current_user();
353 +
354 + if ( ! $user || ! $user->ID || ( empty( $old_password ) || empty( $new_password ) ) ) {
355 + return new WP_Error(
356 + 'rest_user_cannot_change_password',
357 + __( 'Sorry, you are not allowed to change password.' ),
358 + array( 'status' => rest_authorization_required_code() )
359 + );
360 + }
361 +
362 + if ( ! wp_check_password( $old_password, $user->user_pass, $user->ID ) ) {
363 + return new WP_Error(
364 + 'rest_user_incorrect_password',
365 + __( 'Your current password is incorrect.' ),
366 + array( 'status' => 403 )
367 + );
368 + }
369 +
370 + if ( apply_filters( 'learnpress_rest_api_user_change_password', true, $user ) ) {
371 + wp_set_password( $new_password, $user->ID );
372 + } else {
373 + return new WP_Error(
374 + 'rest_user_cannot_change_password',
375 + __( 'Sorry, you are not allowed to change password.' ),
376 + array( 'status' => rest_authorization_required_code() )
377 + );
378 + }
379 +
380 + return rest_ensure_response(
381 + array(
382 + 'code' => 'success',
383 + 'message' => esc_html__( 'Your password has been updated. Please log in again to continue!', 'learnpress' ),
384 + )
385 + );
386 + }
387 +
388 + protected function get_user( $id ) {
389 + $error = new WP_Error(
390 + 'rest_user_invalid_id',
391 + __( 'Invalid user ID.' ),
392 + array( 'status' => 404 )
393 + );
394 +
395 + if ( (int) $id <= 0 ) {
396 + return $error;
397 + }
398 +
399 + $user = get_userdata( (int) $id );
400 + if ( empty( $user ) || ! $user->exists() ) {
401 + return $error;
402 + }
403 +
404 + if ( is_multisite() && ! is_user_member_of_blog( $user->ID ) ) {
405 + return $error;
406 + }
407 +
408 + return $user;
409 + }
410 +
411 + /**
412 + * Updates a single user.
413 + *
414 + * @param WP_REST_Request $request Full details about the request.
415 + * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
416 + */
417 + public function update_item( $request ) {
418 + $user = $this->get_user( $request['id'] );
419 + if ( is_wp_error( $user ) ) {
420 + return $user;
421 + }
422 +
423 + $id = $user->ID;
424 +
425 + if ( ! $user ) {
426 + return new WP_Error(
427 + 'rest_user_invalid_id',
428 + __( 'Invalid user ID.' ),
429 + array( 'status' => 404 )
430 + );
431 + }
432 +
433 + $owner_id = email_exists( $request['email'] );
434 +
435 + if ( $owner_id && $owner_id !== $id ) {
436 + return new WP_Error(
437 + 'rest_user_invalid_email',
438 + __( 'Invalid email address.' ),
439 + array( 'status' => 400 )
440 + );
441 + }
442 +
443 + if ( ! empty( $request['username'] ) && $request['username'] !== $user->user_login ) {
444 + return new WP_Error(
445 + 'rest_user_invalid_argument',
446 + __( "Username isn't editable." ),
447 + array( 'status' => 400 )
448 + );
449 + }
450 +
451 + if ( ! empty( $request['slug'] ) && $request['slug'] !== $user->user_nicename && get_user_by( 'slug', $request['slug'] ) ) {
452 + return new WP_Error(
453 + 'rest_user_invalid_slug',
454 + __( 'Invalid slug.' ),
455 + array( 'status' => 400 )
456 + );
457 + }
458 +
459 + if ( ! empty( $request['roles'] ) ) {
460 + $check_permission = $this->check_role_update( $id, $request['roles'] );
461 +
462 + if ( is_wp_error( $check_permission ) ) {
463 + return $check_permission;
464 + }
465 + }
466 +
467 + $user = $this->prepare_item_for_database( $request );
468 +
469 + // Ensure we're operating on the same user we already checked.
470 + $user->ID = $id;
471 +
472 + $user_id = wp_update_user( wp_slash( (array) $user ) );
473 +
474 + if ( is_wp_error( $user_id ) ) {
475 + return $user_id;
476 + }
477 +
478 + $files = $request->get_file_params();
479 +
480 + if ( ! empty( $files['lp_avatar_file'] ) ) {
481 + $file = $files['lp_avatar_file'];
482 +
483 + if ( ! empty( $file['name'] ) ) {
484 + list($width, $height) = getimagesize( $file['tmp_name'] );
485 +
486 + $upload_size = learn_press_get_avatar_thumb_size();
487 +
488 + if ( $width != $upload_size['width'] || $height != $upload_size['height'] ) {
489 + return new WP_Error(
490 + 'rest_user_invalid_avatar_dimensions',
491 + sprintf( __( 'Invalid avatar dimensions. Please upload a new avatar width size %1$1sx%2$2s' ), $upload_size['width'], $upload_size['height'] ),
492 + array( 'status' => 400 )
493 + );
494 + }
495 +
496 + $data = LP_WP_Filesystem::instance()->file_get_contents( $file['tmp_name'] );
497 + $base64 = base64_encode( $data );
498 +
499 + $controller = new LP_REST_Profile_Controller();
500 +
501 + $request->set_param( 'file', $base64 );
502 +
503 + $uploaded_avatar = $controller->upload_avatar( $request );
504 + }
505 + }
506 +
507 + if ( ! empty( $request['avatar_url'] ) ) {
508 + $controller = new LP_REST_Profile_Controller();
509 +
510 + $request->set_param( 'file', $request['avatar_url'] );
511 +
512 + $uploaded_avatar = $controller->upload_avatar( $request );
513 + }
514 +
515 + $user = get_user_by( 'id', $user_id );
516 +
517 + do_action( 'lp_rest_insert_user', $user, $request, false );
518 +
519 + if ( ! empty( $request['roles'] ) ) {
520 + array_map( array( $user, 'add_role' ), $request['roles'] );
521 + }
522 +
523 + $schema = $this->get_item_schema();
524 +
525 + if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) {
526 + $meta_update = $this->meta->update_value( $request['meta'], $user_id );
527 +
528 + if ( is_wp_error( $meta_update ) ) {
529 + return $meta_update;
530 + }
531 + }
532 +
533 + $user = get_user_by( 'id', $user_id );
534 + $fields_update = $this->update_additional_fields_for_object( $user, $request );
535 +
536 + if ( is_wp_error( $fields_update ) ) {
537 + return $fields_update;
538 + }
539 +
540 + $request->set_param( 'context', 'edit' );
541 +
542 + do_action( 'lp_rest_after_insert_user', $user, $request, false );
543 +
544 + $response = $this->prepare_item_for_response( $user, $request );
545 + $response = rest_ensure_response( $response );
546 +
547 + return $response;
548 + }
549 +
550 + /**
551 + * Prepares a single user for creation or update.
552 + *
553 + * @param WP_REST_Request $request Request object.
554 + * @return object User object.
555 + */
556 + protected function prepare_item_for_database( $request ) {
557 + $prepared_user = new stdClass();
558 +
559 + $schema = $this->get_item_schema();
560 +
561 + // Required arguments.
562 + if ( isset( $request['email'] ) && ! empty( $schema['properties']['email'] ) ) {
563 + $prepared_user->user_email = $request['email'];
564 + }
565 +
566 + if ( isset( $request['username'] ) && ! empty( $schema['properties']['username'] ) ) {
567 + $prepared_user->user_login = $request['username'];
568 + }
569 +
570 + if ( isset( $request['password'] ) && ! empty( $schema['properties']['password'] ) ) {
571 + $prepared_user->user_pass = $request['password'];
572 + }
573 +
574 + // Optional arguments.
575 + if ( isset( $request['id'] ) ) {
576 + $prepared_user->ID = absint( $request['id'] );
577 + }
578 +
579 + if ( isset( $request['name'] ) && ! empty( $schema['properties']['name'] ) ) {
580 + $prepared_user->display_name = $request['name'];
581 + }
582 +
583 + if ( isset( $request['first_name'] ) && ! empty( $schema['properties']['first_name'] ) ) {
584 + $prepared_user->first_name = $request['first_name'];
585 + }
586 +
587 + if ( isset( $request['last_name'] ) && ! empty( $schema['properties']['last_name'] ) ) {
588 + $prepared_user->last_name = $request['last_name'];
589 + }
590 +
591 + if ( isset( $request['nickname'] ) && ! empty( $schema['properties']['nickname'] ) ) {
592 + $prepared_user->nickname = $request['nickname'];
593 + }
594 +
595 + if ( isset( $request['slug'] ) && ! empty( $schema['properties']['slug'] ) ) {
596 + $prepared_user->user_nicename = $request['slug'];
597 + }
598 +
599 + if ( isset( $request['description'] ) && ! empty( $schema['properties']['description'] ) ) {
600 + $prepared_user->description = $request['description'];
601 + }
602 +
603 + if ( isset( $request['url'] ) && ! empty( $schema['properties']['url'] ) ) {
604 + $prepared_user->user_url = $request['url'];
605 + }
606 +
607 + if ( isset( $request['locale'] ) && ! empty( $schema['properties']['locale'] ) ) {
608 + $prepared_user->locale = $request['locale'];
609 + }
610 +
611 + // Setting roles will be handled outside of this function.
612 + if ( isset( $request['roles'] ) ) {
613 + $prepared_user->role = false;
614 + }
615 +
616 + /**
617 + * Filters user data before insertion via the REST API.
618 + *
619 + * @param object $prepared_user User object.
620 + * @param WP_REST_Request $request Request object.
621 + */
622 + return apply_filters( 'lp_rest_pre_insert_user', $prepared_user, $request );
623 + }
624 +
625 + public function get_overview_tab_contents( $user ) {
626 + $output = array();
627 + $statistic = LP_Profile::instance( $user->get_id )->get_statistic_info();
628 +
629 + $output['statistic'] = array_map( 'absint', $statistic );
630 +
631 + $featured_query = new LP_Course_Query(
632 + array(
633 + 'paginate' => false,
634 + 'featured' => 'yes',
635 + 'return' => 'ids',
636 + 'author' => $user->ID,
637 + )
638 + );
639 +
640 + $output['featured'] = $featured_query->get_courses();
641 +
642 + $latest_query = new LP_Course_Query(
643 + array(
644 + 'paginate' => false,
645 + 'return' => 'ids',
646 + 'author' => $user->get_id(),
647 + 'limit' => '-1',
648 + )
649 + );
650 +
651 + $output['latest'] = $latest_query->get_courses();
652 +
653 + return $output;
654 + }
655 +
656 + public function get_course_tab_contents( $user, $request ) {
657 + $output = array(
658 + 'enrolled' => array(),
659 + 'created' => array(),
660 + );
661 +
662 + $profile = learn_press_get_profile( $user->get_id() );
663 + $filters_enrolled = array(
664 + 'all' => 'all',
665 + 'finished' => 'finished',
666 + 'passed' => 'passed',
667 + 'failed' => 'failed',
668 + 'in-progress' => 'in-progress',
669 + );
670 +
671 + if ( method_exists( $profile, 'query_courses' ) ) {
672 + foreach ( $filters_enrolled as $key => $filter ) {
673 + $query_enrolled = $profile->query_courses(
674 + 'purchased',
675 + array(
676 + 'status' => $filter,
677 + 'limit' => $request['per_page'] ?? '100',
678 + 'paged' => $request['paged'] ?? 1,
679 + )
680 + );
681 +
682 + if ( empty( $query_enrolled->get_items() ) ) {
683 + continue;
684 + }
685 +
686 + $items = $query_enrolled->get_items();
687 + $enrolled_ids = array();
688 + foreach ( $items as $enrolled_item ) {
689 + $course_data = $user->get_course_data( $enrolled_item );
690 +
691 + if ( $course_data ) {
692 + $post = get_post( $enrolled_item );
693 +
694 + $enrolled_ids[] = array(
695 + 'id' => $enrolled_item ?? '',
696 + 'title' => $post->post_title,
697 + 'graduation' => ! empty( $course_data->get_graduation() ) ? $course_data->get_graduation() : '',
698 + 'status' => ! empty( $course_data->get_status() ) ? $course_data->get_status() : '',
699 + 'start_time' => lp_jwt_prepare_date_response( $course_data->get_start_time() ? $course_data->get_start_time()->toSql() : '' ),
700 + 'end_time' => lp_jwt_prepare_date_response( $course_data->get_end_time() ? $course_data->get_end_time()->toSql() : '' ),
701 + 'expiration' => lp_jwt_prepare_date_response( $course_data->get_expiration_time() ? $course_data->get_expiration_time()->toSql() : '' ),
702 + 'results' => $course_data->calculate_course_results(),
703 + );
704 + }
705 + }
706 +
707 + $output['enrolled'][ $key ] = $enrolled_ids;
708 + }
709 + }
710 +
711 + $filters_created = array(
712 + 'all' => '',
713 + 'publish' => 'publish',
714 + 'pending' => 'pending',
715 + );
716 +
717 + if ( method_exists( $profile, 'query_courses' ) ) {
718 + foreach ( $filters_created as $created_key => $filter ) {
719 + $query_created = $profile->query_courses(
720 + 'own',
721 + array(
722 + 'status' => $filter,
723 + 'limit' => $request['per_page'] ?? '100',
724 + 'paged' => $request['paged'] ?? 1,
725 + )
726 + );
727 +
728 + $created_ids = array();
729 + if ( ! empty( $query_created->get_items() ) ) {
730 + foreach ( $query_created->get_items() as $created_item ) {
731 + $created_ids[] = $created_item;
732 + }
733 + }
734 +
735 + $output['created'][ $created_key ] = array_map( 'absint', $created_ids );
736 + }
737 + }
738 +
739 + return $output;
740 + }
741 +
742 + /**
743 + * Get Profile Quiz Tab content
744 + *
745 + * @param [type] $request
746 + * @return void
747 + *
748 + * @author Nhamdv <[email protected]>
749 + */
750 + public function get_quiz_tab_contents( $user, $request ) {
751 + $output = array();
752 +
753 + $user_profile = learn_press_get_user( $request['id'] );
754 + $filters = array(
755 + 'all' => '',
756 + 'finished' => 'completed',
757 + 'passed' => 'passed',
758 + 'failed' => 'failed',
759 + 'in-progress' => 'in-progress',
760 + );
761 +
762 + if ( method_exists( $user_profile, 'get_user_quizzes' ) ) {
763 + foreach ( $filters as $key => $quiz_filter ) {
764 + $filter = new LP_User_Items_Filter();
765 + $filter->user_id = $request['id'];
766 + $filter->limit = 100;
767 + $filter->status = $quiz_filter === 'complete' ? 'complete' : '';
768 + $filter->graduation = $quiz_filter !== 'complete' ? $quiz_filter : '';
769 + $query = $user_profile->get_user_quizzes( $filter );
770 +
771 + $ids = array();
772 + if ( ! empty( $query->get_items() ) ) {
773 + foreach ( $query->get_items() as $item ) {
774 + $ids[] = array(
775 + 'id' => $item->get_id(),
776 + 'result' => $item->get_percent_result() ?? '',
777 + 'graduation' => $item->get_graduation() ?? '',
778 + 'start_time' => $item->get_start_time() ? lp_jwt_prepare_date_response( $item->get_start_time()->toSql( false ) ) : '',
779 + 'end_time' => $item->get_end_time() ? lp_jwt_prepare_date_response( $item->get_end_time()->toSql( false ) ) : '',
780 + 'data' => $filter !== 'in-progress' ? $item->calculate_quiz_result() : array(),
781 + 'attempt' => $filter !== 'in-progress' ? $item->get_attempts() : array(),
782 + );
783 + }
784 + }
785 +
786 + $output[ $key ] = $ids;
787 + }
788 + }
789 +
790 + return $output;
791 + }
792 +
793 + /**
794 + * Get order by user id
795 + *
796 + * @param array $request [id: user ID]
797 + * @return array
798 + *
799 + * @author Nhamdv <[email protected]>
800 + */
801 + public function get_order_content_tab( $user, $request ) {
802 + $output = array();
803 +
804 + $profile = learn_press_get_profile( $request['id'] );
805 +
806 + if ( method_exists( $profile, 'query_orders' ) ) {
807 + $query_orders = $profile->query_orders( array( 'fields' => 'ids' ) );
808 + if ( ! empty( $query_orders->get_items() ) ) {
809 + foreach ( $query_orders->get_items() as $order_id ) {
810 + $order = learn_press_get_order( $order_id );
811 +
812 + $output[ $order_id ] = array(
813 + 'order_key' => $order->get_order_number() ?? '',
814 + 'total' => $order->get_total(),
815 + 'currency' => $order->get_currency(),
816 + 'status' => $order->get_status(),
817 + 'date' => $order->get_order_date( 'timestamp' ) ? lp_jwt_prepare_date_response( get_date_from_gmt( gmdate( 'Y-m-d H:i:s', $order->get_order_date( 'timestamp' ) ), 'Y-m-d H:i:s' ) ) : '',
818 + );
819 + }
820 + }
821 + }
822 +
823 + return $output;
824 + }
825 +
826 + /**
827 + * Retrieves a single user.
828 + *
829 + * @since 4.7.0
830 + *
831 + * @param WP_REST_Request $request Full details about the request.
832 + * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
833 + */
834 + public function get_item( $request ) {
835 + $user = $this->get_user( $request['id'] );
836 +
837 + if ( is_wp_error( $user ) ) {
838 + return $user;
839 + }
840 +
841 + $user = $this->prepare_item_for_response( $user, $request );
842 + $response = rest_ensure_response( $user );
843 +
844 + return $response;
845 + }
846 +
847 + /**
848 + * Retrieves all users.
849 + *
850 + * @since 4.7.0
851 + *
852 + * @param WP_REST_Request $request Full details about the request.
853 + * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
854 + */
855 + public function get_items( $request ) {
856 + // Fixed security, with request ?context=edit
857 + if ( isset( $_REQUEST['context'] ) ) {
858 + die();
859 + }
860 +
861 + // Retrieve the list of registered collection query parameters.
862 + $registered = $this->get_collection_params();
863 +
864 + /*
865 + * This array defines mappings between public API query parameters whose
866 + * values are accepted as-passed, and their internal WP_Query parameter
867 + * name equivalents (some are the same). Only values which are also
868 + * present in $registered will be set.
869 + */
870 + $parameter_mappings = array(
871 + 'exclude' => 'exclude',
872 + 'include' => 'include',
873 + 'order' => 'order',
874 + 'per_page' => 'number',
875 + 'search' => 'search',
876 + 'roles' => 'role__in',
877 + 'slug' => 'nicename__in',
878 + );
879 +
880 + $roles = $request->get_param( 'roles' );
881 + if ( ! empty( $roles ) && $roles == [ UserModel::ROLE_ADMINISTRATOR ] ) {
882 + return new WP_Error(
883 + 'rest_forbidden',
884 + __( 'You are not allowed.' ),
885 + array( 'status' => rest_authorization_required_code() )
886 + );
887 + }
888 +
889 + // Always only get instructors and administrators.
890 + $request['roles'] = [ UserModel::ROLE_INSTRUCTOR, UserModel::ROLE_ADMINISTRATOR ];
891 +
892 + $prepared_args = array();
893 +
894 + /*
895 + * For each known parameter which is both registered and present in the request,
896 + * set the parameter's value on the query $prepared_args.
897 + */
898 + foreach ( $parameter_mappings as $api_param => $wp_param ) {
899 + if ( isset( $registered[ $api_param ], $request[ $api_param ] ) ) {
900 + $prepared_args[ $wp_param ] = $request[ $api_param ];
901 + }
902 + }
903 +
904 + if ( isset( $registered['offset'] ) && ! empty( $request['offset'] ) ) {
905 + $prepared_args['offset'] = $request['offset'];
906 + } else {
907 + $prepared_args['offset'] = ( $request['page'] - 1 ) * $prepared_args['number'];
908 + }
909 +
910 + if ( isset( $registered['orderby'] ) ) {
911 + $orderby_possibles = array(
912 + 'id' => 'ID',
913 + 'include' => 'include',
914 + 'name' => 'display_name',
915 + 'registered_date' => 'registered',
916 + 'slug' => 'user_nicename',
917 + 'include_slugs' => 'nicename__in',
918 + 'email' => 'user_email',
919 + 'url' => 'user_url',
920 + );
921 + $prepared_args['orderby'] = $orderby_possibles[ $request['orderby'] ];
922 + }
923 +
924 + if ( isset( $registered['who'] ) && ! empty( $request['who'] ) && 'authors' === $request['who'] ) {
925 + $prepared_args['who'] = 'authors';
926 + }
927 +
928 + if ( ! empty( $prepared_args['search'] ) ) {
929 + $prepared_args['search'] = '*' . $prepared_args['search'] . '*';
930 + }
931 + /**
932 + * Filters WP_User_Query arguments when querying users via the REST API.
933 + *
934 + * @link https://developer.wordpress.org/reference/classes/wp_user_query/
935 + *
936 + * @since 4.7.0
937 + *
938 + * @param array $prepared_args Array of arguments for WP_User_Query.
939 + * @param WP_REST_Request $request The REST API request.
940 + */
941 + $prepared_args = apply_filters( 'rest_user_query', $prepared_args, $request );
942 +
943 + $users = array();
944 + $lp_cache = new LP_Cache();
945 + $key_cache_list_instructors = 'lp_get_instructors';
946 +
947 + // Check cache with cache get instructors.
948 + if ( isset( $prepared_args['role__in'] ) ) {
949 + $users = $lp_cache->get_cache( $key_cache_list_instructors );
950 + $total_users = $lp_cache->get_cache( $key_cache_list_instructors . '/total' );
951 + }
952 +
953 + if ( $users === false ) {
954 + // Query max 10 instructors only.
955 + $prepared_args['number'] = 10;
956 +
957 + $query = new WP_User_Query( $prepared_args );
958 + $users_result = $query->get_results();
959 + $total_users = $query->get_total();
960 +
961 + foreach ( $users_result as $user ) {
962 + $data = $this->prepare_item_for_response( $user, $request );
963 +
964 + $user = $this->prepare_response_for_collection( $data );
965 + unset( $user['custom_register'] );
966 + unset( $user['is_super_admin'] );
967 + $users[] = $user;
968 + }
969 +
970 + // Set cache with cache get instructors.
971 + $lp_cache->set_cache( $key_cache_list_instructors, $users );
972 + $lp_cache->set_cache( $key_cache_list_instructors . '/total', $total_users );
973 + }
974 +
975 + $response = rest_ensure_response( $users );
976 +
977 + // Store pagination values for headers then unset for count query.
978 + $per_page = (int) $prepared_args['number'];
979 + $page = ceil( ( ( (int) $prepared_args['offset'] ) / $per_page ) + 1 );
980 +
981 + $prepared_args['fields'] = 'ID';
982 +
983 + if ( $total_users < 1 ) {
984 + // Out-of-bounds, run the query again without LIMIT for total count.
985 + unset( $prepared_args['number'], $prepared_args['offset'] );
986 + $count_query = new WP_User_Query( $prepared_args );
987 + $total_users = $count_query->get_total();
988 + }
989 +
990 + $response->header( 'X-WP-Total', (int) $total_users );
991 +
992 + $max_pages = ceil( $total_users / $per_page );
993 +
994 + $response->header( 'X-WP-TotalPages', (int) $max_pages );
995 +
996 + $base = add_query_arg( urlencode_deep( $request->get_query_params() ), rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ) );
997 + if ( $page > 1 ) {
998 + $prev_page = $page - 1;
999 +
1000 + if ( $prev_page > $max_pages ) {
1001 + $prev_page = $max_pages;
1002 + }
1003 +
1004 + $prev_link = add_query_arg( 'page', $prev_page, $base );
1005 + $response->link_header( 'prev', $prev_link );
1006 + }
1007 + if ( $max_pages > $page ) {
1008 + $next_page = $page + 1;
1009 + $next_link = add_query_arg( 'page', $next_page, $base );
1010 +
1011 + $response->link_header( 'next', $next_link );
1012 + }
1013 +
1014 + return $response;
1015 + }
1016 +
1017 + /**
1018 + * Prepares a single user output for response.
1019 + *
1020 + * @since 4.7.0
1021 + *
1022 + * @param WP_User $user User object.
1023 + * @param WP_REST_Request $request Request object.
1024 + * @return WP_REST_Response Response object.
1025 + */
1026 + public function prepare_item_for_response( $user, $request ) {
1027 + $context = ! empty( $request['context'] ) ? $request['context'] : 'embed';
1028 + $data = $this->get_users_data( $user, $context, $request );
1029 +
1030 + $data = $this->add_additional_fields_to_object( $data, $request );
1031 + $data = $this->filter_response_by_context( $data, $context );
1032 +
1033 + // Wrap the data in a response object.
1034 + $response = rest_ensure_response( $data );
1035 +
1036 + $response->add_links( $this->prepare_links( $user ) );
1037 +
1038 + return apply_filters( 'lp_rest_prepare_user', $response, $user, $request );
1039 + }
1040 +
1041 + public function get_users_data( $user, $context = 'view' ) {
1042 + $request = func_num_args() >= 2 ? func_get_arg( 2 ) : new WP_REST_Request( '', '', array( 'context' => $context ) );
1043 + $fields = $this->get_fields_for_response( $request );
1044 + $data = array();
1045 +
1046 + foreach ( $fields as $field ) {
1047 + switch ( $field ) {
1048 + case 'id':
1049 + $data['id'] = $user->ID;
1050 + break;
1051 + case 'username':
1052 + if ( current_user_can( 'list_users' ) || current_user_can( 'edit_user', $user->ID ) ) {
1053 + $data['username'] = $user->user_login;
1054 + }
1055 + break;
1056 + case 'name':
1057 + $data['name'] = $user->display_name;
1058 + break;
1059 + case 'first_name':
1060 + $data['first_name'] = $user->first_name;
1061 + break;
1062 + case 'last_name':
1063 + $data['last_name'] = $user->last_name;
1064 + break;
1065 + case 'email':
1066 + if ( current_user_can( 'list_users' ) || current_user_can( 'edit_user', $user->ID ) ) {
1067 + $data['email'] = $user->user_email;
1068 + }
1069 + break;
1070 + case 'url':
1071 + $data['url'] = $user->user_url;
1072 + break;
1073 + case 'description':
1074 + $data['description'] = $user->description;
1075 + break;
1076 + case 'link':
1077 + $data['link'] = get_author_posts_url( $user->ID, $user->user_nicename );
1078 + break;
1079 + case 'locale':
1080 + $data['locale'] = get_user_locale( $user );
1081 + break;
1082 + case 'nickname':
1083 + $data['nickname'] = $user->nickname;
1084 + break;
1085 + case 'slug':
1086 + $data['slug'] = $user->user_nicename;
1087 + break;
1088 + case 'roles':
1089 + $data['roles'] = array_values( $user->roles );
1090 + break;
1091 + case 'registered_date':
1092 + $data['registered_date'] = gmdate( 'c', strtotime( $user->user_registered ) );
1093 + break;
1094 + case 'capabilities':
1095 + $data['capabilities'] = (object) $user->allcaps;
1096 + break;
1097 + case 'extra_capabilities':
1098 + $data['extra_capabilities'] = (object) $user->caps;
1099 + break;
1100 + case 'avatar_url':
1101 + $data['avatar_url'] = $this->get_profile_avatar( $user->ID );
1102 + break;
1103 + case 'avatar_size':
1104 + $data['avatar_size']['width'] = learn_press_get_avatar_thumb_size()['width'];
1105 + $data['avatar_size']['height'] = learn_press_get_avatar_thumb_size()['height'];
1106 + break;
1107 + case 'instructor_data':
1108 + // $data['instructor_data'] = $this->get_instructor_data( $user->ID );
1109 + $data['instructor_data'] = LP_Profile::instance( $user->ID )->get_statistic_info();
1110 + break;
1111 + case 'meta':
1112 + $data['meta'] = $this->meta->get_value( $user->ID, $request );
1113 + break;
1114 + case 'tabs':
1115 + $data['tabs'] = $this->get_lp_data_tabs( $user, $request );
1116 + break;
1117 + case 'custom_register':
1118 + $data['custom_register'] = $this->custom_register( $user );
1119 + break;
1120 + case 'social':
1121 + $data['social'] = $this->get_social_data( $user->ID );
1122 + break;
1123 + }
1124 + }
1125 +
1126 + return $data;
1127 + }
1128 +
1129 + public function get_social_data( $user_id ) {
1130 + return learn_press_get_user_extra_profile_info( $user_id );
1131 + }
1132 +
1133 + /**
1134 + * @since 4.1.4
1135 + * @version 1.0.1
1136 + */
1137 + public function get_profile_avatar( $user_id ): string {
1138 + $user = learn_press_get_user( $user_id );
1139 +
1140 + return $user->get_profile_avatar_url();
1141 + }
1142 +
1143 + /**
1144 + * @editor tungnx
1145 + * @deprecated 4.1.6
1146 + */
1147 + /*
1148 + public function get_instructor_data( $user_id ) {
1149 + $profile = learn_press_get_profile( $user_id );
1150 +
1151 + $output = array();
1152 +
1153 + if ( is_wp_error( $profile ) ) {
1154 + return $output;
1155 + }
1156 +
1157 + $query = $profile->query_courses( 'purchased' );
1158 + $counts = $query['counts'];
1159 +
1160 + $output = array(
1161 + 'enrolled_courses' => isset( $counts['all'] ) ? absint( $counts['all'] ) : 0,
1162 + 'completed_courses' => isset( $counts['finished'] ) ? absint( $counts['finished'] ) : 0,
1163 + 'courses' => absint( count_user_posts( $user_id, LP_COURSE_CPT ) ),
1164 + 'students' => absint( learn_press_count_instructor_users( $user_id ) ),
1165 + );
1166 +
1167 + return $output;
1168 + }*/
1169 +
1170 + /**
1171 + * Get data tabs.
1172 + *
1173 + * @param $user
1174 + * @param $request
1175 + *
1176 + * @return array
1177 + */
1178 + public function get_lp_data_tabs( $user, $request ): array {
1179 + $output = array();
1180 +
1181 + if ( get_current_user_id() === $user->ID || current_user_can( 'list_users' ) ) {
1182 + if ( function_exists( 'learn_press_get_user_profile_tabs' ) ) {
1183 + $tabs = learn_press_get_user_profile_tabs();
1184 +
1185 + $content = array(
1186 + 'overview' => $this->get_overview_tab_contents( $user ),
1187 + 'courses' => $this->get_course_tab_contents( $user, $request ),
1188 + 'quizzes' => $this->get_quiz_tab_contents( $user, $request ),
1189 + 'orders' => $this->get_order_content_tab( $user, $request ),
1190 + );
1191 +
1192 + /**
1193 + * @var LP_Profile_Tab $tab
1194 + */
1195 + foreach ( $tabs->get() as $key => $tab ) {
1196 + $output[ $key ] = array(
1197 + 'title' => $tab->get( 'title' ) ?? '',
1198 + 'slug' => $tab->get( 'slug' ) ?? '',
1199 + 'priority' => $tab->get( 'priority' ) ?? '',
1200 + 'icon' => $tab->get( 'icon' ) ?? '',
1201 + 'content' => $content[ $key ] ?? '',
1202 + );
1203 +
1204 + if ( ! empty( $tab->get( 'sections' ) ) ) {
1205 + foreach ( $tab->get( 'sections' ) as $section_key => $section ) {
1206 + $output[ $key ]['section'][ $section_key ] = array(
1207 + 'title' => $section['title'] ?? '',
1208 + 'slug' => $section['slug'] ?? '',
1209 + 'priority' => $section['priority'] ?? '',
1210 + );
1211 + }
1212 + }
1213 + }
1214 + }
1215 + }
1216 +
1217 + return $output;
1218 + }
1219 +
1220 + /**
1221 + * Display register cutom form in LearnPress Setting
1222 + *
1223 + * @param object $user
1224 + * @return array
1225 + */
1226 + public function custom_register( $user ) {
1227 + $output = array();
1228 +
1229 + if ( function_exists( 'lp_get_user_custom_register_fields' ) ) {
1230 + $custom_fields = LP_Profile::get_register_fields_custom();
1231 + $custom_profile = lp_get_user_custom_register_fields( $user->ID );
1232 +
1233 + if ( $custom_fields ) {
1234 + foreach ( $custom_fields as $field ) {
1235 + $value = $field['id'];
1236 + $output[ $value ] = array(
1237 + 'title' => $field['name'] ?? '',
1238 + 'type' => $field['type'] ?? '',
1239 + 'required' => $field['required'] ?? 'no',
1240 + 'value' => $custom_profile[ $value ] ?? '',
1241 + );
1242 + }
1243 + }
1244 + }
1245 +
1246 + return $output;
1247 + }
1248 +
1249 + /**
1250 + * Prepares links for the user request.
1251 + *
1252 + * @since 4.7.0
1253 + *
1254 + * @param WP_User $user User object.
1255 + * @return array Links for the given user.
1256 + */
1257 + protected function prepare_links( $user ) {
1258 + $links = array(
1259 + 'self' => array(
1260 + 'href' => rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $user->ID ) ),
1261 + ),
1262 + 'collection' => array(
1263 + 'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ),
1264 + ),
1265 + );
1266 +
1267 + return $links;
1268 + }
1269 +
1270 + public function check_username( $value, $request, $param ) {
1271 + $username = (string) $value;
1272 +
1273 + if ( ! validate_username( $username ) ) {
1274 + return new WP_Error(
1275 + 'rest_user_invalid_username',
1276 + __( 'This username is invalid because it uses illegal characters. Please enter a valid username.' ),
1277 + array( 'status' => 400 )
1278 + );
1279 + }
1280 +
1281 + /** This filter is documented in wp-includes/user.php */
1282 + $illegal_logins = (array) apply_filters( 'illegal_user_logins', array() );
1283 +
1284 + if ( in_array( strtolower( $username ), array_map( 'strtolower', $illegal_logins ), true ) ) {
1285 + return new WP_Error(
1286 + 'rest_user_invalid_username',
1287 + __( 'Sorry, that username is not allowed.' ),
1288 + array( 'status' => 400 )
1289 + );
1290 + }
1291 +
1292 + return $username;
1293 + }
1294 +
1295 + /**
1296 + * Check a user password for the REST API.
1297 + *
1298 + * Performs a couple of checks like edit_user() in wp-admin/includes/user.php.
1299 + *
1300 + * @since 4.7.0
1301 + *
1302 + * @param string $value The password submitted in the request.
1303 + * @param WP_REST_Request $request Full details about the request.
1304 + * @param string $param The parameter name.
1305 + * @return string|WP_Error The sanitized password, if valid, otherwise an error.
1306 + */
1307 + public function check_user_password( $value, $request, $param ) {
1308 + $password = (string) $value;
1309 +
1310 + if ( empty( $password ) ) {
1311 + return new WP_Error(
1312 + 'rest_user_invalid_password',
1313 + __( 'Passwords cannot be empty.' ),
1314 + array( 'status' => 400 )
1315 + );
1316 + }
1317 +
1318 + if ( false !== strpos( $password, '\\' ) ) {
1319 + return new WP_Error(
1320 + 'rest_user_invalid_password',
1321 + sprintf(
1322 + /* translators: %s: The '\' character. */
1323 + __( 'Passwords cannot contain the "%s" character.' ),
1324 + '\\'
1325 + ),
1326 + array( 'status' => 400 )
1327 + );
1328 + }
1329 +
1330 + return $password;
1331 + }
1332 +
1333 + public function get_item_schema() {
1334 + $schema = array(
1335 + '$schema' => 'http://json-schema.org/draft-04/schema#',
1336 + 'title' => 'user',
1337 + 'type' => 'object',
1338 + 'properties' => array(
1339 + 'id' => array(
1340 + 'description' => __( 'Unique identifier for the user.' ),
1341 + 'type' => 'integer',
1342 + 'context' => array( 'embed', 'view', 'edit' ),
1343 + 'readonly' => true,
1344 + ),
1345 + 'username' => array(
1346 + 'description' => __( 'Login name for the user.' ),
1347 + 'type' => 'string',
1348 + 'context' => array( 'view', 'edit' ),
1349 + 'required' => true,
1350 + 'arg_options' => array(
1351 + 'sanitize_callback' => array( $this, 'check_username' ),
1352 + ),
1353 + ),
1354 + 'name' => array(
1355 + 'description' => __( 'Display name for the user.' ),
1356 + 'type' => 'string',
1357 + 'context' => array( 'embed', 'view', 'edit' ),
1358 + 'arg_options' => array(
1359 + 'sanitize_callback' => 'sanitize_text_field',
1360 + ),
1361 + ),
1362 + 'first_name' => array(
1363 + 'description' => __( 'First name for the user.' ),
1364 + 'type' => 'string',
1365 + 'context' => array( 'view', 'edit' ),
1366 + 'arg_options' => array(
1367 + 'sanitize_callback' => 'sanitize_text_field',
1368 + ),
1369 + ),
1370 + 'last_name' => array(
1371 + 'description' => __( 'Last name for the user.' ),
1372 + 'type' => 'string',
1373 + 'context' => array( 'view', 'edit' ),
1374 + 'arg_options' => array(
1375 + 'sanitize_callback' => 'sanitize_text_field',
1376 + ),
1377 + ),
1378 + 'email' => array(
1379 + 'description' => __( 'The email address for the user.' ),
1380 + 'type' => 'string',
1381 + 'format' => 'email',
1382 + 'context' => array( 'view', 'edit' ),
1383 + 'required' => true,
1384 + ),
1385 + 'url' => array(
1386 + 'description' => __( 'URL of the user.' ),
1387 + 'type' => 'string',
1388 + 'format' => 'uri',
1389 + 'context' => array( 'embed', 'view', 'edit' ),
1390 + ),
1391 + 'description' => array(
1392 + 'description' => __( 'Description of the user.' ),
1393 + 'type' => 'string',
1394 + 'context' => array( 'embed', 'view', 'edit' ),
1395 + ),
1396 + 'link' => array(
1397 + 'description' => __( 'Author URL of the user.' ),
1398 + 'type' => 'string',
1399 + 'format' => 'uri',
1400 + 'context' => array( 'embed', 'view', 'edit' ),
1401 + 'readonly' => true,
1402 + ),
1403 + 'locale' => array(
1404 + 'description' => __( 'Locale for the user.' ),
1405 + 'type' => 'string',
1406 + 'enum' => array_merge( array( '', 'en_US' ), get_available_languages() ),
1407 + 'context' => array( 'edit' ),
1408 + ),
1409 + 'nickname' => array(
1410 + 'description' => __( 'The nickname for the user.' ),
1411 + 'type' => 'string',
1412 + 'context' => array( 'view', 'edit' ),
1413 + 'arg_options' => array(
1414 + 'sanitize_callback' => 'sanitize_text_field',
1415 + ),
1416 + ),
1417 + 'slug' => array(
1418 + 'description' => __( 'An alphanumeric identifier for the user.' ),
1419 + 'type' => 'string',
1420 + 'context' => array( 'embed', 'view', 'edit' ),
1421 + 'arg_options' => array(
1422 + 'sanitize_callback' => array( $this, 'sanitize_slug' ),
1423 + ),
1424 + ),
1425 + 'registered_date' => array(
1426 + 'description' => __( 'Registration date for the user.' ),
1427 + 'type' => 'string',
1428 + 'format' => 'date-time',
1429 + 'context' => array( 'edit' ),
1430 + 'readonly' => true,
1431 + ),
1432 + 'roles' => array(
1433 + 'description' => __( 'Roles assigned to the user.' ),
1434 + 'type' => 'array',
1435 + 'items' => array(
1436 + 'type' => 'string',
1437 + ),
1438 + 'context' => array( 'edit' ),
1439 + ),
1440 + 'password' => array(
1441 + 'description' => __( 'Password for the user (never included).' ),
1442 + 'type' => 'string',
1443 + 'context' => array(), // Password is never displayed.
1444 + 'required' => true,
1445 + 'arg_options' => array(
1446 + 'sanitize_callback' => array( $this, 'check_user_password' ),
1447 + ),
1448 + ),
1449 + 'capabilities' => array(
1450 + 'description' => __( 'All capabilities assigned to the user.' ),
1451 + 'type' => 'object',
1452 + 'context' => array( 'edit' ),
1453 + 'readonly' => true,
1454 + ),
1455 + 'extra_capabilities' => array(
1456 + 'description' => __( 'Any extra capabilities assigned to the user.' ),
1457 + 'type' => 'object',
1458 + 'context' => array( 'edit' ),
1459 + 'readonly' => true,
1460 + ),
1461 + 'tabs' => array(
1462 + 'description' => __( 'Get all items in user like course, lesson, quiz...' ),
1463 + 'type' => 'array',
1464 + 'context' => array( 'view' ),
1465 + ),
1466 + 'avatar_url' => array(
1467 + 'description' => __( 'URL avatar' ),
1468 + 'type' => 'string',
1469 + 'context' => array( 'view', 'edit' ),
1470 + ),
1471 + 'avatar_size' => array(
1472 + 'description' => __( 'URL avatar size' ),
1473 + 'type' => 'array',
1474 + 'context' => array( 'view' ),
1475 + ),
1476 + 'instructor_data' => array(
1477 + 'description' => __( 'Instructor data' ),
1478 + 'type' => 'array',
1479 + 'context' => array( 'view' ),
1480 + ),
1481 + 'custom_register' => array(
1482 + 'description' => __( 'Get custom register fields.' ),
1483 + 'type' => 'object',
1484 + 'context' => array( 'view' ),
1485 + ),
1486 + 'social' => array(
1487 + 'description' => __( 'Get social fields.' ),
1488 + 'type' => 'object',
1489 + 'context' => array( 'view' ),
1490 + ),
1491 + ),
1492 + );
1493 +
1494 + $schema['properties']['meta'] = $this->meta->get_field_schema();
1495 +
1496 + return $this->add_additional_fields_schema( $schema );
1497 + }
1498 +
1499 + public function get_collection_params() {
1500 + $query_params = parent::get_collection_params();
1501 +
1502 + $query_params['context']['default'] = 'view';
1503 +
1504 + $query_params['exclude'] = array(
1505 + 'description' => __( 'Ensure the result set excludes specific IDs.' ),
1506 + 'type' => 'array',
1507 + 'items' => array(
1508 + 'type' => 'integer',
1509 + ),
1510 + 'default' => array(),
1511 + );
1512 +
1513 + $query_params['include'] = array(
1514 + 'description' => __( 'Limit the result set to specific IDs.' ),
1515 + 'type' => 'array',
1516 + 'items' => array(
1517 + 'type' => 'integer',
1518 + ),
1519 + 'default' => array(),
1520 + );
1521 +
1522 + $query_params['offset'] = array(
1523 + 'description' => __( 'Offset the result set by a specific number of items.' ),
1524 + 'type' => 'integer',
1525 + );
1526 +
1527 + $query_params['order'] = array(
1528 + 'default' => 'asc',
1529 + 'description' => __( 'Sorting attributes in ascending or descending order.' ),
1530 + 'enum' => array( 'asc', 'desc' ),
1531 + 'type' => 'string',
1532 + );
1533 +
1534 + $query_params['orderby'] = array(
1535 + 'default' => 'name',
1536 + 'description' => __( 'Sort collections by the object attribute.' ),
1537 + 'enum' => array(
1538 + 'id',
1539 + 'include',
1540 + 'name',
1541 + 'registered_date',
1542 + 'slug',
1543 + 'include_slugs',
1544 + 'email',
1545 + 'url',
1546 + ),
1547 + 'type' => 'string',
1548 + );
1549 +
1550 + $query_params['slug'] = array(
1551 + 'description' => __( 'Limit result set to users with one or more specific slugs.' ),
1552 + 'type' => 'array',
1553 + 'items' => array(
1554 + 'type' => 'string',
1555 + ),
1556 + );
1557 +
1558 + $query_params['roles'] = array(
1559 + 'description' => __( 'Limit result set to users matching at least one specific role provided. Accepts csv list or single role.' ),
1560 + 'type' => 'array',
1561 + 'items' => array(
1562 + 'type' => 'string',
1563 + ),
1564 + );
1565 +
1566 + $query_params['who'] = array(
1567 + 'description' => __( 'Limit result set to users who are considered authors.' ),
1568 + 'type' => 'string',
1569 + 'enum' => array(
1570 + 'authors',
1571 + ),
1572 + );
1573 +
1574 + /**
1575 + * Filters REST API collection parameters for the users controller.
1576 + *
1577 + * This filter registers the collection parameter, but does not map the
1578 + * collection parameter to an internal WP_User_Query parameter. Use the
1579 + * `rest_user_query` filter to set WP_User_Query arguments.
1580 + *
1581 + * @since 4.7.0
1582 + *
1583 + * @param array $query_params JSON Schema-formatted collection parameters.
1584 + */
1585 + return apply_filters( 'rest_user_collection_params', $query_params );
1586 + }
1587 +}