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