[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

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

   1  <?php
   2  /**
   3   * REST API: WP_REST_View_Config_Controller class
   4   *
   5   * @package    WordPress
   6   * @subpackage REST_API
   7   * @since      7.1.0
   8   */
   9  
  10  /**
  11   * Controller which provides a REST endpoint for retrieving the default
  12   * view configuration for a given entity type.
  13   *
  14   * @since 7.1.0
  15   *
  16   * @see WP_REST_Controller
  17   */
  18  class WP_REST_View_Config_Controller extends WP_REST_Controller {
  19  
  20      /**
  21       * Constructor.
  22       *
  23       * @since 7.1.0
  24       */
  25  	public function __construct() {
  26          $this->namespace = 'wp/v2';
  27          $this->rest_base = 'view-config';
  28      }
  29  
  30      /**
  31       * Registers the routes for the controller.
  32       *
  33       * @since 7.1.0
  34       */
  35  	public function register_routes() {
  36          register_rest_route(
  37              $this->namespace,
  38              '/' . $this->rest_base,
  39              array(
  40                  array(
  41                      'methods'             => WP_REST_Server::READABLE,
  42                      'callback'            => array( $this, 'get_items' ),
  43                      'permission_callback' => array( $this, 'get_items_permissions_check' ),
  44                      'args'                => array(
  45                          'kind' => array(
  46                              'description' => __( 'Entity kind.' ),
  47                              'type'        => 'string',
  48                              'required'    => true,
  49                          ),
  50                          'name' => array(
  51                              'description' => __( 'Entity name.' ),
  52                              'type'        => 'string',
  53                              'required'    => true,
  54                          ),
  55                      ),
  56                  ),
  57                  'schema' => array( $this, 'get_public_item_schema' ),
  58              )
  59          );
  60      }
  61  
  62      /**
  63       * Checks if a given request has access to read view config.
  64       *
  65       * @since 7.1.0
  66       *
  67       * @param WP_REST_Request $request Full details about the request.
  68       * @return true|WP_Error True if the request has read access, WP_Error object otherwise.
  69       */
  70  	public function get_items_permissions_check( $request ) {
  71          $kind = $request->get_param( 'kind' );
  72          $name = $request->get_param( 'name' );
  73  
  74          $capability = $this->get_required_capability( $kind, $name );
  75  
  76          if ( null === $capability ) {
  77              return new WP_Error(
  78                  'rest_view_config_invalid_entity',
  79                  __( 'Invalid entity kind or name.' ),
  80                  array( 'status' => 404 )
  81              );
  82          }
  83  
  84          if ( ! current_user_can( $capability ) ) {
  85              return new WP_Error(
  86                  'rest_cannot_read',
  87                  __( 'Sorry, you are not allowed to read view config.' ),
  88                  array( 'status' => rest_authorization_required_code() )
  89              );
  90          }
  91  
  92          return true;
  93      }
  94  
  95      /**
  96       * Resolves the capability required to read the view config for an entity.
  97       *
  98       * Known kinds map to the capability that gates managing that entity's list:
  99       * post types use their own `edit_posts` capability (which honors custom
 100       * `capability_type` registrations), taxonomies use `manage_terms`, and
 101       * root-level entities use `manage_options`. A post type or taxonomy that is
 102       * not registered, or not exposed to the REST API, resolves to `null` so the
 103       * request is treated as referencing an unknown entity.
 104       *
 105       * Any other kind falls back to `edit_posts`. This keeps entities registered
 106       * through the `get_entity_view_config_{$kind}_{$name}` filter readable behind
 107       * a baseline capability.
 108       *
 109       * @since 7.1.0
 110       *
 111       * @param string $kind The entity kind (e.g. `postType`).
 112       * @param string $name The entity name (e.g. `page`).
 113       * @return string|null Capability required to read the config, or null if the
 114       *                     entity is not registered.
 115       */
 116  	protected function get_required_capability( $kind, $name ) {
 117          switch ( $kind ) {
 118              case 'postType':
 119                  $post_type = get_post_type_object( $name );
 120                  if ( $post_type && $post_type->show_in_rest ) {
 121                      return $post_type->cap->edit_posts;
 122                  }
 123                  return null;
 124  
 125              case 'taxonomy':
 126                  $taxonomy = get_taxonomy( $name );
 127                  if ( $taxonomy && $taxonomy->show_in_rest ) {
 128                      return $taxonomy->cap->manage_terms;
 129                  }
 130                  return null;
 131  
 132              case 'root':
 133                  return 'manage_options';
 134          }
 135  
 136          return 'edit_posts';
 137      }
 138  
 139      /**
 140       * Returns the default view configuration for the given entity type.
 141       *
 142       * @since 7.1.0
 143       *
 144       * @param WP_REST_Request $request Full details about the request.
 145       * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
 146       */
 147  	public function get_items( $request ) {
 148          $kind = $request->get_param( 'kind' );
 149          $name = $request->get_param( 'name' );
 150  
 151          $config = wp_get_entity_view_config( $kind, $name );
 152          $schema = $this->get_item_schema();
 153  
 154          $response = array(
 155              'kind'            => $kind,
 156              'name'            => $name,
 157              'version'         => WP_View_Config_Data::LATEST_VERSION,
 158              'default_view'    => $this->cast_empty_objects( $config['default_view'], $schema['properties']['default_view'] ),
 159              'default_layouts' => $this->cast_empty_objects( $config['default_layouts'], $schema['properties']['default_layouts'] ),
 160              'view_list'       => $this->cast_empty_objects( $config['view_list'], $schema['properties']['view_list'] ),
 161              'form'            => $this->cast_empty_objects( $config['form'], $schema['properties']['form'] ),
 162          );
 163  
 164          return rest_ensure_response( $response );
 165      }
 166  
 167      /**
 168       * Recursively casts empty arrays to objects where the schema types them as
 169       * objects.
 170       *
 171       * PHP cannot distinguish an empty associative array from an empty list, so
 172       * `json_encode()` always serializes `array()` as a JSON array (`[]`). The
 173       * REST schema, however, types several values as objects, which must encode
 174       * as `{}`. This walks the value against its schema and casts any empty,
 175       * object-typed array to an object. Non-empty associative arrays already
 176       * encode as objects, so they are left as arrays and only recursed into to
 177       * fix any nested empty objects.
 178       *
 179       * Union schemas (`oneOf`/`anyOf`) are handled only for the empty-array case:
 180       * an empty value is cast to an object when any branch allows an object. Such
 181       * values are not recursed into, which is sufficient for the form schema
 182       * where they never contain empty nested objects.
 183       *
 184       * @since 7.1.0
 185       *
 186       * @param mixed $value  The value to normalize.
 187       * @param array $schema The schema node describing the value.
 188       * @return mixed The normalized value, with empty object-typed arrays cast to objects.
 189       */
 190  	protected function cast_empty_objects( $value, $schema ) {
 191          if ( ! is_array( $value ) || ! is_array( $schema ) ) {
 192              return $value;
 193          }
 194  
 195          if ( isset( $schema['oneOf'] ) || isset( $schema['anyOf'] ) ) {
 196              $branches = $schema['oneOf'] ?? $schema['anyOf'];
 197              if ( array() === $value ) {
 198                  foreach ( $branches as $branch ) {
 199                      if ( is_array( $branch ) && in_array( 'object', (array) ( $branch['type'] ?? array() ), true ) ) {
 200                          return (object) array();
 201                      }
 202                  }
 203              }
 204              return $value;
 205          }
 206  
 207          $types = (array) ( $schema['type'] ?? array() );
 208  
 209          if ( in_array( 'array', $types, true ) && isset( $schema['items'] ) ) {
 210              foreach ( $value as $index => $item ) {
 211                  $value[ $index ] = $this->cast_empty_objects( $item, $schema['items'] );
 212              }
 213              return $value;
 214          }
 215  
 216          if ( in_array( 'object', $types, true ) ) {
 217              if ( isset( $schema['properties'] ) ) {
 218                  foreach ( $schema['properties'] as $property => $property_schema ) {
 219                      if ( array_key_exists( $property, $value ) ) {
 220                          $value[ $property ] = $this->cast_empty_objects( $value[ $property ], $property_schema );
 221                      }
 222                  }
 223              }
 224              if ( isset( $schema['additionalProperties'] ) && is_array( $schema['additionalProperties'] ) ) {
 225                  foreach ( $value as $key => $item ) {
 226                      if ( isset( $schema['properties'][ $key ] ) ) {
 227                          continue;
 228                      }
 229                      $value[ $key ] = $this->cast_empty_objects( $item, $schema['additionalProperties'] );
 230                  }
 231              }
 232  
 233              // Empty object-typed arrays must serialize as {} to match the schema.
 234              if ( array() === $value ) {
 235                  return (object) array();
 236              }
 237          }
 238  
 239          return $value;
 240      }
 241  
 242      /**
 243       * Retrieves the item's schema, conforming to JSON Schema.
 244       *
 245       * @since 7.1.0
 246       *
 247       * @return array Item schema data.
 248       */
 249  	public function get_item_schema() {
 250          if ( $this->schema ) {
 251              return $this->add_additional_fields_schema( $this->schema );
 252          }
 253  
 254          $view_base_properties = $this->get_view_base_schema();
 255  
 256          $this->schema = array(
 257              '$schema'    => 'http://json-schema.org/draft-04/schema#',
 258              'title'      => 'view-config',
 259              'type'       => 'object',
 260              'properties' => array(
 261                  'kind'            => array(
 262                      'description' => __( 'Entity kind.' ),
 263                      'type'        => 'string',
 264                      'readonly'    => true,
 265                  ),
 266                  'name'            => array(
 267                      'description' => __( 'Entity name.' ),
 268                      'type'        => 'string',
 269                      'readonly'    => true,
 270                  ),
 271                  'version'         => array(
 272                      'description' => __( 'The schema version of the configuration.' ),
 273                      'type'        => 'integer',
 274                      'readonly'    => true,
 275                  ),
 276                  'default_view'    => array(
 277                      'description' => __( 'Default view configuration.' ),
 278                      'type'        => 'object',
 279                      'readonly'    => true,
 280                      'properties'  => array_merge(
 281                          array(
 282                              'type'   => array(
 283                                  'type' => 'string',
 284                              ),
 285                              'layout' => $this->get_combined_layout_schema(),
 286                          ),
 287                          $view_base_properties
 288                      ),
 289                  ),
 290                  'default_layouts' => array(
 291                      'description' => __( 'Default layout configurations.' ),
 292                      'type'        => 'object',
 293                      'readonly'    => true,
 294                      'properties'  => array(
 295                          'table'       => array(
 296                              'type'       => 'object',
 297                              'properties' => array_merge(
 298                                  $view_base_properties,
 299                                  array(
 300                                      'layout' => $this->get_table_layout_schema(),
 301                                  )
 302                              ),
 303                          ),
 304                          'list'        => array(
 305                              'type'       => 'object',
 306                              'properties' => array_merge(
 307                                  $view_base_properties,
 308                                  array(
 309                                      'layout' => $this->get_list_layout_schema(),
 310                                  )
 311                              ),
 312                          ),
 313                          'grid'        => array(
 314                              'type'       => 'object',
 315                              'properties' => array_merge(
 316                                  $view_base_properties,
 317                                  array(
 318                                      'layout' => $this->get_grid_layout_schema(),
 319                                  )
 320                              ),
 321                          ),
 322                          'activity'    => array(
 323                              'type'       => 'object',
 324                              'properties' => array_merge(
 325                                  $view_base_properties,
 326                                  array(
 327                                      'layout' => $this->get_list_layout_schema(),
 328                                  )
 329                              ),
 330                          ),
 331                          'pickerGrid'  => array(
 332                              'type'       => 'object',
 333                              'properties' => array_merge(
 334                                  $view_base_properties,
 335                                  array(
 336                                      'layout' => $this->get_grid_layout_schema(),
 337                                  )
 338                              ),
 339                          ),
 340                          'pickerTable' => array(
 341                              'type'       => 'object',
 342                              'properties' => array_merge(
 343                                  $view_base_properties,
 344                                  array(
 345                                      'layout' => $this->get_table_layout_schema(),
 346                                  )
 347                              ),
 348                          ),
 349                      ),
 350                  ),
 351                  'view_list'       => array(
 352                      'description' => __( 'List of default views.' ),
 353                      'type'        => 'array',
 354                      'readonly'    => true,
 355                      'items'       => array(
 356                          'type'       => 'object',
 357                          'properties' => array(
 358                              'title' => array(
 359                                  'type' => 'string',
 360                              ),
 361                              'slug'  => array(
 362                                  'type' => 'string',
 363                              ),
 364                              'view'  => array(
 365                                  'type'       => 'object',
 366                                  'properties' => array_merge(
 367                                      array(
 368                                          'type'   => array(
 369                                              'type' => 'string',
 370                                          ),
 371                                          'layout' => $this->get_combined_layout_schema(),
 372                                      ),
 373                                      $view_base_properties
 374                                  ),
 375                              ),
 376                          ),
 377                      ),
 378                  ),
 379                  'form'            => array(
 380                      'description' => __( 'Default form configuration.' ),
 381                      'type'        => 'object',
 382                      'readonly'    => true,
 383                      'properties'  => $this->get_form_schema(),
 384                  ),
 385              ),
 386          );
 387  
 388          return $this->add_additional_fields_schema( $this->schema );
 389      }
 390  
 391      /**
 392       * Returns the schema properties shared by all view types (ViewBase), excluding 'type'.
 393       *
 394       * Note that `search` and `page` are not part of the schema: they are managed
 395       * via the URL, which is their only source of truth.
 396       *
 397       * @since 7.1.0
 398       *
 399       * @return array Schema properties for the base view configuration.
 400       */
 401  	protected function get_view_base_schema() {
 402          return array(
 403              'filters'               => array(
 404                  'type'  => 'array',
 405                  'items' => array(
 406                      'type'       => 'object',
 407                      'properties' => array(
 408                          'field'    => array(
 409                              'type' => 'string',
 410                          ),
 411                          'operator' => array(
 412                              'type' => 'string',
 413                              'enum' => array(
 414                                  'is',
 415                                  'isNot',
 416                                  'isAny',
 417                                  'isNone',
 418                                  'isAll',
 419                                  'isNotAll',
 420                                  'lessThan',
 421                                  'greaterThan',
 422                                  'lessThanOrEqual',
 423                                  'greaterThanOrEqual',
 424                                  'before',
 425                                  'after',
 426                              ),
 427                          ),
 428                          'value'    => array(),
 429                          'isLocked' => array(
 430                              'type' => 'boolean',
 431                          ),
 432                      ),
 433                  ),
 434              ),
 435              'sort'                  => array(
 436                  'type'       => 'object',
 437                  'properties' => array(
 438                      'field'     => array(
 439                          'type' => 'string',
 440                      ),
 441                      'direction' => array(
 442                          'type' => 'string',
 443                          'enum' => array( 'asc', 'desc' ),
 444                      ),
 445                  ),
 446              ),
 447              'perPage'               => array(
 448                  'type' => 'integer',
 449              ),
 450              'fields'                => array(
 451                  'type'  => 'array',
 452                  'items' => array(
 453                      'type' => 'string',
 454                  ),
 455              ),
 456              'titleField'            => array(
 457                  'type' => 'string',
 458              ),
 459              'mediaField'            => array(
 460                  'type' => 'string',
 461              ),
 462              'descriptionField'      => array(
 463                  'type' => 'string',
 464              ),
 465              'showTitle'             => array(
 466                  'type' => 'boolean',
 467              ),
 468              'showMedia'             => array(
 469                  'type' => 'boolean',
 470              ),
 471              'showDescription'       => array(
 472                  'type' => 'boolean',
 473              ),
 474              'showLevels'            => array(
 475                  'type' => 'boolean',
 476              ),
 477              'groupBy'               => array(
 478                  'type'       => 'object',
 479                  'properties' => array(
 480                      'field'     => array(
 481                          'type' => 'string',
 482                      ),
 483                      'direction' => array(
 484                          'type' => 'string',
 485                          'enum' => array( 'asc', 'desc' ),
 486                      ),
 487                      'showLabel' => array(
 488                          'type'    => 'boolean',
 489                          'default' => true,
 490                      ),
 491                  ),
 492              ),
 493              'infiniteScrollEnabled' => array(
 494                  'type' => 'boolean',
 495              ),
 496          );
 497      }
 498  
 499      /**
 500       * Returns the schema for the ColumnStyle type.
 501       *
 502       * @since 7.1.0
 503       *
 504       * @return array Schema for a column style object.
 505       */
 506  	protected function get_column_style_schema() {
 507          return array(
 508              'type'       => 'object',
 509              'properties' => array(
 510                  'width'    => array(
 511                      'type' => array( 'string', 'number' ),
 512                  ),
 513                  'maxWidth' => array(
 514                      'type' => array( 'string', 'number' ),
 515                  ),
 516                  'minWidth' => array(
 517                      'type' => array( 'string', 'number' ),
 518                  ),
 519                  'align'    => array(
 520                      'type' => 'string',
 521                      'enum' => array( 'start', 'center', 'end' ),
 522                  ),
 523              ),
 524          );
 525      }
 526  
 527      /**
 528       * Returns the layout schema for table-type views (ViewTable, ViewPickerTable).
 529       *
 530       * @since 7.1.0
 531       *
 532       * @return array Schema for a table layout object.
 533       */
 534  	protected function get_table_layout_schema() {
 535          return array(
 536              'type'       => 'object',
 537              'properties' => array(
 538                  'styles'       => array(
 539                      'type'                 => 'object',
 540                      'additionalProperties' => $this->get_column_style_schema(),
 541                  ),
 542                  'density'      => array(
 543                      'type' => 'string',
 544                      'enum' => array( 'compact', 'balanced', 'comfortable' ),
 545                  ),
 546                  'enableMoving' => array(
 547                      'type' => 'boolean',
 548                  ),
 549              ),
 550          );
 551      }
 552  
 553      /**
 554       * Returns the layout schema for list-type views (ViewList, ViewActivity).
 555       *
 556       * @since 7.1.0
 557       *
 558       * @return array Schema for a list layout object.
 559       */
 560  	protected function get_list_layout_schema() {
 561          return array(
 562              'type'       => 'object',
 563              'properties' => array(
 564                  'density' => array(
 565                      'type' => 'string',
 566                      'enum' => array( 'compact', 'balanced', 'comfortable' ),
 567                  ),
 568              ),
 569          );
 570      }
 571  
 572      /**
 573       * Returns a combined layout schema that accepts properties from all view types.
 574       *
 575       * This is useful for contexts where the view type is not known ahead of time
 576       * (e.g. the `view` override in a view list item), so all possible layout
 577       * properties must be accepted.
 578       *
 579       * @since 7.1.0
 580       *
 581       * @return array Schema for a combined layout object.
 582       */
 583  	protected function get_combined_layout_schema() {
 584          return array(
 585              'type'       => 'object',
 586              'properties' => array_merge(
 587                  $this->get_table_layout_schema()['properties'],
 588                  $this->get_grid_layout_schema()['properties'],
 589                  $this->get_list_layout_schema()['properties']
 590              ),
 591          );
 592      }
 593  
 594      /**
 595       * Returns the layout schema for grid-type views (ViewGrid, ViewPickerGrid).
 596       *
 597       * @since 7.1.0
 598       *
 599       * @return array Schema for a grid layout object.
 600       */
 601  	protected function get_grid_layout_schema() {
 602          return array(
 603              'type'       => 'object',
 604              'properties' => array(
 605                  'badgeFields' => array(
 606                      'type'  => 'array',
 607                      'items' => array(
 608                          'type' => 'string',
 609                      ),
 610                  ),
 611                  'previewSize' => array(
 612                      'type' => 'number',
 613                  ),
 614                  'density'     => array(
 615                      'type' => 'string',
 616                      'enum' => array( 'compact', 'balanced', 'comfortable' ),
 617                  ),
 618              ),
 619          );
 620      }
 621  
 622      /**
 623       * Returns the schema for a form layout object as a discriminated union.
 624       *
 625       * Each variant is discriminated by a single-value enum on its `type` property,
 626       * matching the TypeScript Layout union in dataviews/src/types/dataform.ts.
 627       *
 628       * @since 7.1.0
 629       *
 630       * @return array Schema for a form layout object.
 631       */
 632  	protected function get_form_layout_schema() {
 633          return array(
 634              'oneOf' => array(
 635                  // RegularLayout.
 636                  array(
 637                      'type'       => 'object',
 638                      'properties' => array(
 639                          'type'          => array(
 640                              'type' => 'string',
 641                              'enum' => array( 'regular' ),
 642                          ),
 643                          'labelPosition' => array(
 644                              'type' => 'string',
 645                              'enum' => array( 'top', 'side', 'none' ),
 646                          ),
 647                      ),
 648                  ),
 649                  // PanelLayout.
 650                  array(
 651                      'type'       => 'object',
 652                      'properties' => array(
 653                          'type'           => array(
 654                              'type' => 'string',
 655                              'enum' => array( 'panel' ),
 656                          ),
 657                          'labelPosition'  => array(
 658                              'type' => 'string',
 659                              'enum' => array( 'top', 'side', 'none' ),
 660                          ),
 661                          'openAs'         => array(
 662                              'oneOf' => array(
 663                                  array(
 664                                      'type' => 'string',
 665                                      'enum' => array( 'dropdown', 'modal' ),
 666                                  ),
 667                                  array(
 668                                      'type'       => 'object',
 669                                      'properties' => array(
 670                                          'type'        => array(
 671                                              'type' => 'string',
 672                                              'enum' => array( 'dropdown', 'modal' ),
 673                                          ),
 674                                          'applyLabel'  => array(
 675                                              'type' => 'string',
 676                                          ),
 677                                          'cancelLabel' => array(
 678                                              'type' => 'string',
 679                                          ),
 680                                      ),
 681                                  ),
 682                              ),
 683                          ),
 684                          'summary'        => array(
 685                              'oneOf' => array(
 686                                  array( 'type' => 'string' ),
 687                                  array(
 688                                      'type'  => 'array',
 689                                      'items' => array(
 690                                          'type' => 'string',
 691                                      ),
 692                                  ),
 693                              ),
 694                          ),
 695                          'editVisibility' => array(
 696                              'type' => 'string',
 697                              'enum' => array( 'always', 'on-hover' ),
 698                          ),
 699                      ),
 700                  ),
 701                  // CardLayout.
 702                  array(
 703                      'type'       => 'object',
 704                      'properties' => array(
 705                          'type'          => array(
 706                              'type' => 'string',
 707                              'enum' => array( 'card' ),
 708                          ),
 709                          'withHeader'    => array(
 710                              'type' => 'boolean',
 711                          ),
 712                          'isOpened'      => array(
 713                              'type' => 'boolean',
 714                          ),
 715                          'isCollapsible' => array(
 716                              'type' => 'boolean',
 717                          ),
 718                          'summary'       => array(
 719                              'oneOf' => array(
 720                                  array( 'type' => 'string' ),
 721                                  array(
 722                                      'type'  => 'array',
 723                                      'items' => array(
 724                                          'oneOf' => array(
 725                                              array( 'type' => 'string' ),
 726                                              array(
 727                                                  'type' => 'object',
 728                                                  'properties' => array(
 729                                                      'id' => array(
 730                                                          'type' => 'string',
 731                                                      ),
 732                                                      'visibility' => array(
 733                                                          'type' => 'string',
 734                                                          'enum' => array( 'always', 'when-collapsed' ),
 735                                                      ),
 736                                                  ),
 737                                              ),
 738                                          ),
 739                                      ),
 740                                  ),
 741                              ),
 742                          ),
 743                      ),
 744                  ),
 745                  // RowLayout.
 746                  array(
 747                      'type'       => 'object',
 748                      'properties' => array(
 749                          'type'      => array(
 750                              'type' => 'string',
 751                              'enum' => array( 'row' ),
 752                          ),
 753                          'alignment' => array(
 754                              'type' => 'string',
 755                              'enum' => array( 'start', 'center', 'end' ),
 756                          ),
 757                          'styles'    => array(
 758                              'type'                 => 'object',
 759                              'additionalProperties' => array(
 760                                  'type'       => 'object',
 761                                  'properties' => array(
 762                                      'flex' => array(
 763                                          'type' => array( 'string', 'number' ),
 764                                      ),
 765                                  ),
 766                              ),
 767                          ),
 768                      ),
 769                  ),
 770                  // DetailsLayout.
 771                  array(
 772                      'type'       => 'object',
 773                      'properties' => array(
 774                          'type'    => array(
 775                              'type' => 'string',
 776                              'enum' => array( 'details' ),
 777                          ),
 778                          'summary' => array(
 779                              'type' => 'string',
 780                          ),
 781                      ),
 782                  ),
 783              ),
 784          );
 785      }
 786  
 787      /**
 788       * Returns the schema for a form field item (string or object).
 789       *
 790       * @since 7.1.0
 791       *
 792       * @return array Schema for a form field.
 793       */
 794  	protected function get_form_field_schema() {
 795          return array(
 796              'oneOf' => array(
 797                  array( 'type' => 'string' ),
 798                  array(
 799                      'type'       => 'object',
 800                      'properties' => array(
 801                          'id'          => array(
 802                              'type' => 'string',
 803                          ),
 804                          'label'       => array(
 805                              'type' => 'string',
 806                          ),
 807                          'description' => array(
 808                              'type' => 'string',
 809                          ),
 810                          'layout'      => $this->get_form_layout_schema(),
 811                          'children'    => array(
 812                              'type'  => 'array',
 813                              'items' => array(
 814                                  'oneOf' => array(
 815                                      array( 'type' => 'string' ),
 816                                      // This object can have the shape of a form field itself,
 817                                      // allowing for recursive nesting of form fields.
 818                                      // There's no easy way to codify this recursion via the JSON Schema draft-04
 819                                      // supported by the REST API.
 820                                      array( 'type' => 'object' ),
 821                                  ),
 822                              ),
 823                          ),
 824                      ),
 825                  ),
 826              ),
 827          );
 828      }
 829  
 830      /**
 831       * Returns the schema for the form configuration object.
 832       *
 833       * @since 7.1.0
 834       *
 835       * @return array Schema properties for the form configuration.
 836       */
 837  	protected function get_form_schema() {
 838          return array(
 839              'layout' => $this->get_form_layout_schema(),
 840              'fields' => array(
 841                  'type'  => 'array',
 842                  'items' => $this->get_form_field_schema(),
 843              ),
 844          );
 845      }
 846  }


Generated : Tue Aug 4 08:20:20 2026 Cross-referenced by PHPXref