[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

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

   1  <?php
   2  /**
   3   * REST API: WP_REST_Themes_Controller class
   4   *
   5   * @package WordPress
   6   * @subpackage REST_API
   7   * @since 5.0.0
   8   */
   9  
  10  /**
  11   * Core class used to manage themes via the REST API.
  12   *
  13   * @since 5.0.0
  14   *
  15   * @see WP_REST_Controller
  16   */
  17  class WP_REST_Themes_Controller extends WP_REST_Controller {
  18  
  19      /**
  20       * Matches theme's directory: `/themes/<subdirectory>/<theme>/` or `/themes/<theme>/`.
  21       * Excludes invalid directory name characters: `/:<>*?"|`.
  22       */
  23      const PATTERN = '[^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?';
  24  
  25      /**
  26       * Constructor.
  27       *
  28       * @since 5.0.0
  29       */
  30  	public function __construct() {
  31          $this->namespace = 'wp/v2';
  32          $this->rest_base = 'themes';
  33      }
  34  
  35      /**
  36       * Registers the routes for themes.
  37       *
  38       * @since 5.0.0
  39       *
  40       * @see register_rest_route()
  41       */
  42  	public function register_routes() {
  43          register_rest_route(
  44              $this->namespace,
  45              '/' . $this->rest_base,
  46              array(
  47                  array(
  48                      'methods'             => WP_REST_Server::READABLE,
  49                      'callback'            => array( $this, 'get_items' ),
  50                      'permission_callback' => array( $this, 'get_items_permissions_check' ),
  51                      'args'                => $this->get_collection_params(),
  52                  ),
  53                  'schema' => array( $this, 'get_item_schema' ),
  54              )
  55          );
  56  
  57          register_rest_route(
  58              $this->namespace,
  59              sprintf( '/%s/(?P<stylesheet>%s)', $this->rest_base, self::PATTERN ),
  60              array(
  61                  'args'   => array(
  62                      'stylesheet' => array(
  63                          'description'       => __( "The theme's stylesheet. This uniquely identifies the theme." ),
  64                          'type'              => 'string',
  65                          'sanitize_callback' => array( $this, '_sanitize_stylesheet_callback' ),
  66                      ),
  67                  ),
  68                  array(
  69                      'methods'             => WP_REST_Server::READABLE,
  70                      'callback'            => array( $this, 'get_item' ),
  71                      'permission_callback' => array( $this, 'get_item_permissions_check' ),
  72                  ),
  73                  'schema' => array( $this, 'get_public_item_schema' ),
  74              )
  75          );
  76      }
  77  
  78      /**
  79       * Sanitize the stylesheet to decode endpoint.
  80       *
  81       * @since 5.9.0
  82       *
  83       * @param string $stylesheet The stylesheet name.
  84       * @return string Sanitized stylesheet.
  85       */
  86  	public function _sanitize_stylesheet_callback( $stylesheet ) {
  87          return urldecode( $stylesheet );
  88      }
  89  
  90      /**
  91       * Checks if a given request has access to read the theme.
  92       *
  93       * @since 5.0.0
  94       *
  95       * @param WP_REST_Request $request Full details about the request.
  96       * @return true|WP_Error True if the request has read access for the item, otherwise WP_Error object.
  97       */
  98  	public function get_items_permissions_check( $request ) {
  99          if ( current_user_can( 'switch_themes' ) || current_user_can( 'manage_network_themes' ) ) {
 100              return true;
 101          }
 102  
 103          $registered = $this->get_collection_params();
 104          if ( isset( $registered['status'], $request['status'] ) && is_array( $request['status'] ) && array( 'active' ) === $request['status'] ) {
 105              return $this->check_read_active_theme_permission();
 106          }
 107  
 108          return new WP_Error(
 109              'rest_cannot_view_themes',
 110              __( 'Sorry, you are not allowed to view themes.' ),
 111              array( 'status' => rest_authorization_required_code() )
 112          );
 113      }
 114  
 115      /**
 116       * Checks if a given request has access to read the theme.
 117       *
 118       * @since 5.7.0
 119       *
 120       * @param WP_REST_Request $request Full details about the request.
 121       * @return true|WP_Error True if the request has read access for the item, otherwise WP_Error object.
 122       */
 123  	public function get_item_permissions_check( $request ) {
 124          if ( current_user_can( 'switch_themes' ) || current_user_can( 'manage_network_themes' ) ) {
 125              return true;
 126          }
 127  
 128          $wp_theme      = wp_get_theme( $request['stylesheet'] );
 129          $current_theme = wp_get_theme();
 130  
 131          if ( $this->is_same_theme( $wp_theme, $current_theme ) ) {
 132              return $this->check_read_active_theme_permission();
 133          }
 134  
 135          return new WP_Error(
 136              'rest_cannot_view_themes',
 137              __( 'Sorry, you are not allowed to view themes.' ),
 138              array( 'status' => rest_authorization_required_code() )
 139          );
 140      }
 141  
 142      /**
 143       * Checks if a theme can be read.
 144       *
 145       * @since 5.7.0
 146       *
 147       * @return true|WP_Error True if the theme can be read, WP_Error object otherwise.
 148       */
 149  	protected function check_read_active_theme_permission() {
 150          if ( current_user_can( 'edit_posts' ) ) {
 151              return true;
 152          }
 153  
 154          foreach ( get_post_types( array( 'show_in_rest' => true ), 'objects' ) as $post_type ) {
 155              if ( current_user_can( $post_type->cap->edit_posts ) ) {
 156                  return true;
 157              }
 158          }
 159  
 160          return new WP_Error(
 161              'rest_cannot_view_active_theme',
 162              __( 'Sorry, you are not allowed to view the active theme.' ),
 163              array( 'status' => rest_authorization_required_code() )
 164          );
 165      }
 166  
 167      /**
 168       * Retrieves a single theme.
 169       *
 170       * @since 5.7.0
 171       *
 172       * @param WP_REST_Request $request Full details about the request.
 173       * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
 174       */
 175  	public function get_item( $request ) {
 176          $wp_theme = wp_get_theme( $request['stylesheet'] );
 177          if ( ! $wp_theme->exists() ) {
 178              return new WP_Error(
 179                  'rest_theme_not_found',
 180                  __( 'Theme not found.' ),
 181                  array( 'status' => 404 )
 182              );
 183          }
 184          $data = $this->prepare_item_for_response( $wp_theme, $request );
 185  
 186          return rest_ensure_response( $data );
 187      }
 188  
 189      /**
 190       * Retrieves a collection of themes.
 191       *
 192       * @since 5.0.0
 193       *
 194       * @param WP_REST_Request $request Full details about the request.
 195       * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
 196       */
 197  	public function get_items( $request ) {
 198          $themes = array();
 199  
 200          $active_themes = wp_get_themes();
 201          $current_theme = wp_get_theme();
 202          $status        = $request['status'];
 203  
 204          foreach ( $active_themes as $theme ) {
 205              $theme_status = ( $this->is_same_theme( $theme, $current_theme ) ) ? 'active' : 'inactive';
 206              if ( is_array( $status ) && ! in_array( $theme_status, $status, true ) ) {
 207                  continue;
 208              }
 209  
 210              $prepared = $this->prepare_item_for_response( $theme, $request );
 211              $themes[] = $this->prepare_response_for_collection( $prepared );
 212          }
 213  
 214          $response = rest_ensure_response( $themes );
 215  
 216          $response->header( 'X-WP-Total', count( $themes ) );
 217          $response->header( 'X-WP-TotalPages', 1 );
 218  
 219          return $response;
 220      }
 221  
 222      /**
 223       * Prepares a single theme output for response.
 224       *
 225       * @since 5.0.0
 226       * @since 5.9.0 Renamed `$theme` to `$item` to match parent class for PHP 8 named parameter support.
 227       * @since 6.6.0 Added `stylesheet_uri` and `template_uri` fields.
 228       *
 229       * @param WP_Theme        $item    Theme object.
 230       * @param WP_REST_Request $request Request object.
 231       * @return WP_REST_Response Response object.
 232       */
 233  	public function prepare_item_for_response( $item, $request ) {
 234          // Restores the more descriptive, specific name for use within this method.
 235          $theme = $item;
 236  
 237          $fields = $this->get_fields_for_response( $request );
 238          $data   = array();
 239  
 240          if ( rest_is_field_included( 'stylesheet', $fields ) ) {
 241              $data['stylesheet'] = $theme->get_stylesheet();
 242          }
 243  
 244          if ( rest_is_field_included( 'template', $fields ) ) {
 245              /**
 246               * Use the get_template() method, not the 'Template' header, for finding the template.
 247               * The 'Template' header is only good for what was written in the style.css, while
 248               * get_template() takes into account where WordPress actually located the theme and
 249               * whether it is actually valid.
 250               */
 251              $data['template'] = $theme->get_template();
 252          }
 253  
 254          $plain_field_mappings = array(
 255              'requires_php' => 'RequiresPHP',
 256              'requires_wp'  => 'RequiresWP',
 257              'textdomain'   => 'TextDomain',
 258              'version'      => 'Version',
 259          );
 260  
 261          foreach ( $plain_field_mappings as $field => $header ) {
 262              if ( rest_is_field_included( $field, $fields ) ) {
 263                  $data[ $field ] = $theme->get( $header );
 264              }
 265          }
 266  
 267          if ( rest_is_field_included( 'screenshot', $fields ) ) {
 268              // Using $theme->get_screenshot() with no args to get absolute URL.
 269              $data['screenshot'] = $theme->get_screenshot() ? $theme->get_screenshot() : '';
 270          }
 271  
 272          $rich_field_mappings = array(
 273              'author'      => 'Author',
 274              'author_uri'  => 'AuthorURI',
 275              'description' => 'Description',
 276              'name'        => 'Name',
 277              'tags'        => 'Tags',
 278              'theme_uri'   => 'ThemeURI',
 279          );
 280  
 281          foreach ( $rich_field_mappings as $field => $header ) {
 282              if ( rest_is_field_included( "{$field}.raw", $fields ) ) {
 283                  $data[ $field ]['raw'] = $theme->display( $header, false, true );
 284              }
 285  
 286              if ( rest_is_field_included( "{$field}.rendered", $fields ) ) {
 287                  $data[ $field ]['rendered'] = $theme->display( $header );
 288              }
 289          }
 290  
 291          $current_theme = wp_get_theme();
 292          if ( rest_is_field_included( 'status', $fields ) ) {
 293              $data['status'] = ( $this->is_same_theme( $theme, $current_theme ) ) ? 'active' : 'inactive';
 294          }
 295  
 296          if ( rest_is_field_included( 'theme_supports', $fields ) && $this->is_same_theme( $theme, $current_theme ) ) {
 297              foreach ( get_registered_theme_features() as $feature => $config ) {
 298                  if ( ! is_array( $config['show_in_rest'] ) ) {
 299                      continue;
 300                  }
 301  
 302                  $name = $config['show_in_rest']['name'];
 303  
 304                  if ( ! rest_is_field_included( "theme_supports.{$name}", $fields ) ) {
 305                      continue;
 306                  }
 307  
 308                  if ( ! current_theme_supports( $feature ) ) {
 309                      $data['theme_supports'][ $name ] = $config['show_in_rest']['schema']['default'];
 310                      continue;
 311                  }
 312  
 313                  $support = get_theme_support( $feature );
 314  
 315                  if ( isset( $config['show_in_rest']['prepare_callback'] ) ) {
 316                      $prepare = $config['show_in_rest']['prepare_callback'];
 317                  } else {
 318                      $prepare = array( $this, 'prepare_theme_support' );
 319                  }
 320  
 321                  $prepared = $prepare( $support, $config, $feature, $request );
 322  
 323                  if ( is_wp_error( $prepared ) ) {
 324                      continue;
 325                  }
 326  
 327                  $data['theme_supports'][ $name ] = $prepared;
 328              }
 329          }
 330  
 331          if ( rest_is_field_included( 'is_block_theme', $fields ) ) {
 332              $data['is_block_theme'] = $theme->is_block_theme();
 333          }
 334  
 335          if ( rest_is_field_included( 'stylesheet_uri', $fields ) ) {
 336              if ( $this->is_same_theme( $theme, $current_theme ) ) {
 337                  $data['stylesheet_uri'] = get_stylesheet_directory_uri();
 338              } else {
 339                  $data['stylesheet_uri'] = $theme->get_stylesheet_directory_uri();
 340              }
 341          }
 342  
 343          if ( rest_is_field_included( 'template_uri', $fields ) ) {
 344              if ( $this->is_same_theme( $theme, $current_theme ) ) {
 345                  $data['template_uri'] = get_template_directory_uri();
 346              } else {
 347                  $data['template_uri'] = $theme->get_template_directory_uri();
 348              }
 349          }
 350  
 351          if ( rest_is_field_included( 'default_template_types', $fields ) && $this->is_same_theme( $theme, $current_theme ) ) {
 352              $default_template_types = array();
 353              foreach ( get_default_block_template_types() as $slug => $template_type ) {
 354                  $template_type['slug']    = (string) $slug;
 355                  $default_template_types[] = $template_type;
 356              }
 357              $data['default_template_types'] = $default_template_types;
 358          }
 359  
 360          if ( rest_is_field_included( 'default_template_part_areas', $fields ) && $this->is_same_theme( $theme, $current_theme ) ) {
 361              $data['default_template_part_areas'] = get_allowed_block_template_part_areas();
 362          }
 363  
 364          $data = $this->add_additional_fields_to_object( $data, $request );
 365  
 366          // Wrap the data in a response object.
 367          $response = rest_ensure_response( $data );
 368  
 369          if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) {
 370              $response->add_links( $this->prepare_links( $theme ) );
 371          }
 372  
 373          /**
 374           * Filters theme data returned from the REST API.
 375           *
 376           * @since 5.0.0
 377           *
 378           * @param WP_REST_Response $response The response object.
 379           * @param WP_Theme         $theme    Theme object used to create response.
 380           * @param WP_REST_Request  $request  Request object.
 381           */
 382          return apply_filters( 'rest_prepare_theme', $response, $theme, $request );
 383      }
 384  
 385      /**
 386       * Prepares links for the request.
 387       *
 388       * @since 5.7.0
 389       *
 390       * @param WP_Theme $theme Theme data.
 391       * @return array Links for the given block type.
 392       */
 393  	protected function prepare_links( $theme ) {
 394          $links = array(
 395              'self'       => array(
 396                  'href' => rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $theme->get_stylesheet() ) ),
 397              ),
 398              'collection' => array(
 399                  'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ),
 400              ),
 401          );
 402  
 403          if ( $this->is_same_theme( $theme, wp_get_theme() ) ) {
 404              // This creates a record for the active theme if not existent.
 405              $id = WP_Theme_JSON_Resolver::get_user_global_styles_post_id();
 406          } else {
 407              $user_cpt = WP_Theme_JSON_Resolver::get_user_data_from_wp_global_styles( $theme );
 408              $id       = isset( $user_cpt['ID'] ) ? $user_cpt['ID'] : null;
 409          }
 410  
 411          if ( $id ) {
 412              $links['https://api.w.org/user-global-styles'] = array(
 413                  'href' => rest_url( 'wp/v2/global-styles/' . $id ),
 414              );
 415          }
 416  
 417          if ( $theme->is_block_theme() && $this->is_same_theme( $theme, wp_get_theme() ) ) {
 418              $links['https://api.w.org/export-theme'] = array(
 419                  'href'        => rest_url( 'wp-block-editor/v1/export' ),
 420                  'targetHints' => array(
 421                      'allow' => current_user_can( 'export' ) ? array( 'GET' ) : array(),
 422                  ),
 423              );
 424          }
 425  
 426          return $links;
 427      }
 428  
 429      /**
 430       * Helper function to compare two themes.
 431       *
 432       * @since 5.7.0
 433       *
 434       * @param WP_Theme $theme_a First theme to compare.
 435       * @param WP_Theme $theme_b Second theme to compare.
 436       * @return bool
 437       */
 438  	protected function is_same_theme( $theme_a, $theme_b ) {
 439          return $theme_a->get_stylesheet() === $theme_b->get_stylesheet();
 440      }
 441  
 442      /**
 443       * Prepares the theme support value for inclusion in the REST API response.
 444       *
 445       * @since 5.5.0
 446       *
 447       * @param mixed           $support The raw value from get_theme_support().
 448       * @param array           $args    The feature's registration args.
 449       * @param string          $feature The feature name.
 450       * @param WP_REST_Request $request The request object.
 451       * @return mixed The prepared support value.
 452       */
 453  	protected function prepare_theme_support( $support, $args, $feature, $request ) {
 454          $schema = $args['show_in_rest']['schema'];
 455  
 456          if ( 'boolean' === $schema['type'] ) {
 457              return true;
 458          }
 459  
 460          if ( is_array( $support ) && ! $args['variadic'] ) {
 461              $support = $support[0];
 462          }
 463  
 464          return rest_sanitize_value_from_schema( $support, $schema );
 465      }
 466  
 467      /**
 468       * Retrieves the theme's schema, conforming to JSON Schema.
 469       *
 470       * @since 5.0.0
 471       *
 472       * @return array Item schema data.
 473       */
 474  	public function get_item_schema() {
 475          if ( $this->schema ) {
 476              return $this->add_additional_fields_schema( $this->schema );
 477          }
 478  
 479          $schema = array(
 480              '$schema'    => 'http://json-schema.org/draft-04/schema#',
 481              'title'      => 'theme',
 482              'type'       => 'object',
 483              'properties' => array(
 484                  'stylesheet'                  => array(
 485                      'description' => __( 'The theme\'s stylesheet. This uniquely identifies the theme.' ),
 486                      'type'        => 'string',
 487                      'readonly'    => true,
 488                  ),
 489                  'stylesheet_uri'              => array(
 490                      'description' => __( 'The uri for the theme\'s stylesheet directory.' ),
 491                      'type'        => 'string',
 492                      'format'      => 'uri',
 493                      'readonly'    => true,
 494                  ),
 495                  'template'                    => array(
 496                      'description' => __( 'The theme\'s template. If this is a child theme, this refers to the parent theme, otherwise this is the same as the theme\'s stylesheet.' ),
 497                      'type'        => 'string',
 498                      'readonly'    => true,
 499                  ),
 500                  'template_uri'                => array(
 501                      'description' => __( 'The uri for the theme\'s template directory. If this is a child theme, this refers to the parent theme, otherwise this is the same as the theme\'s stylesheet directory.' ),
 502                      'type'        => 'string',
 503                      'format'      => 'uri',
 504                      'readonly'    => true,
 505                  ),
 506                  'author'                      => array(
 507                      'description' => __( 'The theme author.' ),
 508                      'type'        => 'object',
 509                      'readonly'    => true,
 510                      'properties'  => array(
 511                          'raw'      => array(
 512                              'description' => __( 'The theme author\'s name, as found in the theme header.' ),
 513                              'type'        => 'string',
 514                          ),
 515                          'rendered' => array(
 516                              'description' => __( 'HTML for the theme author, transformed for display.' ),
 517                              'type'        => 'string',
 518                          ),
 519                      ),
 520                  ),
 521                  'author_uri'                  => array(
 522                      'description' => __( 'The website of the theme author.' ),
 523                      'type'        => 'object',
 524                      'readonly'    => true,
 525                      'properties'  => array(
 526                          'raw'      => array(
 527                              'description' => __( 'The website of the theme author, as found in the theme header.' ),
 528                              'type'        => 'string',
 529                              'format'      => 'uri',
 530                          ),
 531                          'rendered' => array(
 532                              'description' => __( 'The website of the theme author, transformed for display.' ),
 533                              'type'        => 'string',
 534                              'format'      => 'uri',
 535                          ),
 536                      ),
 537                  ),
 538                  'description'                 => array(
 539                      'description' => __( 'A description of the theme.' ),
 540                      'type'        => 'object',
 541                      'readonly'    => true,
 542                      'properties'  => array(
 543                          'raw'      => array(
 544                              'description' => __( 'The theme description, as found in the theme header.' ),
 545                              'type'        => 'string',
 546                          ),
 547                          'rendered' => array(
 548                              'description' => __( 'The theme description, transformed for display.' ),
 549                              'type'        => 'string',
 550                          ),
 551                      ),
 552                  ),
 553                  'is_block_theme'              => array(
 554                      'description' => __( 'Whether the theme is a block-based theme.' ),
 555                      'type'        => 'boolean',
 556                      'readonly'    => true,
 557                  ),
 558                  'name'                        => array(
 559                      'description' => __( 'The name of the theme.' ),
 560                      'type'        => 'object',
 561                      'readonly'    => true,
 562                      'properties'  => array(
 563                          'raw'      => array(
 564                              'description' => __( 'The theme name, as found in the theme header.' ),
 565                              'type'        => 'string',
 566                          ),
 567                          'rendered' => array(
 568                              'description' => __( 'The theme name, transformed for display.' ),
 569                              'type'        => 'string',
 570                          ),
 571                      ),
 572                  ),
 573                  'requires_php'                => array(
 574                      'description' => __( 'The minimum PHP version required for the theme to work.' ),
 575                      'type'        => 'string',
 576                      'readonly'    => true,
 577                  ),
 578                  'requires_wp'                 => array(
 579                      'description' => __( 'The minimum WordPress version required for the theme to work.' ),
 580                      'type'        => 'string',
 581                      'readonly'    => true,
 582                  ),
 583                  'screenshot'                  => array(
 584                      'description' => __( 'The theme\'s screenshot URL.' ),
 585                      'type'        => 'string',
 586                      'format'      => 'uri',
 587                      'readonly'    => true,
 588                  ),
 589                  'tags'                        => array(
 590                      'description' => __( 'Tags indicating styles and features of the theme.' ),
 591                      'type'        => 'object',
 592                      'readonly'    => true,
 593                      'properties'  => array(
 594                          'raw'      => array(
 595                              'description' => __( 'The theme tags, as found in the theme header.' ),
 596                              'type'        => 'array',
 597                              'items'       => array(
 598                                  'type' => 'string',
 599                              ),
 600                          ),
 601                          'rendered' => array(
 602                              'description' => __( 'The theme tags, transformed for display.' ),
 603                              'type'        => 'string',
 604                          ),
 605                      ),
 606                  ),
 607                  'textdomain'                  => array(
 608                      'description' => __( 'The theme\'s text domain.' ),
 609                      'type'        => 'string',
 610                      'readonly'    => true,
 611                  ),
 612                  'theme_supports'              => array(
 613                      'description' => __( 'Features supported by this theme.' ),
 614                      'type'        => 'object',
 615                      'readonly'    => true,
 616                      'properties'  => array(),
 617                  ),
 618                  'theme_uri'                   => array(
 619                      'description' => __( 'The URI of the theme\'s webpage.' ),
 620                      'type'        => 'object',
 621                      'readonly'    => true,
 622                      'properties'  => array(
 623                          'raw'      => array(
 624                              'description' => __( 'The URI of the theme\'s webpage, as found in the theme header.' ),
 625                              'type'        => 'string',
 626                              'format'      => 'uri',
 627                          ),
 628                          'rendered' => array(
 629                              'description' => __( 'The URI of the theme\'s webpage, transformed for display.' ),
 630                              'type'        => 'string',
 631                              'format'      => 'uri',
 632                          ),
 633                      ),
 634                  ),
 635                  'version'                     => array(
 636                      'description' => __( 'The theme\'s current version.' ),
 637                      'type'        => 'string',
 638                      'readonly'    => true,
 639                  ),
 640                  'status'                      => array(
 641                      'description' => __( 'A named status for the theme.' ),
 642                      'type'        => 'string',
 643                      'enum'        => array( 'inactive', 'active' ),
 644                  ),
 645                  'default_template_types'      => array(
 646                      'description' => __( 'A list of default template types.' ),
 647                      'type'        => 'array',
 648                      'readonly'    => true,
 649                      'items'       => array(
 650                          'type'       => 'object',
 651                          'properties' => array(
 652                              'slug'        => array(
 653                                  'type' => 'string',
 654                              ),
 655                              'title'       => array(
 656                                  'type' => 'string',
 657                              ),
 658                              'description' => array(
 659                                  'type' => 'string',
 660                              ),
 661                          ),
 662                      ),
 663                  ),
 664                  'default_template_part_areas' => array(
 665                      'description' => __( 'A list of allowed area values for template parts.' ),
 666                      'type'        => 'array',
 667                      'readonly'    => true,
 668                      'items'       => array(
 669                          'type'       => 'object',
 670                          'properties' => array(
 671                              'area'        => array(
 672                                  'type' => 'string',
 673                              ),
 674                              'label'       => array(
 675                                  'type' => 'string',
 676                              ),
 677                              'description' => array(
 678                                  'type' => 'string',
 679                              ),
 680                              'icon'        => array(
 681                                  'type' => 'string',
 682                              ),
 683                              'area_tag'    => array(
 684                                  'type' => 'string',
 685                              ),
 686                          ),
 687                      ),
 688                  ),
 689              ),
 690          );
 691  
 692          foreach ( get_registered_theme_features() as $feature => $config ) {
 693              if ( ! is_array( $config['show_in_rest'] ) ) {
 694                  continue;
 695              }
 696  
 697              $name = $config['show_in_rest']['name'];
 698  
 699              $schema['properties']['theme_supports']['properties'][ $name ] = $config['show_in_rest']['schema'];
 700          }
 701  
 702          $this->schema = $schema;
 703  
 704          return $this->add_additional_fields_schema( $this->schema );
 705      }
 706  
 707      /**
 708       * Retrieves the search params for the themes collection.
 709       *
 710       * @since 5.0.0
 711       *
 712       * @return array Collection parameters.
 713       */
 714  	public function get_collection_params() {
 715          $query_params = array(
 716              'status' => array(
 717                  'description' => __( 'Limit result set to themes assigned one or more statuses.' ),
 718                  'type'        => 'array',
 719                  'items'       => array(
 720                      'enum' => array( 'active', 'inactive' ),
 721                      'type' => 'string',
 722                  ),
 723              ),
 724          );
 725  
 726          /**
 727           * Filters REST API collection parameters for the themes controller.
 728           *
 729           * @since 5.0.0
 730           *
 731           * @param array $query_params JSON Schema-formatted collection parameters.
 732           */
 733          return apply_filters( 'rest_themes_collection_params', $query_params );
 734      }
 735  
 736      /**
 737       * Sanitizes and validates the list of theme status.
 738       *
 739       * @since 5.0.0
 740       * @deprecated 5.7.0
 741       *
 742       * @param string|array    $statuses  One or more theme statuses.
 743       * @param WP_REST_Request $request   Full details about the request.
 744       * @param string          $parameter Additional parameter to pass to validation.
 745       * @return array|WP_Error A list of valid statuses, otherwise WP_Error object.
 746       */
 747  	public function sanitize_theme_status( $statuses, $request, $parameter ) {
 748          _deprecated_function( __METHOD__, '5.7.0' );
 749  
 750          $statuses = wp_parse_slug_list( $statuses );
 751  
 752          foreach ( $statuses as $status ) {
 753              $result = rest_validate_request_arg( $status, $request, $parameter );
 754  
 755              if ( is_wp_error( $result ) ) {
 756                  return $result;
 757              }
 758          }
 759  
 760          return $statuses;
 761      }
 762  }


Generated : Thu Oct 30 08:20:06 2025 Cross-referenced by PHPXref