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