[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/rest-api/endpoints/ -> class-wp-rest-users-controller.php (source)

   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  }


Generated : Wed Apr 15 08:20:10 2026 Cross-referenced by PHPXref