[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * REST API: WP_REST_Users_Controller class 4 * 5 * @package WordPress 6 * @subpackage REST_API 7 * @since 4.7.0 8 */ 9 10 /** 11 * Core class used to manage users via the REST API. 12 * 13 * @since 4.7.0 14 * 15 * @see WP_REST_Controller 16 */ 17 class WP_REST_Users_Controller extends WP_REST_Controller { 18 19 /** 20 * Instance of a user meta fields object. 21 * 22 * @since 4.7.0 23 * @var WP_REST_User_Meta_Fields 24 */ 25 protected $meta; 26 27 /** 28 * Whether the controller supports batching. 29 * 30 * @since 6.6.0 31 * @var array 32 */ 33 protected $allow_batch = array( 'v1' => true ); 34 35 /** 36 * Constructor. 37 * 38 * @since 4.7.0 39 */ 40 public function __construct() { 41 $this->namespace = 'wp/v2'; 42 $this->rest_base = 'users'; 43 44 $this->meta = new WP_REST_User_Meta_Fields(); 45 } 46 47 /** 48 * Registers the routes for users. 49 * 50 * @since 4.7.0 51 * 52 * @see register_rest_route() 53 */ 54 public function register_routes() { 55 56 register_rest_route( 57 $this->namespace, 58 '/' . $this->rest_base, 59 array( 60 array( 61 'methods' => WP_REST_Server::READABLE, 62 'callback' => array( $this, 'get_items' ), 63 'permission_callback' => array( $this, 'get_items_permissions_check' ), 64 'args' => $this->get_collection_params(), 65 ), 66 array( 67 'methods' => WP_REST_Server::CREATABLE, 68 'callback' => array( $this, 'create_item' ), 69 'permission_callback' => array( $this, 'create_item_permissions_check' ), 70 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), 71 ), 72 'allow_batch' => $this->allow_batch, 73 'schema' => array( $this, 'get_public_item_schema' ), 74 ) 75 ); 76 77 register_rest_route( 78 $this->namespace, 79 '/' . $this->rest_base . '/(?P<id>[\d]+)', 80 array( 81 'args' => array( 82 'id' => array( 83 'description' => __( 'Unique identifier for the user.' ), 84 'type' => 'integer', 85 ), 86 ), 87 array( 88 'methods' => WP_REST_Server::READABLE, 89 'callback' => array( $this, 'get_item' ), 90 'permission_callback' => array( $this, 'get_item_permissions_check' ), 91 'args' => array( 92 'context' => $this->get_context_param( array( 'default' => 'view' ) ), 93 ), 94 ), 95 array( 96 'methods' => WP_REST_Server::EDITABLE, 97 'callback' => array( $this, 'update_item' ), 98 'permission_callback' => array( $this, 'update_item_permissions_check' ), 99 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), 100 ), 101 array( 102 'methods' => WP_REST_Server::DELETABLE, 103 'callback' => array( $this, 'delete_item' ), 104 'permission_callback' => array( $this, 'delete_item_permissions_check' ), 105 'args' => array( 106 'force' => array( 107 'type' => 'boolean', 108 'default' => false, 109 'description' => __( 'Required to be true, as users do not support trashing.' ), 110 ), 111 'reassign' => array( 112 'type' => 'integer', 113 'description' => __( 'Reassign the deleted user\'s posts and links to this user ID.' ), 114 'required' => true, 115 'sanitize_callback' => array( $this, 'check_reassign' ), 116 ), 117 ), 118 ), 119 'allow_batch' => $this->allow_batch, 120 'schema' => array( $this, 'get_public_item_schema' ), 121 ) 122 ); 123 124 register_rest_route( 125 $this->namespace, 126 '/' . $this->rest_base . '/me', 127 array( 128 array( 129 'methods' => WP_REST_Server::READABLE, 130 'permission_callback' => '__return_true', 131 'callback' => array( $this, 'get_current_item' ), 132 'args' => array( 133 'context' => $this->get_context_param( array( 'default' => 'view' ) ), 134 ), 135 ), 136 array( 137 'methods' => WP_REST_Server::EDITABLE, 138 'callback' => array( $this, 'update_current_item' ), 139 'permission_callback' => array( $this, 'update_current_item_permissions_check' ), 140 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), 141 ), 142 array( 143 'methods' => WP_REST_Server::DELETABLE, 144 'callback' => array( $this, 'delete_current_item' ), 145 'permission_callback' => array( $this, 'delete_current_item_permissions_check' ), 146 'args' => array( 147 'force' => array( 148 'type' => 'boolean', 149 'default' => false, 150 'description' => __( 'Required to be true, as users do not support trashing.' ), 151 ), 152 'reassign' => array( 153 'type' => 'integer', 154 'description' => __( 'Reassign the deleted user\'s posts and links to this user ID.' ), 155 'required' => true, 156 'sanitize_callback' => array( $this, 'check_reassign' ), 157 ), 158 ), 159 ), 160 'schema' => array( $this, 'get_public_item_schema' ), 161 ) 162 ); 163 } 164 165 /** 166 * Checks for a valid value for the reassign parameter when deleting users. 167 * 168 * The value can be an integer, 'false', false, or ''. 169 * 170 * @since 4.7.0 171 * 172 * @param int|bool $value The value passed to the reassign parameter. 173 * @param WP_REST_Request $request Full details about the request. 174 * @param string $param The parameter that is being sanitized. 175 * @return int|bool|WP_Error 176 */ 177 public function check_reassign( $value, $request, $param ) { 178 if ( is_numeric( $value ) ) { 179 return $value; 180 } 181 182 if ( empty( $value ) || false === $value || 'false' === $value ) { 183 return false; 184 } 185 186 return new WP_Error( 187 'rest_invalid_param', 188 __( 'Invalid user parameter(s).' ), 189 array( 'status' => 400 ) 190 ); 191 } 192 193 /** 194 * Permissions check for getting all users. 195 * 196 * @since 4.7.0 197 * 198 * @param WP_REST_Request $request Full details about the request. 199 * @return true|WP_Error True if the request has read access, otherwise WP_Error object. 200 */ 201 public function get_items_permissions_check( $request ) { 202 // Check if roles is specified in GET request and if user can list users. 203 if ( ! empty( $request['roles'] ) && ! current_user_can( 'list_users' ) ) { 204 return new WP_Error( 205 'rest_user_cannot_view', 206 __( 'Sorry, you are not allowed to filter users by role.' ), 207 array( 'status' => rest_authorization_required_code() ) 208 ); 209 } 210 211 // Check if capabilities is specified in GET request and if user can list users. 212 if ( ! empty( $request['capabilities'] ) && ! current_user_can( 'list_users' ) ) { 213 return new WP_Error( 214 'rest_user_cannot_view', 215 __( 'Sorry, you are not allowed to filter users by capability.' ), 216 array( 'status' => rest_authorization_required_code() ) 217 ); 218 } 219 220 if ( 'edit' === $request['context'] && ! current_user_can( 'list_users' ) ) { 221 return new WP_Error( 222 'rest_forbidden_context', 223 __( 'Sorry, you are not allowed to list users.' ), 224 array( 'status' => rest_authorization_required_code() ) 225 ); 226 } 227 228 if ( in_array( $request['orderby'], array( 'email', 'registered_date' ), true ) && ! current_user_can( 'list_users' ) ) { 229 return new WP_Error( 230 'rest_forbidden_orderby', 231 __( 'Sorry, you are not allowed to order users by this parameter.' ), 232 array( 'status' => rest_authorization_required_code() ) 233 ); 234 } 235 236 if ( 'authors' === $request['who'] ) { 237 $types = get_post_types( array( 'show_in_rest' => true ), 'objects' ); 238 239 foreach ( $types as $type ) { 240 if ( post_type_supports( $type->name, 'author' ) 241 && current_user_can( $type->cap->edit_posts ) ) { 242 return true; 243 } 244 } 245 246 return new WP_Error( 247 'rest_forbidden_who', 248 __( 'Sorry, you are not allowed to query users by this parameter.' ), 249 array( 'status' => rest_authorization_required_code() ) 250 ); 251 } 252 253 return true; 254 } 255 256 /** 257 * Retrieves all users. 258 * 259 * @since 4.7.0 260 * @since 6.8.0 Added support for the search_columns query param. 261 * 262 * @param WP_REST_Request $request Full details about the request. 263 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. 264 */ 265 public function get_items( $request ) { 266 267 // Retrieve the list of registered collection query parameters. 268 $registered = $this->get_collection_params(); 269 270 /* 271 * This array defines mappings between public API query parameters whose 272 * values are accepted as-passed, and their internal WP_Query parameter 273 * name equivalents (some are the same). Only values which are also 274 * present in $registered will be set. 275 */ 276 $parameter_mappings = array( 277 'exclude' => 'exclude', 278 'include' => 'include', 279 'order' => 'order', 280 'per_page' => 'number', 281 'search' => 'search', 282 'roles' => 'role__in', 283 'capabilities' => 'capability__in', 284 'slug' => 'nicename__in', 285 ); 286 287 $prepared_args = array(); 288 289 /* 290 * For each known parameter which is both registered and present in the request, 291 * set the parameter's value on the query $prepared_args. 292 */ 293 foreach ( $parameter_mappings as $api_param => $wp_param ) { 294 if ( isset( $registered[ $api_param ], $request[ $api_param ] ) ) { 295 $prepared_args[ $wp_param ] = $request[ $api_param ]; 296 } 297 } 298 299 if ( isset( $registered['offset'] ) && ! empty( $request['offset'] ) ) { 300 $prepared_args['offset'] = $request['offset']; 301 } else { 302 $prepared_args['offset'] = ( $request['page'] - 1 ) * $prepared_args['number']; 303 } 304 305 if ( isset( $registered['orderby'] ) ) { 306 $orderby_possibles = array( 307 'id' => 'ID', 308 'include' => 'include', 309 'name' => 'display_name', 310 'registered_date' => 'registered', 311 'slug' => 'user_nicename', 312 'include_slugs' => 'nicename__in', 313 'email' => 'user_email', 314 'url' => 'user_url', 315 ); 316 $prepared_args['orderby'] = $orderby_possibles[ $request['orderby'] ]; 317 } 318 319 if ( isset( $registered['who'] ) && ! empty( $request['who'] ) && 'authors' === $request['who'] ) { 320 $prepared_args['who'] = 'authors'; 321 } elseif ( ! current_user_can( 'list_users' ) ) { 322 $prepared_args['has_published_posts'] = get_post_types( array( 'show_in_rest' => true ), 'names' ); 323 } 324 325 if ( ! empty( $request['has_published_posts'] ) ) { 326 $prepared_args['has_published_posts'] = ( true === $request['has_published_posts'] ) 327 ? get_post_types( array( 'show_in_rest' => true ), 'names' ) 328 : (array) $request['has_published_posts']; 329 } 330 331 if ( ! empty( $prepared_args['search'] ) ) { 332 if ( ! current_user_can( 'list_users' ) ) { 333 $prepared_args['search_columns'] = array( 'ID', 'user_login', 'user_nicename', 'display_name' ); 334 } 335 $search_columns = $request->get_param( 'search_columns' ); 336 $valid_columns = isset( $prepared_args['search_columns'] ) 337 ? $prepared_args['search_columns'] 338 : array( 'ID', 'user_login', 'user_nicename', 'user_email', 'display_name' ); 339 $search_columns_mapping = array( 340 'id' => 'ID', 341 'username' => 'user_login', 342 'slug' => 'user_nicename', 343 'email' => 'user_email', 344 'name' => 'display_name', 345 ); 346 $search_columns = array_map( 347 static function ( $column ) use ( $search_columns_mapping ) { 348 return $search_columns_mapping[ $column ]; 349 }, 350 $search_columns 351 ); 352 $search_columns = array_intersect( $search_columns, $valid_columns ); 353 if ( ! empty( $search_columns ) ) { 354 $prepared_args['search_columns'] = $search_columns; 355 } 356 $prepared_args['search'] = '*' . $prepared_args['search'] . '*'; 357 } 358 359 $is_head_request = $request->is_method( 'HEAD' ); 360 if ( $is_head_request ) { 361 // Force the 'fields' argument. For HEAD requests, only user IDs are required. 362 $prepared_args['fields'] = 'id'; 363 } 364 /** 365 * Filters WP_User_Query arguments when querying users via the REST API. 366 * 367 * @link https://developer.wordpress.org/reference/classes/wp_user_query/ 368 * 369 * @since 4.7.0 370 * 371 * @param array $prepared_args Array of arguments for WP_User_Query. 372 * @param WP_REST_Request $request The REST API request. 373 */ 374 $prepared_args = apply_filters( 'rest_user_query', $prepared_args, $request ); 375 376 $query = new WP_User_Query( $prepared_args ); 377 378 if ( ! $is_head_request ) { 379 $users = array(); 380 381 foreach ( $query->get_results() as $user ) { 382 $data = $this->prepare_item_for_response( $user, $request ); 383 $users[] = $this->prepare_response_for_collection( $data ); 384 } 385 } 386 387 $response = $is_head_request ? new WP_REST_Response( array() ) : rest_ensure_response( $users ); 388 389 // Store pagination values for headers then unset for count query. 390 $per_page = (int) $prepared_args['number']; 391 $page = (int) ceil( ( ( (int) $prepared_args['offset'] ) / $per_page ) + 1 ); 392 393 $prepared_args['fields'] = 'ID'; 394 395 $total_users = $query->get_total(); 396 397 if ( $total_users < 1 ) { 398 // Out-of-bounds, run the query again without LIMIT for total count. 399 unset( $prepared_args['number'], $prepared_args['offset'] ); 400 $count_query = new WP_User_Query( $prepared_args ); 401 $total_users = $count_query->get_total(); 402 } 403 404 $response->header( 'X-WP-Total', (int) $total_users ); 405 406 $max_pages = (int) ceil( $total_users / $per_page ); 407 408 $response->header( 'X-WP-TotalPages', $max_pages ); 409 410 $base = add_query_arg( urlencode_deep( $request->get_query_params() ), rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ) ); 411 if ( $page > 1 ) { 412 $prev_page = $page - 1; 413 414 if ( $prev_page > $max_pages ) { 415 $prev_page = $max_pages; 416 } 417 418 $prev_link = add_query_arg( 'page', $prev_page, $base ); 419 $response->link_header( 'prev', $prev_link ); 420 } 421 if ( $max_pages > $page ) { 422 $next_page = $page + 1; 423 $next_link = add_query_arg( 'page', $next_page, $base ); 424 425 $response->link_header( 'next', $next_link ); 426 } 427 428 return $response; 429 } 430 431 /** 432 * Get the user, if the ID is valid. 433 * 434 * @since 4.7.2 435 * 436 * @param int $id Supplied ID. 437 * @return WP_User|WP_Error True if ID is valid, WP_Error otherwise. 438 */ 439 protected function get_user( $id ) { 440 $error = new WP_Error( 441 'rest_user_invalid_id', 442 __( 'Invalid user ID.' ), 443 array( 'status' => 404 ) 444 ); 445 446 if ( (int) $id <= 0 ) { 447 return $error; 448 } 449 450 $user = get_userdata( (int) $id ); 451 if ( empty( $user ) || ! $user->exists() ) { 452 return $error; 453 } 454 455 if ( is_multisite() && ! is_user_member_of_blog( $user->ID ) ) { 456 return $error; 457 } 458 459 return $user; 460 } 461 462 /** 463 * Checks if a given request has access to read a user. 464 * 465 * @since 4.7.0 466 * 467 * @param WP_REST_Request $request Full details about the request. 468 * @return true|WP_Error True if the request has read access for the item, otherwise WP_Error object. 469 */ 470 public function get_item_permissions_check( $request ) { 471 $user = $this->get_user( $request['id'] ); 472 if ( is_wp_error( $user ) ) { 473 return $user; 474 } 475 476 $types = get_post_types( array( 'show_in_rest' => true ), 'names' ); 477 478 if ( get_current_user_id() === $user->ID ) { 479 return true; 480 } 481 482 if ( 'edit' === $request['context'] && ! current_user_can( 'list_users' ) ) { 483 return new WP_Error( 484 'rest_user_cannot_view', 485 __( 'Sorry, you are not allowed to list users.' ), 486 array( 'status' => rest_authorization_required_code() ) 487 ); 488 } elseif ( ! count_user_posts( $user->ID, $types ) && ! current_user_can( 'edit_user', $user->ID ) && ! current_user_can( 'list_users' ) ) { 489 return new WP_Error( 490 'rest_user_cannot_view', 491 __( 'Sorry, you are not allowed to list users.' ), 492 array( 'status' => rest_authorization_required_code() ) 493 ); 494 } 495 496 return true; 497 } 498 499 /** 500 * Retrieves a single user. 501 * 502 * @since 4.7.0 503 * 504 * @param WP_REST_Request $request Full details about the request. 505 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. 506 */ 507 public function get_item( $request ) { 508 $user = $this->get_user( $request['id'] ); 509 if ( is_wp_error( $user ) ) { 510 return $user; 511 } 512 513 $user = $this->prepare_item_for_response( $user, $request ); 514 $response = rest_ensure_response( $user ); 515 516 return $response; 517 } 518 519 /** 520 * Retrieves the current user. 521 * 522 * @since 4.7.0 523 * 524 * @param WP_REST_Request $request Full details about the request. 525 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. 526 */ 527 public function get_current_item( $request ) { 528 $current_user_id = get_current_user_id(); 529 530 if ( empty( $current_user_id ) ) { 531 return new WP_Error( 532 'rest_not_logged_in', 533 __( 'You are not currently logged in.' ), 534 array( 'status' => 401 ) 535 ); 536 } 537 538 $user = wp_get_current_user(); 539 $response = $this->prepare_item_for_response( $user, $request ); 540 $response = rest_ensure_response( $response ); 541 542 return $response; 543 } 544 545 /** 546 * Checks if a given request has access create users. 547 * 548 * @since 4.7.0 549 * 550 * @param WP_REST_Request $request Full details about the request. 551 * @return true|WP_Error True if the request has access to create items, WP_Error object otherwise. 552 */ 553 public function create_item_permissions_check( $request ) { 554 555 if ( ! current_user_can( 'create_users' ) ) { 556 return new WP_Error( 557 'rest_cannot_create_user', 558 __( 'Sorry, you are not allowed to create new users.' ), 559 array( 'status' => rest_authorization_required_code() ) 560 ); 561 } 562 563 return true; 564 } 565 566 /** 567 * Creates a single user. 568 * 569 * @since 4.7.0 570 * 571 * @param WP_REST_Request $request Full details about the request. 572 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. 573 */ 574 public function create_item( $request ) { 575 if ( ! empty( $request['id'] ) ) { 576 return new WP_Error( 577 'rest_user_exists', 578 __( 'Cannot create existing user.' ), 579 array( 'status' => 400 ) 580 ); 581 } 582 583 $schema = $this->get_item_schema(); 584 585 if ( ! empty( $request['roles'] ) && ! empty( $schema['properties']['roles'] ) ) { 586 $check_permission = $this->check_role_update( $request['id'], $request['roles'] ); 587 588 if ( is_wp_error( $check_permission ) ) { 589 return $check_permission; 590 } 591 } 592 593 $user = $this->prepare_item_for_database( $request ); 594 595 if ( is_multisite() ) { 596 $ret = wpmu_validate_user_signup( $user->user_login, $user->user_email ); 597 598 if ( is_wp_error( $ret['errors'] ) && $ret['errors']->has_errors() ) { 599 $error = new WP_Error( 600 'rest_invalid_param', 601 __( 'Invalid user parameter(s).' ), 602 array( 'status' => 400 ) 603 ); 604 605 foreach ( $ret['errors']->errors as $code => $messages ) { 606 foreach ( $messages as $message ) { 607 $error->add( $code, $message ); 608 } 609 610 $error_data = $error->get_error_data( $code ); 611 612 if ( $error_data ) { 613 $error->add_data( $error_data, $code ); 614 } 615 } 616 return $error; 617 } 618 } 619 620 if ( is_multisite() ) { 621 $user_id = wpmu_create_user( $user->user_login, $user->user_pass, $user->user_email ); 622 623 if ( ! $user_id ) { 624 return new WP_Error( 625 'rest_user_create', 626 __( 'Error creating new user.' ), 627 array( 'status' => 500 ) 628 ); 629 } 630 631 $user->ID = $user_id; 632 $user_id = wp_update_user( wp_slash( (array) $user ) ); 633 634 if ( is_wp_error( $user_id ) ) { 635 return $user_id; 636 } 637 638 $result = add_user_to_blog( get_site()->id, $user_id, '' ); 639 if ( is_wp_error( $result ) ) { 640 return $result; 641 } 642 } else { 643 $user_id = wp_insert_user( wp_slash( (array) $user ) ); 644 645 if ( is_wp_error( $user_id ) ) { 646 return $user_id; 647 } 648 } 649 650 $user = get_user_by( 'id', $user_id ); 651 652 /** 653 * Fires immediately after a user is created or updated via the REST API. 654 * 655 * @since 4.7.0 656 * 657 * @param WP_User $user Inserted or updated user object. 658 * @param WP_REST_Request $request Request object. 659 * @param bool $creating True when creating a user, false when updating. 660 */ 661 do_action( 'rest_insert_user', $user, $request, true ); 662 663 if ( ! empty( $request['roles'] ) && ! empty( $schema['properties']['roles'] ) ) { 664 array_map( array( $user, 'add_role' ), $request['roles'] ); 665 } 666 667 if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) { 668 $meta_update = $this->meta->update_value( $request['meta'], $user_id ); 669 670 if ( is_wp_error( $meta_update ) ) { 671 return $meta_update; 672 } 673 } 674 675 $user = get_user_by( 'id', $user_id ); 676 $fields_update = $this->update_additional_fields_for_object( $user, $request ); 677 678 if ( is_wp_error( $fields_update ) ) { 679 return $fields_update; 680 } 681 682 $request->set_param( 'context', 'edit' ); 683 684 /** 685 * Fires after a user is completely created or updated via the REST API. 686 * 687 * @since 5.0.0 688 * 689 * @param WP_User $user Inserted or updated user object. 690 * @param WP_REST_Request $request Request object. 691 * @param bool $creating True when creating a user, false when updating. 692 */ 693 do_action( 'rest_after_insert_user', $user, $request, true ); 694 695 $response = $this->prepare_item_for_response( $user, $request ); 696 $response = rest_ensure_response( $response ); 697 698 $response->set_status( 201 ); 699 $response->header( 'Location', rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $user_id ) ) ); 700 701 return $response; 702 } 703 704 /** 705 * Checks if a given request has access to update a user. 706 * 707 * @since 4.7.0 708 * 709 * @param WP_REST_Request $request Full details about the request. 710 * @return true|WP_Error True if the request has access to update the item, WP_Error object otherwise. 711 */ 712 public function update_item_permissions_check( $request ) { 713 $user = $this->get_user( $request['id'] ); 714 if ( is_wp_error( $user ) ) { 715 return $user; 716 } 717 718 if ( ! empty( $request['roles'] ) ) { 719 if ( ! current_user_can( 'promote_user', $user->ID ) ) { 720 return new WP_Error( 721 'rest_cannot_edit_roles', 722 __( 'Sorry, you are not allowed to edit roles of this user.' ), 723 array( 'status' => rest_authorization_required_code() ) 724 ); 725 } 726 727 $request_params = array_keys( $request->get_params() ); 728 sort( $request_params ); 729 /* 730 * If only 'id' and 'roles' are specified (we are only trying to 731 * edit roles), then only the 'promote_user' cap is required. 732 */ 733 if ( array( 'id', 'roles' ) === $request_params ) { 734 return true; 735 } 736 } 737 738 if ( ! current_user_can( 'edit_user', $user->ID ) ) { 739 return new WP_Error( 740 'rest_cannot_edit', 741 __( 'Sorry, you are not allowed to edit this user.' ), 742 array( 'status' => rest_authorization_required_code() ) 743 ); 744 } 745 746 return true; 747 } 748 749 /** 750 * Updates a single user. 751 * 752 * @since 4.7.0 753 * 754 * @param WP_REST_Request $request Full details about the request. 755 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. 756 */ 757 public function update_item( $request ) { 758 $user = $this->get_user( $request['id'] ); 759 if ( is_wp_error( $user ) ) { 760 return $user; 761 } 762 763 $id = $user->ID; 764 765 $owner_id = false; 766 if ( is_string( $request['email'] ) ) { 767 $owner_id = email_exists( $request['email'] ); 768 } 769 770 if ( $owner_id && $owner_id !== $id ) { 771 return new WP_Error( 772 'rest_user_invalid_email', 773 __( 'Invalid email address.' ), 774 array( 'status' => 400 ) 775 ); 776 } 777 778 if ( ! empty( $request['username'] ) && $request['username'] !== $user->user_login ) { 779 return new WP_Error( 780 'rest_user_invalid_argument', 781 __( 'Username is not editable.' ), 782 array( 'status' => 400 ) 783 ); 784 } 785 786 if ( ! empty( $request['slug'] ) && $request['slug'] !== $user->user_nicename && get_user_by( 'slug', $request['slug'] ) ) { 787 return new WP_Error( 788 'rest_user_invalid_slug', 789 __( 'Invalid slug.' ), 790 array( 'status' => 400 ) 791 ); 792 } 793 794 if ( ! empty( $request['roles'] ) ) { 795 $check_permission = $this->check_role_update( $id, $request['roles'] ); 796 797 if ( is_wp_error( $check_permission ) ) { 798 return $check_permission; 799 } 800 } 801 802 $user = $this->prepare_item_for_database( $request ); 803 804 // Ensure we're operating on the same user we already checked. 805 $user->ID = $id; 806 807 $user_id = wp_update_user( wp_slash( (array) $user ) ); 808 809 if ( is_wp_error( $user_id ) ) { 810 return $user_id; 811 } 812 813 $user = get_user_by( 'id', $user_id ); 814 815 /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php */ 816 do_action( 'rest_insert_user', $user, $request, false ); 817 818 if ( ! empty( $request['roles'] ) ) { 819 array_map( array( $user, 'add_role' ), $request['roles'] ); 820 } 821 822 $schema = $this->get_item_schema(); 823 824 if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) { 825 $meta_update = $this->meta->update_value( $request['meta'], $id ); 826 827 if ( is_wp_error( $meta_update ) ) { 828 return $meta_update; 829 } 830 } 831 832 $user = get_user_by( 'id', $user_id ); 833 $fields_update = $this->update_additional_fields_for_object( $user, $request ); 834 835 if ( is_wp_error( $fields_update ) ) { 836 return $fields_update; 837 } 838 839 $request->set_param( 'context', 'edit' ); 840 841 /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php */ 842 do_action( 'rest_after_insert_user', $user, $request, false ); 843 844 $response = $this->prepare_item_for_response( $user, $request ); 845 $response = rest_ensure_response( $response ); 846 847 return $response; 848 } 849 850 /** 851 * Checks if a given request has access to update the current user. 852 * 853 * @since 4.7.0 854 * 855 * @param WP_REST_Request $request Full details about the request. 856 * @return true|WP_Error True if the request has access to update the item, WP_Error object otherwise. 857 */ 858 public function update_current_item_permissions_check( $request ) { 859 $request['id'] = get_current_user_id(); 860 861 return $this->update_item_permissions_check( $request ); 862 } 863 864 /** 865 * Updates the current user. 866 * 867 * @since 4.7.0 868 * 869 * @param WP_REST_Request $request Full details about the request. 870 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. 871 */ 872 public function update_current_item( $request ) { 873 $request['id'] = get_current_user_id(); 874 875 return $this->update_item( $request ); 876 } 877 878 /** 879 * Checks if a given request has access delete a user. 880 * 881 * @since 4.7.0 882 * 883 * @param WP_REST_Request $request Full details about the request. 884 * @return true|WP_Error True if the request has access to delete the item, WP_Error object otherwise. 885 */ 886 public function delete_item_permissions_check( $request ) { 887 $user = $this->get_user( $request['id'] ); 888 if ( is_wp_error( $user ) ) { 889 return $user; 890 } 891 892 if ( ! current_user_can( 'delete_user', $user->ID ) ) { 893 return new WP_Error( 894 'rest_user_cannot_delete', 895 __( 'Sorry, you are not allowed to delete this user.' ), 896 array( 'status' => rest_authorization_required_code() ) 897 ); 898 } 899 900 return true; 901 } 902 903 /** 904 * Deletes a single user. 905 * 906 * @since 4.7.0 907 * 908 * @param WP_REST_Request $request Full details about the request. 909 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. 910 */ 911 public function delete_item( $request ) { 912 // We don't support delete requests in multisite. 913 if ( is_multisite() ) { 914 return new WP_Error( 915 'rest_cannot_delete', 916 __( 'The user cannot be deleted.' ), 917 array( 'status' => 501 ) 918 ); 919 } 920 921 $user = $this->get_user( $request['id'] ); 922 923 if ( is_wp_error( $user ) ) { 924 return $user; 925 } 926 927 $id = $user->ID; 928 $reassign = false === $request['reassign'] ? null : absint( $request['reassign'] ); 929 $force = isset( $request['force'] ) ? (bool) $request['force'] : false; 930 931 // We don't support trashing for users. 932 if ( ! $force ) { 933 return new WP_Error( 934 'rest_trash_not_supported', 935 /* translators: %s: force=true */ 936 sprintf( __( "Users do not support trashing. Set '%s' to delete." ), 'force=true' ), 937 array( 'status' => 501 ) 938 ); 939 } 940 941 if ( ! empty( $reassign ) ) { 942 if ( $reassign === $id || ! get_userdata( $reassign ) ) { 943 return new WP_Error( 944 'rest_user_invalid_reassign', 945 __( 'Invalid user ID for reassignment.' ), 946 array( 'status' => 400 ) 947 ); 948 } 949 } 950 951 $request->set_param( 'context', 'edit' ); 952 953 $previous = $this->prepare_item_for_response( $user, $request ); 954 955 // Include user admin functions to get access to wp_delete_user(). 956 require_once ABSPATH . 'wp-admin/includes/user.php'; 957 958 $result = wp_delete_user( $id, $reassign ); 959 960 if ( ! $result ) { 961 return new WP_Error( 962 'rest_cannot_delete', 963 __( 'The user cannot be deleted.' ), 964 array( 'status' => 500 ) 965 ); 966 } 967 968 $response = new WP_REST_Response(); 969 $response->set_data( 970 array( 971 'deleted' => true, 972 'previous' => $previous->get_data(), 973 ) 974 ); 975 976 /** 977 * Fires immediately after a user is deleted via the REST API. 978 * 979 * @since 4.7.0 980 * 981 * @param WP_User $user The user data. 982 * @param WP_REST_Response $response The response returned from the API. 983 * @param WP_REST_Request $request The request sent to the API. 984 */ 985 do_action( 'rest_delete_user', $user, $response, $request ); 986 987 return $response; 988 } 989 990 /** 991 * Checks if a given request has access to delete the current user. 992 * 993 * @since 4.7.0 994 * 995 * @param WP_REST_Request $request Full details about the request. 996 * @return true|WP_Error True if the request has access to delete the item, WP_Error object otherwise. 997 */ 998 public function delete_current_item_permissions_check( $request ) { 999 $request['id'] = get_current_user_id(); 1000 1001 return $this->delete_item_permissions_check( $request ); 1002 } 1003 1004 /** 1005 * Deletes the current user. 1006 * 1007 * @since 4.7.0 1008 * 1009 * @param WP_REST_Request $request Full details about the request. 1010 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. 1011 */ 1012 public function delete_current_item( $request ) { 1013 $request['id'] = get_current_user_id(); 1014 1015 return $this->delete_item( $request ); 1016 } 1017 1018 /** 1019 * Prepares a single user output for response. 1020 * 1021 * @since 4.7.0 1022 * @since 5.9.0 Renamed `$user` to `$item` to match parent class for PHP 8 named parameter support. 1023 * 1024 * @param WP_User $item User object. 1025 * @param WP_REST_Request $request Request object. 1026 * @return WP_REST_Response Response object. 1027 */ 1028 public function prepare_item_for_response( $item, $request ) { 1029 // Restores the more descriptive, specific name for use within this method. 1030 $user = $item; 1031 1032 // Don't prepare the response body for HEAD requests. 1033 if ( $request->is_method( 'HEAD' ) ) { 1034 /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php */ 1035 return apply_filters( 'rest_prepare_user', new WP_REST_Response( array() ), $user, $request ); 1036 } 1037 1038 $fields = $this->get_fields_for_response( $request ); 1039 $data = array(); 1040 1041 if ( in_array( 'id', $fields, true ) ) { 1042 $data['id'] = $user->ID; 1043 } 1044 1045 if ( in_array( 'username', $fields, true ) ) { 1046 $data['username'] = $user->user_login; 1047 } 1048 1049 if ( in_array( 'name', $fields, true ) ) { 1050 $data['name'] = $user->display_name; 1051 } 1052 1053 if ( in_array( 'first_name', $fields, true ) ) { 1054 $data['first_name'] = $user->first_name; 1055 } 1056 1057 if ( in_array( 'last_name', $fields, true ) ) { 1058 $data['last_name'] = $user->last_name; 1059 } 1060 1061 if ( in_array( 'email', $fields, true ) ) { 1062 $data['email'] = $user->user_email; 1063 } 1064 1065 if ( in_array( 'url', $fields, true ) ) { 1066 $data['url'] = $user->user_url; 1067 } 1068 1069 if ( in_array( 'description', $fields, true ) ) { 1070 $data['description'] = $user->description; 1071 } 1072 1073 if ( in_array( 'link', $fields, true ) ) { 1074 $data['link'] = get_author_posts_url( $user->ID, $user->user_nicename ); 1075 } 1076 1077 if ( in_array( 'locale', $fields, true ) ) { 1078 $data['locale'] = get_user_locale( $user ); 1079 } 1080 1081 if ( in_array( 'nickname', $fields, true ) ) { 1082 $data['nickname'] = $user->nickname; 1083 } 1084 1085 if ( in_array( 'slug', $fields, true ) ) { 1086 $data['slug'] = $user->user_nicename; 1087 } 1088 1089 if ( in_array( 'roles', $fields, true ) ) { 1090 // Defensively call array_values() to ensure an array is returned. 1091 $data['roles'] = array_values( $user->roles ); 1092 } 1093 1094 if ( in_array( 'registered_date', $fields, true ) ) { 1095 $data['registered_date'] = gmdate( 'c', strtotime( $user->user_registered ) ); 1096 } 1097 1098 if ( in_array( 'capabilities', $fields, true ) ) { 1099 $data['capabilities'] = (object) $user->allcaps; 1100 } 1101 1102 if ( in_array( 'extra_capabilities', $fields, true ) ) { 1103 $data['extra_capabilities'] = (object) $user->caps; 1104 } 1105 1106 if ( in_array( 'avatar_urls', $fields, true ) ) { 1107 $data['avatar_urls'] = rest_get_avatar_urls( $user ); 1108 } 1109 1110 if ( in_array( 'meta', $fields, true ) ) { 1111 $data['meta'] = $this->meta->get_value( $user->ID, $request ); 1112 } 1113 1114 $context = ! empty( $request['context'] ) ? $request['context'] : 'embed'; 1115 1116 $data = $this->add_additional_fields_to_object( $data, $request ); 1117 $data = $this->filter_response_by_context( $data, $context ); 1118 1119 // Wrap the data in a response object. 1120 $response = rest_ensure_response( $data ); 1121 1122 if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { 1123 $response->add_links( $this->prepare_links( $user ) ); 1124 } 1125 1126 /** 1127 * Filters user data returned from the REST API. 1128 * 1129 * @since 4.7.0 1130 * 1131 * @param WP_REST_Response $response The response object. 1132 * @param WP_User $user User object used to create response. 1133 * @param WP_REST_Request $request Request object. 1134 */ 1135 return apply_filters( 'rest_prepare_user', $response, $user, $request ); 1136 } 1137 1138 /** 1139 * Prepares links for the user request. 1140 * 1141 * @since 4.7.0 1142 * 1143 * @param WP_User $user User object. 1144 * @return array Links for the given user. 1145 */ 1146 protected function prepare_links( $user ) { 1147 $links = array( 1148 'self' => array( 1149 'href' => rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $user->ID ) ), 1150 ), 1151 'collection' => array( 1152 'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ), 1153 ), 1154 ); 1155 1156 return $links; 1157 } 1158 1159 /** 1160 * Prepares a single user for creation or update. 1161 * 1162 * @since 4.7.0 1163 * 1164 * @param WP_REST_Request $request Request object. 1165 * @return object User object. 1166 */ 1167 protected function prepare_item_for_database( $request ) { 1168 $prepared_user = new stdClass(); 1169 1170 $schema = $this->get_item_schema(); 1171 1172 // Required arguments. 1173 if ( isset( $request['email'] ) && ! empty( $schema['properties']['email'] ) ) { 1174 $prepared_user->user_email = $request['email']; 1175 } 1176 1177 if ( isset( $request['username'] ) && ! empty( $schema['properties']['username'] ) ) { 1178 $prepared_user->user_login = $request['username']; 1179 } 1180 1181 if ( isset( $request['password'] ) && ! empty( $schema['properties']['password'] ) ) { 1182 $prepared_user->user_pass = $request['password']; 1183 } 1184 1185 // Optional arguments. 1186 if ( isset( $request['id'] ) ) { 1187 $prepared_user->ID = absint( $request['id'] ); 1188 } 1189 1190 if ( isset( $request['name'] ) && ! empty( $schema['properties']['name'] ) ) { 1191 $prepared_user->display_name = $request['name']; 1192 } 1193 1194 if ( isset( $request['first_name'] ) && ! empty( $schema['properties']['first_name'] ) ) { 1195 $prepared_user->first_name = $request['first_name']; 1196 } 1197 1198 if ( isset( $request['last_name'] ) && ! empty( $schema['properties']['last_name'] ) ) { 1199 $prepared_user->last_name = $request['last_name']; 1200 } 1201 1202 if ( isset( $request['nickname'] ) && ! empty( $schema['properties']['nickname'] ) ) { 1203 $prepared_user->nickname = $request['nickname']; 1204 } 1205 1206 if ( isset( $request['slug'] ) && ! empty( $schema['properties']['slug'] ) ) { 1207 $prepared_user->user_nicename = $request['slug']; 1208 } 1209 1210 if ( isset( $request['description'] ) && ! empty( $schema['properties']['description'] ) ) { 1211 $prepared_user->description = $request['description']; 1212 } 1213 1214 if ( isset( $request['url'] ) && ! empty( $schema['properties']['url'] ) ) { 1215 $prepared_user->user_url = $request['url']; 1216 } 1217 1218 if ( isset( $request['locale'] ) && ! empty( $schema['properties']['locale'] ) ) { 1219 $prepared_user->locale = $request['locale']; 1220 } 1221 1222 // Setting roles will be handled outside of this function. 1223 if ( isset( $request['roles'] ) ) { 1224 $prepared_user->role = false; 1225 } 1226 1227 /** 1228 * Filters user data before insertion via the REST API. 1229 * 1230 * @since 4.7.0 1231 * 1232 * @param object $prepared_user User object. 1233 * @param WP_REST_Request $request Request object. 1234 */ 1235 return apply_filters( 'rest_pre_insert_user', $prepared_user, $request ); 1236 } 1237 1238 /** 1239 * Determines if the current user is allowed to make the desired roles change. 1240 * 1241 * @since 4.7.0 1242 * 1243 * @global WP_Roles $wp_roles WordPress role management object. 1244 * 1245 * @param int $user_id User ID. 1246 * @param array $roles New user roles. 1247 * @return true|WP_Error True if the current user is allowed to make the role change, 1248 * otherwise a WP_Error object. 1249 */ 1250 protected function check_role_update( $user_id, $roles ) { 1251 global $wp_roles; 1252 1253 foreach ( $roles as $role ) { 1254 1255 if ( ! isset( $wp_roles->role_objects[ $role ] ) ) { 1256 return new WP_Error( 1257 'rest_user_invalid_role', 1258 /* translators: %s: Role key. */ 1259 sprintf( __( 'The role %s does not exist.' ), $role ), 1260 array( 'status' => 400 ) 1261 ); 1262 } 1263 1264 $potential_role = $wp_roles->role_objects[ $role ]; 1265 1266 /* 1267 * Don't let anyone with 'edit_users' (admins) edit their own role to something without it. 1268 * Multisite super admins can freely edit their blog roles -- they possess all caps. 1269 */ 1270 if ( ! ( is_multisite() 1271 && current_user_can( 'manage_sites' ) ) 1272 && get_current_user_id() === $user_id 1273 && ! $potential_role->has_cap( 'edit_users' ) 1274 ) { 1275 return new WP_Error( 1276 'rest_user_invalid_role', 1277 __( 'Sorry, you are not allowed to give users that role.' ), 1278 array( 'status' => rest_authorization_required_code() ) 1279 ); 1280 } 1281 1282 // Include user admin functions to get access to get_editable_roles(). 1283 require_once ABSPATH . 'wp-admin/includes/user.php'; 1284 1285 // The new role must be editable by the logged-in user. 1286 $editable_roles = get_editable_roles(); 1287 1288 if ( empty( $editable_roles[ $role ] ) ) { 1289 return new WP_Error( 1290 'rest_user_invalid_role', 1291 __( 'Sorry, you are not allowed to give users that role.' ), 1292 array( 'status' => 403 ) 1293 ); 1294 } 1295 } 1296 1297 return true; 1298 } 1299 1300 /** 1301 * Check a username for the REST API. 1302 * 1303 * Performs a couple of checks like edit_user() in wp-admin/includes/user.php. 1304 * 1305 * @since 4.7.0 1306 * 1307 * @param string $value The username submitted in the request. 1308 * @param WP_REST_Request $request Full details about the request. 1309 * @param string $param The parameter name. 1310 * @return string|WP_Error The sanitized username, if valid, otherwise an error. 1311 */ 1312 public function check_username( $value, $request, $param ) { 1313 $username = (string) $value; 1314 1315 if ( ! validate_username( $username ) ) { 1316 return new WP_Error( 1317 'rest_user_invalid_username', 1318 __( 'This username is invalid because it uses illegal characters. Please enter a valid username.' ), 1319 array( 'status' => 400 ) 1320 ); 1321 } 1322 1323 /** This filter is documented in wp-includes/user.php */ 1324 $illegal_logins = (array) apply_filters( 'illegal_user_logins', array() ); 1325 1326 if ( in_array( strtolower( $username ), array_map( 'strtolower', $illegal_logins ), true ) ) { 1327 return new WP_Error( 1328 'rest_user_invalid_username', 1329 __( 'Sorry, that username is not allowed.' ), 1330 array( 'status' => 400 ) 1331 ); 1332 } 1333 1334 return $username; 1335 } 1336 1337 /** 1338 * Check a user password for the REST API. 1339 * 1340 * Performs a couple of checks like edit_user() in wp-admin/includes/user.php. 1341 * 1342 * @since 4.7.0 1343 * 1344 * @param string $value The password submitted in the request. 1345 * @param WP_REST_Request $request Full details about the request. 1346 * @param string $param The parameter name. 1347 * @return string|WP_Error The sanitized password, if valid, otherwise an error. 1348 */ 1349 public function check_user_password( 1350 #[\SensitiveParameter] 1351 $value, 1352 $request, 1353 $param 1354 ) { 1355 $password = (string) $value; 1356 1357 if ( empty( $password ) ) { 1358 return new WP_Error( 1359 'rest_user_invalid_password', 1360 __( 'Passwords cannot be empty.' ), 1361 array( 'status' => 400 ) 1362 ); 1363 } 1364 1365 if ( str_contains( $password, '\\' ) ) { 1366 return new WP_Error( 1367 'rest_user_invalid_password', 1368 sprintf( 1369 /* translators: %s: The '\' character. */ 1370 __( 'Passwords cannot contain the "%s" character.' ), 1371 '\\' 1372 ), 1373 array( 'status' => 400 ) 1374 ); 1375 } 1376 1377 return $password; 1378 } 1379 1380 /** 1381 * Retrieves the user's schema, conforming to JSON Schema. 1382 * 1383 * @since 4.7.0 1384 * 1385 * @return array Item schema data. 1386 */ 1387 public function get_item_schema() { 1388 if ( $this->schema ) { 1389 return $this->add_additional_fields_schema( $this->schema ); 1390 } 1391 1392 $schema = array( 1393 '$schema' => 'http://json-schema.org/draft-04/schema#', 1394 'title' => 'user', 1395 'type' => 'object', 1396 'properties' => array( 1397 'id' => array( 1398 'description' => __( 'Unique identifier for the user.' ), 1399 'type' => 'integer', 1400 'context' => array( 'embed', 'view', 'edit' ), 1401 'readonly' => true, 1402 ), 1403 'username' => array( 1404 'description' => __( 'Login name for the user.' ), 1405 'type' => 'string', 1406 'context' => array( 'edit' ), 1407 'required' => true, 1408 'arg_options' => array( 1409 'sanitize_callback' => array( $this, 'check_username' ), 1410 ), 1411 ), 1412 'name' => array( 1413 'description' => __( 'Display name for the user.' ), 1414 'type' => 'string', 1415 'context' => array( 'embed', 'view', 'edit' ), 1416 'arg_options' => array( 1417 'sanitize_callback' => 'sanitize_text_field', 1418 ), 1419 ), 1420 'first_name' => array( 1421 'description' => __( 'First name for the user.' ), 1422 'type' => 'string', 1423 'context' => array( 'edit' ), 1424 'arg_options' => array( 1425 'sanitize_callback' => 'sanitize_text_field', 1426 ), 1427 ), 1428 'last_name' => array( 1429 'description' => __( 'Last name for the user.' ), 1430 'type' => 'string', 1431 'context' => array( 'edit' ), 1432 'arg_options' => array( 1433 'sanitize_callback' => 'sanitize_text_field', 1434 ), 1435 ), 1436 'email' => array( 1437 'description' => __( 'The email address for the user.' ), 1438 'type' => 'string', 1439 'format' => 'email', 1440 'context' => array( 'edit' ), 1441 'required' => true, 1442 ), 1443 'url' => array( 1444 'description' => __( 'URL of the user.' ), 1445 'type' => 'string', 1446 'format' => 'uri', 1447 'context' => array( 'embed', 'view', 'edit' ), 1448 ), 1449 'description' => array( 1450 'description' => __( 'Description of the user.' ), 1451 'type' => 'string', 1452 'context' => array( 'embed', 'view', 'edit' ), 1453 ), 1454 'link' => array( 1455 'description' => __( 'Author URL of the user.' ), 1456 'type' => 'string', 1457 'format' => 'uri', 1458 'context' => array( 'embed', 'view', 'edit' ), 1459 'readonly' => true, 1460 ), 1461 'locale' => array( 1462 'description' => __( 'Locale for the user.' ), 1463 'type' => 'string', 1464 'enum' => array_merge( array( '', 'en_US' ), get_available_languages() ), 1465 'context' => array( 'edit' ), 1466 ), 1467 'nickname' => array( 1468 'description' => __( 'The nickname for the user.' ), 1469 'type' => 'string', 1470 'context' => array( 'edit' ), 1471 'arg_options' => array( 1472 'sanitize_callback' => 'sanitize_text_field', 1473 ), 1474 ), 1475 'slug' => array( 1476 'description' => __( 'An alphanumeric identifier for the user.' ), 1477 'type' => 'string', 1478 'context' => array( 'embed', 'view', 'edit' ), 1479 'arg_options' => array( 1480 'sanitize_callback' => array( $this, 'sanitize_slug' ), 1481 ), 1482 ), 1483 'registered_date' => array( 1484 'description' => __( 'Registration date for the user.' ), 1485 'type' => 'string', 1486 'format' => 'date-time', 1487 'context' => array( 'edit' ), 1488 'readonly' => true, 1489 ), 1490 'roles' => array( 1491 'description' => __( 'Roles assigned to the user.' ), 1492 'type' => 'array', 1493 'items' => array( 1494 'type' => 'string', 1495 ), 1496 'context' => array( 'edit' ), 1497 ), 1498 'password' => array( 1499 'description' => __( 'Password for the user (never included).' ), 1500 'type' => 'string', 1501 'context' => array(), // Password is never displayed. 1502 'required' => true, 1503 'arg_options' => array( 1504 'sanitize_callback' => array( $this, 'check_user_password' ), 1505 ), 1506 ), 1507 'capabilities' => array( 1508 'description' => __( 'All capabilities assigned to the user.' ), 1509 'type' => 'object', 1510 'context' => array( 'edit' ), 1511 'readonly' => true, 1512 ), 1513 'extra_capabilities' => array( 1514 'description' => __( 'Any extra capabilities assigned to the user.' ), 1515 'type' => 'object', 1516 'context' => array( 'edit' ), 1517 'readonly' => true, 1518 ), 1519 ), 1520 ); 1521 1522 if ( get_option( 'show_avatars' ) ) { 1523 $avatar_properties = array(); 1524 1525 $avatar_sizes = rest_get_avatar_sizes(); 1526 1527 foreach ( $avatar_sizes as $size ) { 1528 $avatar_properties[ $size ] = array( 1529 /* translators: %d: Avatar image size in pixels. */ 1530 'description' => sprintf( __( 'Avatar URL with image size of %d pixels.' ), $size ), 1531 'type' => 'string', 1532 'format' => 'uri', 1533 'context' => array( 'embed', 'view', 'edit' ), 1534 ); 1535 } 1536 1537 $schema['properties']['avatar_urls'] = array( 1538 'description' => __( 'Avatar URLs for the user.' ), 1539 'type' => 'object', 1540 'context' => array( 'embed', 'view', 'edit' ), 1541 'readonly' => true, 1542 'properties' => $avatar_properties, 1543 ); 1544 } 1545 1546 $schema['properties']['meta'] = $this->meta->get_field_schema(); 1547 1548 $this->schema = $schema; 1549 1550 return $this->add_additional_fields_schema( $this->schema ); 1551 } 1552 1553 /** 1554 * Retrieves the query params for collections. 1555 * 1556 * @since 4.7.0 1557 * 1558 * @return array Collection parameters. 1559 */ 1560 public function get_collection_params() { 1561 $query_params = parent::get_collection_params(); 1562 1563 $query_params['context']['default'] = 'view'; 1564 1565 $query_params['exclude'] = array( 1566 'description' => __( 'Ensure result set excludes specific IDs.' ), 1567 'type' => 'array', 1568 'items' => array( 1569 'type' => 'integer', 1570 ), 1571 'default' => array(), 1572 ); 1573 1574 $query_params['include'] = array( 1575 'description' => __( 'Limit result set to specific IDs.' ), 1576 'type' => 'array', 1577 'items' => array( 1578 'type' => 'integer', 1579 ), 1580 'default' => array(), 1581 ); 1582 1583 $query_params['offset'] = array( 1584 'description' => __( 'Offset the result set by a specific number of items.' ), 1585 'type' => 'integer', 1586 ); 1587 1588 $query_params['order'] = array( 1589 'default' => 'asc', 1590 'description' => __( 'Order sort attribute ascending or descending.' ), 1591 'enum' => array( 'asc', 'desc' ), 1592 'type' => 'string', 1593 ); 1594 1595 $query_params['orderby'] = array( 1596 'default' => 'name', 1597 'description' => __( 'Sort collection by user attribute.' ), 1598 'enum' => array( 1599 'id', 1600 'include', 1601 'name', 1602 'registered_date', 1603 'slug', 1604 'include_slugs', 1605 'email', 1606 'url', 1607 ), 1608 'type' => 'string', 1609 ); 1610 1611 $query_params['slug'] = array( 1612 'description' => __( 'Limit result set to users with one or more specific slugs.' ), 1613 'type' => 'array', 1614 'items' => array( 1615 'type' => 'string', 1616 ), 1617 ); 1618 1619 $query_params['roles'] = array( 1620 'description' => __( 'Limit result set to users matching at least one specific role provided. Accepts csv list or single role.' ), 1621 'type' => 'array', 1622 'items' => array( 1623 'type' => 'string', 1624 ), 1625 ); 1626 1627 $query_params['capabilities'] = array( 1628 'description' => __( 'Limit result set to users matching at least one specific capability provided. Accepts csv list or single capability.' ), 1629 'type' => 'array', 1630 'items' => array( 1631 'type' => 'string', 1632 ), 1633 ); 1634 1635 $query_params['who'] = array( 1636 'description' => __( 'Limit result set to users who are considered authors.' ), 1637 'type' => 'string', 1638 'enum' => array( 1639 'authors', 1640 ), 1641 ); 1642 1643 $query_params['has_published_posts'] = array( 1644 'description' => __( 'Limit result set to users who have published posts.' ), 1645 'type' => array( 'boolean', 'array' ), 1646 'items' => array( 1647 'type' => 'string', 1648 'enum' => get_post_types( array( 'show_in_rest' => true ), 'names' ), 1649 ), 1650 ); 1651 1652 $query_params['search_columns'] = array( 1653 'default' => array(), 1654 'description' => __( 'Array of column names to be searched.' ), 1655 'type' => 'array', 1656 'items' => array( 1657 'enum' => array( 'email', 'name', 'id', 'username', 'slug' ), 1658 'type' => 'string', 1659 ), 1660 ); 1661 1662 /** 1663 * Filters REST API collection parameters for the users controller. 1664 * 1665 * This filter registers the collection parameter, but does not map the 1666 * collection parameter to an internal WP_User_Query parameter. Use the 1667 * `rest_user_query` filter to set WP_User_Query arguments. 1668 * 1669 * @since 4.7.0 1670 * 1671 * @param array $query_params JSON Schema-formatted collection parameters. 1672 */ 1673 return apply_filters( 'rest_user_collection_params', $query_params ); 1674 } 1675 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Sun Apr 27 08:20:01 2025 | Cross-referenced by PHPXref |