[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

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

   1  <?php
   2  /**
   3   * REST API: WP_REST_Entity_Fields_Controller class
   4   *
   5   * @package    WordPress
   6   * @subpackage REST_API
   7   * @since      7.2.0
   8   */
   9  
  10  /**
  11   * Controller which provides a REST endpoint for retrieving the fields
  12   * registered for a given entity type.
  13   *
  14   * The fields are the ones registered on the server on the
  15   * `wp_entity_fields_api_init` action: the serializable part of each field, plus
  16   * the script modules that provide the JavaScript parts (render callbacks,
  17   * components, value getters and setters), each with the ids of the fields
  18   * it applies to. The client merges both into the fields it derives itself.
  19   *
  20   * @since 7.2.0
  21   *
  22   * @see WP_REST_Controller
  23   */
  24  class WP_REST_Entity_Fields_Controller extends WP_REST_Controller {
  25  
  26      /**
  27       * Constructor.
  28       *
  29       * @since 7.2.0
  30       */
  31  	public function __construct() {
  32          $this->namespace = 'wp/v2';
  33          $this->rest_base = 'entity-fields';
  34      }
  35  
  36      /**
  37       * Registers the routes for the controller.
  38       *
  39       * @since 7.2.0
  40       */
  41  	public function register_routes() {
  42          register_rest_route(
  43              $this->namespace,
  44              '/' . $this->rest_base,
  45              array(
  46                  array(
  47                      'methods'             => WP_REST_Server::READABLE,
  48                      'callback'            => array( $this, 'get_items' ),
  49                      'permission_callback' => array( $this, 'get_items_permissions_check' ),
  50                      'args'                => array(
  51                          'kind' => array(
  52                              'description' => __( 'Entity kind.' ),
  53                              'type'        => 'string',
  54                              'required'    => true,
  55                          ),
  56                          'name' => array(
  57                              'description' => __( 'Entity name.' ),
  58                              'type'        => 'string',
  59                              'required'    => true,
  60                          ),
  61                      ),
  62                  ),
  63                  'schema' => array( $this, 'get_public_item_schema' ),
  64              )
  65          );
  66      }
  67  
  68      /**
  69       * Checks if a given request has access to read the fields of an entity.
  70       *
  71       * @since 7.2.0
  72       *
  73       * @param WP_REST_Request $request Full details about the request.
  74       * @return true|WP_Error True if the request has read access, WP_Error object otherwise.
  75       */
  76  	public function get_items_permissions_check( $request ) {
  77          $kind = $request->get_param( 'kind' );
  78          $name = $request->get_param( 'name' );
  79  
  80          $capability = $this->get_required_capability( $kind, $name );
  81  
  82          if ( null === $capability ) {
  83              return new WP_Error(
  84                  'rest_entity_fields_invalid_entity',
  85                  __( 'Invalid entity kind or name.' ),
  86                  array( 'status' => 404 )
  87              );
  88          }
  89  
  90          if ( ! current_user_can( $capability ) ) {
  91              return new WP_Error(
  92                  'rest_cannot_read',
  93                  __( 'Sorry, you are not allowed to read the fields of this entity.' ),
  94                  array( 'status' => rest_authorization_required_code() )
  95              );
  96          }
  97  
  98          return true;
  99      }
 100  
 101      /**
 102       * Resolves the capability required to read the fields of an entity.
 103       *
 104       * Mirrors the view config endpoint, which gates the same entities: post
 105       * types use their own `edit_posts` capability (which honors custom
 106       * `capability_type` registrations), taxonomies use `manage_terms`, and
 107       * root-level entities use `manage_options`. A post type or taxonomy that is
 108       * not registered, or not exposed to the REST API, resolves to `null` so the
 109       * request is treated as referencing an unknown entity.
 110       *
 111       * Any other kind falls back to `edit_posts`, so fields registered for a
 112       * custom entity kind stay readable behind a baseline capability.
 113       *
 114       * @since 7.2.0
 115       *
 116       * @param string $kind The entity kind (e.g. `postType`).
 117       * @param string $name The entity name (e.g. `page`).
 118       * @return string|null Capability required to read the fields, or null if
 119       *                     the entity is not registered.
 120       */
 121  	protected function get_required_capability( $kind, $name ) {
 122          switch ( $kind ) {
 123              case 'postType':
 124                  $post_type = get_post_type_object( $name );
 125                  if ( $post_type && $post_type->show_in_rest ) {
 126                      return $post_type->cap->edit_posts;
 127                  }
 128                  return null;
 129  
 130              case 'taxonomy':
 131                  $taxonomy = get_taxonomy( $name );
 132                  if ( $taxonomy && $taxonomy->show_in_rest ) {
 133                      return $taxonomy->cap->manage_terms;
 134                  }
 135                  return null;
 136  
 137              case 'root':
 138                  return 'manage_options';
 139          }
 140  
 141          return 'edit_posts';
 142      }
 143  
 144      /**
 145       * Returns the fields registered for the given entity type.
 146       *
 147       * @since 7.2.0
 148       *
 149       * @param WP_REST_Request $request Full details about the request.
 150       * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
 151       */
 152  	public function get_items( $request ) {
 153          $kind = $request->get_param( 'kind' );
 154          $name = $request->get_param( 'name' );
 155  
 156          $field_schema = $this->get_field_schema();
 157          $fields       = array();
 158          foreach ( wp_get_registered_entity_fields( $kind, $name ) as $field ) {
 159              $fields[] = _rest_cast_empty_objects_from_schema( $field, $field_schema );
 160          }
 161  
 162          $script_modules = array();
 163          foreach ( wp_get_registered_entity_field_modules( $kind, $name ) as $module => $field_ids ) {
 164              $script_modules[] = array(
 165                  'id'     => $module,
 166                  'fields' => array_values( $field_ids ),
 167              );
 168          }
 169  
 170          $response = array(
 171              'kind'           => $kind,
 172              'name'           => $name,
 173              'fields'         => $fields,
 174              'script_modules' => $script_modules,
 175          );
 176  
 177          return rest_ensure_response( $response );
 178      }
 179  
 180      /**
 181       * Retrieves the item's schema, conforming to JSON Schema.
 182       *
 183       * @since 7.2.0
 184       *
 185       * @return array Item schema data.
 186       */
 187  	public function get_item_schema() {
 188          if ( $this->schema ) {
 189              return $this->add_additional_fields_schema( $this->schema );
 190          }
 191  
 192          $this->schema = array(
 193              '$schema'    => 'http://json-schema.org/draft-04/schema#',
 194              'title'      => 'entity-fields',
 195              'type'       => 'object',
 196              'properties' => array(
 197                  'kind'           => array(
 198                      'description' => __( 'Entity kind.' ),
 199                      'type'        => 'string',
 200                      'readonly'    => true,
 201                  ),
 202                  'name'           => array(
 203                      'description' => __( 'Entity name.' ),
 204                      'type'        => 'string',
 205                      'readonly'    => true,
 206                  ),
 207                  'fields'         => array(
 208                      'description' => __( 'The fields registered for the entity, in registration order.' ),
 209                      'type'        => 'array',
 210                      'readonly'    => true,
 211                      'items'       => $this->get_field_schema(),
 212                  ),
 213                  'script_modules' => array(
 214                      'description' => __( 'The script modules providing the JavaScript parts of the fields, each with the ids of the fields it applies to.' ),
 215                      'type'        => 'array',
 216                      'readonly'    => true,
 217                      'items'       => array(
 218                          'type'       => 'object',
 219                          'properties' => array(
 220                              'id'     => array(
 221                                  'description' => __( 'The id of the script module.' ),
 222                                  'type'        => 'string',
 223                              ),
 224                              'fields' => array(
 225                                  'description' => __( 'The ids of the fields the script module applies to.' ),
 226                                  'type'        => 'array',
 227                                  'items'       => array(
 228                                      'type' => 'string',
 229                                  ),
 230                              ),
 231                          ),
 232                      ),
 233                  ),
 234              ),
 235          );
 236  
 237          return $this->add_additional_fields_schema( $this->schema );
 238      }
 239  
 240      /**
 241       * Returns the schema for a field definition.
 242       *
 243       * Describes the serializable subset of the DataViews Field API, see
 244       * packages/dataviews/src/types/field-api.ts in Gutenberg. The properties
 245       * that are JavaScript callbacks or components (`render`, `sort`,
 246       * `getValue`, …) come from the script modules and are not part of the
 247       * definition.
 248       * Additional properties are allowed, so a plugin can register a field
 249       * with properties of its own that its script module understands.
 250       *
 251       * @since 7.2.0
 252       *
 253       * @return array Schema for a field definition.
 254       */
 255  	protected function get_field_schema() {
 256          $option_schema = array(
 257              'type'       => 'object',
 258              'properties' => array(
 259                  'value'       => array(
 260                      'description' => __( 'The value of the option.' ),
 261                      'type'        => array( 'string', 'integer', 'number', 'boolean', 'null' ),
 262                  ),
 263                  'label'       => array(
 264                      'description' => __( 'The label of the option.' ),
 265                      'type'        => 'string',
 266                  ),
 267                  'description' => array(
 268                      'description' => __( 'The description of the option.' ),
 269                      'type'        => 'string',
 270                  ),
 271              ),
 272          );
 273  
 274          return array(
 275              'type'                 => 'object',
 276              'properties'           => array(
 277                  'id'                 => array(
 278                      'description' => __( 'The unique identifier of the field.' ),
 279                      'type'        => 'string',
 280                  ),
 281                  'origin'             => array(
 282                      'description' => sprintf(
 283                          /* translators: %s: core */
 284                          __( 'Who registered and updated the field: %s, or the slug of a plugin or theme.' ),
 285                          'core'
 286                      ),
 287                      'type'        => 'object',
 288                      'properties'  => array(
 289                          'registeredBy' => array(
 290                              'description' => __( 'Who registered the field.' ),
 291                              'type'        => 'string',
 292                          ),
 293                          'updatedBy'    => array(
 294                              'description' => __( 'Who updated the field, in update order.' ),
 295                              'type'        => 'array',
 296                              'items'       => array(
 297                                  'type' => 'string',
 298                              ),
 299                          ),
 300                      ),
 301                  ),
 302                  'type'               => array(
 303                      'description' => __( 'The type of the field, one of the types DataViews provides a control for.' ),
 304                      'type'        => 'string',
 305                      'enum'        => array( 'array', 'boolean', 'color', 'date', 'datetime', 'email', 'integer', 'media', 'number', 'password', 'telephone', 'text', 'time', 'url' ),
 306                  ),
 307                  'label'              => array(
 308                      'description' => __( 'The label of the field.' ),
 309                      'type'        => 'string',
 310                  ),
 311                  'header'             => array(
 312                      'description' => __( 'The header of the field. Defaults to the label.' ),
 313                      'type'        => 'string',
 314                  ),
 315                  'description'        => array(
 316                      'description' => __( 'The description of the field.' ),
 317                      'type'        => 'string',
 318                  ),
 319                  'placeholder'        => array(
 320                      'description' => __( 'The placeholder of the field.' ),
 321                      'type'        => 'string',
 322                  ),
 323                  'Edit'               => array(
 324                      'description' => __( 'The control used to edit the field: the name of a control, or a control configuration.' ),
 325                      'type'        => array( 'string', 'object' ),
 326                  ),
 327                  'isValid'            => array(
 328                      'description' => __( 'The validation rules of the field.' ),
 329                      'type'        => 'object',
 330                  ),
 331                  'isDisabled'         => array(
 332                      'description' => __( 'Whether the field is disabled.' ),
 333                      'type'        => 'boolean',
 334                  ),
 335                  'enableSorting'      => array(
 336                      'description' => __( 'Whether the field is sortable.' ),
 337                      'type'        => 'boolean',
 338                  ),
 339                  'enableGlobalSearch' => array(
 340                      'description' => __( 'Whether the field is searchable.' ),
 341                      'type'        => 'boolean',
 342                  ),
 343                  'enableHiding'       => array(
 344                      'description' => __( 'Whether the field can be hidden.' ),
 345                      'type'        => 'boolean',
 346                  ),
 347                  'elements'           => array(
 348                      'description' => __( 'The options to pick from when using the field as a filter.' ),
 349                      'type'        => 'array',
 350                      'items'       => $option_schema,
 351                  ),
 352                  'filterBy'           => array(
 353                      'description' => __( 'The filter configuration of the field, or false when the field cannot be filtered.' ),
 354                      'type'        => array( 'object', 'boolean' ),
 355                      'properties'  => array(
 356                          'operators' => array(
 357                              'type'  => 'array',
 358                              'items' => array(
 359                                  'type' => 'string',
 360                                  'enum' => array(
 361                                      'is',
 362                                      'isNot',
 363                                      'isAny',
 364                                      'isNone',
 365                                      'isAll',
 366                                      'lessThan',
 367                                      'greaterThan',
 368                                      'lessThanOrEqual',
 369                                      'greaterThanOrEqual',
 370                                      'before',
 371                                      'after',
 372                                      'beforeInc',
 373                                      'afterInc',
 374                                      'contains',
 375                                      'notContains',
 376                                      'startsWith',
 377                                      'between',
 378                                      'on',
 379                                      'notOn',
 380                                      'inThePast',
 381                                      'over',
 382                                  ),
 383                              ),
 384                          ),
 385                          'isPrimary' => array(
 386                              'type' => 'boolean',
 387                          ),
 388                      ),
 389                  ),
 390                  'readOnly'           => array(
 391                      'description' => __( 'Whether the field is read only.' ),
 392                      'type'        => 'boolean',
 393                  ),
 394                  'format'             => array(
 395                      'description' => __( 'The display format of the field.' ),
 396                      'type'        => 'object',
 397                  ),
 398              ),
 399              'additionalProperties' => true,
 400          );
 401      }
 402  }


Generated : Tue Oct 20 08:20:34 2026 Cross-referenced by PHPXref