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