[ 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 = isset( $schema['oneOf'] ) ? $schema['oneOf'] : $schema['anyOf'];
 197              if ( array() === $value ) {
 198                  foreach ( $branches as $branch ) {
 199                      if ( is_array( $branch ) && in_array( 'object', (array) ( isset( $branch['type'] ) ? $branch['type'] : array() ), true ) ) {
 200                          return (object) array();
 201                      }
 202                  }
 203              }
 204              return $value;
 205          }
 206  
 207          $types = (array) ( isset( $schema['type'] ) ? $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       * @since 7.1.0
 395       *
 396       * @return array Schema properties for the base view configuration.
 397       */
 398  	protected function get_view_base_schema() {
 399          return array(
 400              'search'                => array(
 401                  'type' => 'string',
 402              ),
 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              'page'                  => array(
 448                  'type' => 'integer',
 449              ),
 450              'perPage'               => array(
 451                  'type' => 'integer',
 452              ),
 453              'fields'                => array(
 454                  'type'  => 'array',
 455                  'items' => array(
 456                      'type' => 'string',
 457                  ),
 458              ),
 459              'titleField'            => array(
 460                  'type' => 'string',
 461              ),
 462              'mediaField'            => array(
 463                  'type' => 'string',
 464              ),
 465              'descriptionField'      => array(
 466                  'type' => 'string',
 467              ),
 468              'showTitle'             => array(
 469                  'type' => 'boolean',
 470              ),
 471              'showMedia'             => array(
 472                  'type' => 'boolean',
 473              ),
 474              'showDescription'       => array(
 475                  'type' => 'boolean',
 476              ),
 477              'showLevels'            => array(
 478                  'type' => 'boolean',
 479              ),
 480              'groupBy'               => array(
 481                  'type'       => 'object',
 482                  'properties' => array(
 483                      'field'     => array(
 484                          'type' => 'string',
 485                      ),
 486                      'direction' => array(
 487                          'type' => 'string',
 488                          'enum' => array( 'asc', 'desc' ),
 489                      ),
 490                      'showLabel' => array(
 491                          'type'    => 'boolean',
 492                          'default' => true,
 493                      ),
 494                  ),
 495              ),
 496              'infiniteScrollEnabled' => array(
 497                  'type' => 'boolean',
 498              ),
 499          );
 500      }
 501  
 502      /**
 503       * Returns the schema for the ColumnStyle type.
 504       *
 505       * @since 7.1.0
 506       *
 507       * @return array Schema for a column style object.
 508       */
 509  	protected function get_column_style_schema() {
 510          return array(
 511              'type'       => 'object',
 512              'properties' => array(
 513                  'width'    => array(
 514                      'type' => array( 'string', 'number' ),
 515                  ),
 516                  'maxWidth' => array(
 517                      'type' => array( 'string', 'number' ),
 518                  ),
 519                  'minWidth' => array(
 520                      'type' => array( 'string', 'number' ),
 521                  ),
 522                  'align'    => array(
 523                      'type' => 'string',
 524                      'enum' => array( 'start', 'center', 'end' ),
 525                  ),
 526              ),
 527          );
 528      }
 529  
 530      /**
 531       * Returns the layout schema for table-type views (ViewTable, ViewPickerTable).
 532       *
 533       * @since 7.1.0
 534       *
 535       * @return array Schema for a table layout object.
 536       */
 537  	protected function get_table_layout_schema() {
 538          return array(
 539              'type'       => 'object',
 540              'properties' => array(
 541                  'styles'       => array(
 542                      'type'                 => 'object',
 543                      'additionalProperties' => $this->get_column_style_schema(),
 544                  ),
 545                  'density'      => array(
 546                      'type' => 'string',
 547                      'enum' => array( 'compact', 'balanced', 'comfortable' ),
 548                  ),
 549                  'enableMoving' => array(
 550                      'type' => 'boolean',
 551                  ),
 552              ),
 553          );
 554      }
 555  
 556      /**
 557       * Returns the layout schema for list-type views (ViewList, ViewActivity).
 558       *
 559       * @since 7.1.0
 560       *
 561       * @return array Schema for a list layout object.
 562       */
 563  	protected function get_list_layout_schema() {
 564          return array(
 565              'type'       => 'object',
 566              'properties' => array(
 567                  'density' => array(
 568                      'type' => 'string',
 569                      'enum' => array( 'compact', 'balanced', 'comfortable' ),
 570                  ),
 571              ),
 572          );
 573      }
 574  
 575      /**
 576       * Returns a combined layout schema that accepts properties from all view types.
 577       *
 578       * This is useful for contexts where the view type is not known ahead of time
 579       * (e.g. the `view` override in a view list item), so all possible layout
 580       * properties must be accepted.
 581       *
 582       * @since 7.1.0
 583       *
 584       * @return array Schema for a combined layout object.
 585       */
 586  	protected function get_combined_layout_schema() {
 587          return array(
 588              'type'       => 'object',
 589              'properties' => array_merge(
 590                  $this->get_table_layout_schema()['properties'],
 591                  $this->get_grid_layout_schema()['properties'],
 592                  $this->get_list_layout_schema()['properties']
 593              ),
 594          );
 595      }
 596  
 597      /**
 598       * Returns the layout schema for grid-type views (ViewGrid, ViewPickerGrid).
 599       *
 600       * @since 7.1.0
 601       *
 602       * @return array Schema for a grid layout object.
 603       */
 604  	protected function get_grid_layout_schema() {
 605          return array(
 606              'type'       => 'object',
 607              'properties' => array(
 608                  'badgeFields' => array(
 609                      'type'  => 'array',
 610                      'items' => array(
 611                          'type' => 'string',
 612                      ),
 613                  ),
 614                  'previewSize' => array(
 615                      'type' => 'number',
 616                  ),
 617                  'density'     => array(
 618                      'type' => 'string',
 619                      'enum' => array( 'compact', 'balanced', 'comfortable' ),
 620                  ),
 621              ),
 622          );
 623      }
 624  
 625      /**
 626       * Returns the schema for a form layout object as a discriminated union.
 627       *
 628       * Each variant is discriminated by a single-value enum on its `type` property,
 629       * matching the TypeScript Layout union in dataviews/src/types/dataform.ts.
 630       *
 631       * @since 7.1.0
 632       *
 633       * @return array Schema for a form layout object.
 634       */
 635  	protected function get_form_layout_schema() {
 636          return array(
 637              'oneOf' => array(
 638                  // RegularLayout.
 639                  array(
 640                      'type'       => 'object',
 641                      'properties' => array(
 642                          'type'          => array(
 643                              'type' => 'string',
 644                              'enum' => array( 'regular' ),
 645                          ),
 646                          'labelPosition' => array(
 647                              'type' => 'string',
 648                              'enum' => array( 'top', 'side', 'none' ),
 649                          ),
 650                      ),
 651                  ),
 652                  // PanelLayout.
 653                  array(
 654                      'type'       => 'object',
 655                      'properties' => array(
 656                          'type'           => array(
 657                              'type' => 'string',
 658                              'enum' => array( 'panel' ),
 659                          ),
 660                          'labelPosition'  => array(
 661                              'type' => 'string',
 662                              'enum' => array( 'top', 'side', 'none' ),
 663                          ),
 664                          'openAs'         => array(
 665                              'oneOf' => array(
 666                                  array(
 667                                      'type' => 'string',
 668                                      'enum' => array( 'dropdown', 'modal' ),
 669                                  ),
 670                                  array(
 671                                      'type'       => 'object',
 672                                      'properties' => array(
 673                                          'type'        => array(
 674                                              'type' => 'string',
 675                                              'enum' => array( 'dropdown', 'modal' ),
 676                                          ),
 677                                          'applyLabel'  => array(
 678                                              'type' => 'string',
 679                                          ),
 680                                          'cancelLabel' => array(
 681                                              'type' => 'string',
 682                                          ),
 683                                      ),
 684                                  ),
 685                              ),
 686                          ),
 687                          'summary'        => array(
 688                              'oneOf' => array(
 689                                  array( 'type' => 'string' ),
 690                                  array(
 691                                      'type'  => 'array',
 692                                      'items' => array(
 693                                          'type' => 'string',
 694                                      ),
 695                                  ),
 696                              ),
 697                          ),
 698                          'editVisibility' => array(
 699                              'type' => 'string',
 700                              'enum' => array( 'always', 'on-hover' ),
 701                          ),
 702                      ),
 703                  ),
 704                  // CardLayout.
 705                  array(
 706                      'type'       => 'object',
 707                      'properties' => array(
 708                          'type'          => array(
 709                              'type' => 'string',
 710                              'enum' => array( 'card' ),
 711                          ),
 712                          'withHeader'    => array(
 713                              'type' => 'boolean',
 714                          ),
 715                          'isOpened'      => array(
 716                              'type' => 'boolean',
 717                          ),
 718                          'isCollapsible' => array(
 719                              'type' => 'boolean',
 720                          ),
 721                          'summary'       => array(
 722                              'oneOf' => array(
 723                                  array( 'type' => 'string' ),
 724                                  array(
 725                                      'type'  => 'array',
 726                                      'items' => array(
 727                                          'oneOf' => array(
 728                                              array( 'type' => 'string' ),
 729                                              array(
 730                                                  'type' => 'object',
 731                                                  'properties' => array(
 732                                                      'id' => array(
 733                                                          'type' => 'string',
 734                                                      ),
 735                                                      'visibility' => array(
 736                                                          'type' => 'string',
 737                                                          'enum' => array( 'always', 'when-collapsed' ),
 738                                                      ),
 739                                                  ),
 740                                              ),
 741                                          ),
 742                                      ),
 743                                  ),
 744                              ),
 745                          ),
 746                      ),
 747                  ),
 748                  // RowLayout.
 749                  array(
 750                      'type'       => 'object',
 751                      'properties' => array(
 752                          'type'      => array(
 753                              'type' => 'string',
 754                              'enum' => array( 'row' ),
 755                          ),
 756                          'alignment' => array(
 757                              'type' => 'string',
 758                              'enum' => array( 'start', 'center', 'end' ),
 759                          ),
 760                          'styles'    => array(
 761                              'type'                 => 'object',
 762                              'additionalProperties' => array(
 763                                  'type'       => 'object',
 764                                  'properties' => array(
 765                                      'flex' => array(
 766                                          'type' => array( 'string', 'number' ),
 767                                      ),
 768                                  ),
 769                              ),
 770                          ),
 771                      ),
 772                  ),
 773                  // DetailsLayout.
 774                  array(
 775                      'type'       => 'object',
 776                      'properties' => array(
 777                          'type'    => array(
 778                              'type' => 'string',
 779                              'enum' => array( 'details' ),
 780                          ),
 781                          'summary' => array(
 782                              'type' => 'string',
 783                          ),
 784                      ),
 785                  ),
 786              ),
 787          );
 788      }
 789  
 790      /**
 791       * Returns the schema for a form field item (string or object).
 792       *
 793       * @since 7.1.0
 794       *
 795       * @return array Schema for a form field.
 796       */
 797  	protected function get_form_field_schema() {
 798          return array(
 799              'oneOf' => array(
 800                  array( 'type' => 'string' ),
 801                  array(
 802                      'type'       => 'object',
 803                      'properties' => array(
 804                          'id'          => array(
 805                              'type' => 'string',
 806                          ),
 807                          'label'       => array(
 808                              'type' => 'string',
 809                          ),
 810                          'description' => array(
 811                              'type' => 'string',
 812                          ),
 813                          'layout'      => $this->get_form_layout_schema(),
 814                          'children'    => array(
 815                              'type'  => 'array',
 816                              'items' => array(
 817                                  'oneOf' => array(
 818                                      array( 'type' => 'string' ),
 819                                      // This object can have the shape of a form field itself,
 820                                      // allowing for recursive nesting of form fields.
 821                                      // There's no easy way to codify this recursion via the JSON Schema draft-04
 822                                      // supported by the REST API.
 823                                      array( 'type' => 'object' ),
 824                                  ),
 825                              ),
 826                          ),
 827                      ),
 828                  ),
 829              ),
 830          );
 831      }
 832  
 833      /**
 834       * Returns the schema for the form configuration object.
 835       *
 836       * @since 7.1.0
 837       *
 838       * @return array Schema properties for the form configuration.
 839       */
 840  	protected function get_form_schema() {
 841          return array(
 842              'layout' => $this->get_form_layout_schema(),
 843              'fields' => array(
 844                  'type'  => 'array',
 845                  'items' => $this->get_form_field_schema(),
 846              ),
 847          );
 848      }
 849  }


Generated : Wed Jul 15 08:20:16 2026 Cross-referenced by PHPXref