Make WordPress Core


Ignore:
Timestamp:
06/25/2020 10:11:09 PM (6 years ago)
Author:
TimothyBlynJacobs
Message:

Themes: Introduce register_theme_feature API.

Currently themes can declare support for a given feature by using add_theme_support(). This commit adds a register_theme_feature() API that allows plugins and WordPress Core to declare a list of available features that themes can support.

The REST API uses this to expose a theme's supported features if the feature has been registered with "show_in_rest" set to true.

Props kadamwhite, spacedmonkey, williampatton, desrosj, TimothyBlynJacobs.
Fixes #49406.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php

    r47929 r48171  
    168168
    169169                if ( rest_is_field_included( 'theme_supports', $fields ) ) {
    170                         $item_schemas   = $this->get_item_schema();
    171                         $theme_supports = $item_schemas['properties']['theme_supports']['properties'];
    172                         foreach ( $theme_supports as $name => $schema ) {
     170                        foreach ( get_registered_theme_features() as $feature => $config ) {
     171                                if ( ! is_array( $config['show_in_rest'] ) ) {
     172                                        continue;
     173                                }
     174
     175                                $name = $config['show_in_rest']['name'];
     176
    173177                                if ( ! rest_is_field_included( "theme_supports.{$name}", $fields ) ) {
    174178                                        continue;
    175179                                }
    176180
    177                                 if ( 'formats' === $name ) {
     181                                if ( ! current_theme_supports( $feature ) ) {
     182                                        $data['theme_supports'][ $name ] = $config['show_in_rest']['schema']['default'];
    178183                                        continue;
    179184                                }
    180185
    181                                 if ( ! current_theme_supports( $name ) ) {
    182                                         $data['theme_supports'][ $name ] = false;
     186                                $support = get_theme_support( $feature );
     187
     188                                if ( isset( $config['show_in_rest']['prepare_callback'] ) ) {
     189                                        $prepare = $config['show_in_rest']['prepare_callback'];
     190                                } else {
     191                                        $prepare = array( $this, 'prepare_theme_support' );
     192                                }
     193
     194                                $prepared = $prepare( $support, $config, $feature, $request );
     195
     196                                if ( is_wp_error( $prepared ) ) {
    183197                                        continue;
    184198                                }
    185199
    186                                 if ( 'boolean' === $schema['type'] ) {
    187                                         $data['theme_supports'][ $name ] = true;
    188                                         continue;
    189                                 }
    190 
    191                                 $support = get_theme_support( $name );
    192 
    193                                 if ( is_array( $support ) ) {
    194                                         // None of the Core theme supports have variadic args.
    195                                         $support = $support[0];
    196 
    197                                         // Core multi-type theme-support schema definitions always list boolean first.
    198                                         if ( is_array( $schema['type'] ) && 'boolean' === $schema['type'][0] ) {
    199                                                 // Pass the non-boolean type through to the sanitizer, which cannot itself
    200                                                 // determine the intended type if the value is invalid (for example if an
    201                                                 // object includes non-safelisted properties).
    202                                                 $schema['type'] = $schema['type'][1];
    203                                         }
    204                                 }
    205 
    206                                 $data['theme_supports'][ $name ] = rest_sanitize_value_from_schema( $support, $schema );
    207                         }
    208 
    209                         $formats = get_theme_support( 'post-formats' );
    210                         $formats = is_array( $formats ) ? array_values( $formats[0] ) : array();
    211                         $formats = array_merge( array( 'standard' ), $formats );
    212 
    213                         $data['theme_supports']['formats'] = $formats;
     200                                $data['theme_supports'][ $name ] = $prepared;
     201                        }
    214202                }
    215203
    … …  
    232220
    233221        /**
     222         * Prepares the theme support value for inclusion in the REST API response.
     223         *
     224         * @since 5.5.0
     225         *
     226         * @param mixed           $support The raw value from {@see get_theme_support()}
     227         * @param array           $args    The feature's registration args.
     228         * @param string          $feature The feature name.
     229         * @param WP_REST_Request $request The request object.
     230         * @return mixed The prepared support value.
     231         */
     232        protected function prepare_theme_support( $support, $args, $feature, $request ) {
     233                $schema = $args['show_in_rest']['schema'];
     234
     235                if ( 'boolean' === $schema['type'] ) {
     236                        return true;
     237                }
     238
     239                if ( is_array( $support ) ) {
     240                        if ( ! $args['variadic'] ) {
     241                                $support = $support[0];
     242                        }
     243
     244                        // Multi-type theme-support schema definitions always list boolean first.
     245                        if ( is_array( $schema['type'] ) && 'boolean' === $schema['type'][0] ) {
     246                                // Pass the non-boolean type through to the sanitizer, which cannot itself
     247                                // determine the intended type if the value is invalid (for example if an
     248                                // object includes non-safelisted properties). See #50300.
     249                                $schema['type'] = $schema['type'][1];
     250                        }
     251                }
     252
     253                return rest_sanitize_value_from_schema( $support, $schema );
     254        }
     255
     256        /**
    234257         * Retrieves the theme's schema, conforming to JSON Schema.
    235258         *
    … …  
    363386                                        'type'        => 'object',
    364387                                        'readonly'    => true,
    365                                         'properties'  => array(
    366                                                 'align-wide'                => array(
    367                                                         'description' => __( 'Whether theme opts in to wide alignment CSS class.' ),
    368                                                         'type'        => 'boolean',
    369                                                 ),
    370                                                 'automatic-feed-links'      => array(
    371                                                         'description' => __( 'Whether posts and comments RSS feed links are added to head.' ),
    372                                                         'type'        => 'boolean',
    373                                                 ),
    374                                                 'custom-header'             => array(
    375                                                         'description'          => __( 'Custom header if defined by the theme.' ),
    376                                                         'type'                 => array( 'boolean', 'object' ),
    377                                                         'properties'           => array(
    378                                                                 'default-image'      => array(
    379                                                                         'type'   => 'string',
    380                                                                         'format' => 'uri',
    381                                                                 ),
    382                                                                 'random-default'     => array(
    383                                                                         'type' => 'boolean',
    384                                                                 ),
    385                                                                 'width'              => array(
    386                                                                         'type' => 'integer',
    387                                                                 ),
    388                                                                 'height'             => array(
    389                                                                         'type' => 'integer',
    390                                                                 ),
    391                                                                 'flex-height'        => array(
    392                                                                         'type' => 'boolean',
    393                                                                 ),
    394                                                                 'flex-width'         => array(
    395                                                                         'type' => 'boolean',
    396                                                                 ),
    397                                                                 'default-text-color' => array(
    398                                                                         'type' => 'string',
    399                                                                 ),
    400                                                                 'header-text'        => array(
    401                                                                         'type' => 'boolean',
    402                                                                 ),
    403                                                                 'uploads'            => array(
    404                                                                         'type' => 'boolean',
    405                                                                 ),
    406                                                                 'video'              => array(
    407                                                                         'type' => 'boolean',
    408                                                                 ),
    409                                                         ),
    410                                                         'additionalProperties' => false,
    411                                                 ),
    412                                                 'custom-background'         => array(
    413                                                         'description'          => __( 'Custom background if defined by the theme.' ),
    414                                                         'type'                 => array( 'boolean', 'object' ),
    415                                                         'properties'           => array(
    416                                                                 'default-image'      => array(
    417                                                                         'type'   => 'string',
    418                                                                         'format' => 'uri',
    419                                                                 ),
    420                                                                 'default-preset'     => array(
    421                                                                         'type' => 'string',
    422                                                                         'enum' => array(
    423                                                                                 'default',
    424                                                                                 'fill',
    425                                                                                 'fit',
    426                                                                                 'repeat',
    427                                                                                 'custom',
    428                                                                         ),
    429                                                                 ),
    430                                                                 'default-position-x' => array(
    431                                                                         'type' => 'string',
    432                                                                         'enum' => array(
    433                                                                                 'left',
    434                                                                                 'center',
    435                                                                                 'right',
    436                                                                         ),
    437                                                                 ),
    438                                                                 'default-position-y' => array(
    439                                                                         'type' => 'string',
    440                                                                         'enum' => array(
    441                                                                                 'left',
    442                                                                                 'center',
    443                                                                                 'right',
    444                                                                         ),
    445                                                                 ),
    446                                                                 'default-size'       => array(
    447                                                                         'type' => 'string',
    448                                                                         'enum' => array(
    449                                                                                 'auto',
    450                                                                                 'contain',
    451                                                                                 'cover',
    452                                                                         ),
    453                                                                 ),
    454                                                                 'default-repeat'     => array(
    455                                                                         'type' => 'string',
    456                                                                         'enum' => array(
    457                                                                                 'repeat-x',
    458                                                                                 'repeat-y',
    459                                                                                 'repeat',
    460                                                                                 'no-repeat',
    461                                                                         ),
    462                                                                 ),
    463                                                                 'default-attachment' => array(
    464                                                                         'type' => 'string',
    465                                                                         'enum' => array(
    466                                                                                 'scroll',
    467                                                                                 'fixed',
    468                                                                         ),
    469                                                                 ),
    470                                                                 'default-color'      => array(
    471                                                                         'type' => 'string',
    472                                                                 ),
    473                                                         ),
    474                                                         'additionalProperties' => false,
    475                                                 ),
    476                                                 'custom-logo'               => array(
    477                                                         'description'          => __( 'Custom logo if defined by the theme.' ),
    478                                                         'type'                 => array( 'boolean', 'object' ),
    479                                                         'properties'           => array(
    480                                                                 'width'       => array(
    481                                                                         'type' => 'integer',
    482                                                                 ),
    483                                                                 'height'      => array(
    484                                                                         'type' => 'integer',
    485                                                                 ),
    486                                                                 'flex-width'  => array(
    487                                                                         'type' => 'boolean',
    488                                                                 ),
    489                                                                 'flex-height' => array(
    490                                                                         'type' => 'boolean',
    491                                                                 ),
    492                                                                 'header-text' => array(
    493                                                                         'type'  => 'array',
    494                                                                         'items' => array(
    495                                                                                 'type' => 'string',
    496                                                                         ),
    497                                                                 ),
    498                                                         ),
    499                                                         'additionalProperties' => false,
    500                                                 ),
    501                                                 'customize-selective-refresh-widgets' => array(
    502                                                         'description' => __( 'Whether the theme enables Selective Refresh for Widgets being managed with the Customizer.' ),
    503                                                         'type'        => 'boolean',
    504                                                 ),
    505                                                 'dark-editor-style'         => array(
    506                                                         'description' => __( 'Whether theme opts in to the dark editor style UI.' ),
    507                                                         'type'        => 'boolean',
    508                                                 ),
    509                                                 'disable-custom-colors'     => array(
    510                                                         'description' => __( 'Whether the theme disables custom colors.' ),
    511                                                         'type'        => 'boolean',
    512                                                 ),
    513                                                 'disable-custom-font-sizes' => array(
    514                                                         'description' => __( 'Whether the theme disables custom font sizes.' ),
    515                                                         'type'        => 'boolean',
    516                                                 ),
    517                                                 'disable-custom-gradients'  => array(
    518                                                         'description' => __( 'Whether the theme disables custom gradients.' ),
    519                                                         'type'        => 'boolean',
    520                                                 ),
    521                                                 'editor-color-palette'      => array(
    522                                                         'description' => __( 'Custom color palette if defined by the theme.' ),
    523                                                         'type'        => array( 'boolean', 'array' ),
    524                                                         'items'       => array(
    525                                                                 'type'                 => 'object',
    526                                                                 'properties'           => array(
    527                                                                         'name'  => array(
    528                                                                                 'type' => 'string',
    529                                                                         ),
    530                                                                         'slug'  => array(
    531                                                                                 'type' => 'string',
    532                                                                         ),
    533                                                                         'color' => array(
    534                                                                                 'type' => 'string',
    535                                                                         ),
    536                                                                 ),
    537                                                                 'additionalProperties' => false,
    538                                                         ),
    539                                                 ),
    540                                                 'editor-font-sizes'         => array(
    541                                                         'description' => __( 'Custom font sizes if defined by the theme.' ),
    542                                                         'type'        => array( 'boolean', 'array' ),
    543                                                         'items'       => array(
    544                                                                 'type'                 => 'object',
    545                                                                 'properties'           => array(
    546                                                                         'name' => array(
    547                                                                                 'type' => 'string',
    548                                                                         ),
    549                                                                         'size' => array(
    550                                                                                 'type' => 'number',
    551                                                                         ),
    552                                                                         'slug' => array(
    553                                                                                 'type' => 'string',
    554                                                                         ),
    555                                                                 ),
    556                                                                 'additionalProperties' => false,
    557                                                         ),
    558                                                 ),
    559                                                 'editor-gradient-presets'   => array(
    560                                                         'description' => __( 'Custom gradient presets if defined by the theme.' ),
    561                                                         'type'        => array( 'boolean', 'array' ),
    562                                                         'items'       => array(
    563                                                                 'type'                 => 'object',
    564                                                                 'properties'           => array(
    565                                                                         'name'     => array(
    566                                                                                 'type' => 'string',
    567                                                                         ),
    568                                                                         'gradient' => array(
    569                                                                                 'type' => 'string',
    570                                                                         ),
    571                                                                         'slug'     => array(
    572                                                                                 'type' => 'string',
    573                                                                         ),
    574                                                                 ),
    575                                                                 'additionalProperties' => false,
    576                                                         ),
    577                                                 ),
    578                                                 'editor-styles'             => array(
    579                                                         'description' => __( 'Whether theme opts in to the editor styles CSS wrapper.' ),
    580                                                         'type'        => 'boolean',
    581                                                 ),
    582                                                 'formats'                   => array(
    583                                                         'description' => __( 'Post formats supported.' ),
    584                                                         'type'        => 'array',
    585                                                         'items'       => array(
    586                                                                 'type' => 'string',
    587                                                                 'enum' => get_post_format_slugs(),
    588                                                         ),
    589                                                 ),
    590                                                 'html5'                     => array(
    591                                                         'description' => __( 'Allows use of html5 markup for search forms, comment forms, comment lists, gallery, and caption.' ),
    592                                                         'type'        => array( 'boolean', 'array' ),
    593                                                         'items'       => array(
    594                                                                 'type' => 'string',
    595                                                                 'enum' => array(
    596                                                                         'search-form',
    597                                                                         'comment-form',
    598                                                                         'comment-list',
    599                                                                         'gallery',
    600                                                                         'caption',
    601                                                                         'script',
    602                                                                         'style',
    603                                                                 ),
    604                                                         ),
    605                                                 ),
    606                                                 'post-thumbnails'           => array(
    607                                                         'description' => __( 'Whether the theme supports post thumbnails.' ),
    608                                                         'type'        => array( 'boolean', 'array' ),
    609                                                         'items'       => array(
    610                                                                 'type' => 'string',
    611                                                         ),
    612                                                 ),
    613                                                 'responsive-embeds'         => array(
    614                                                         'description' => __( 'Whether the theme supports responsive embedded content.' ),
    615                                                         'type'        => 'boolean',
    616                                                 ),
    617                                                 'title-tag'                 => array(
    618                                                         'description' => __( 'Whether the theme can manage the document title tag.' ),
    619                                                         'type'        => 'boolean',
    620                                                 ),
    621                                                 'wp-block-styles'           => array(
    622                                                         'description' => __( 'Whether theme opts in to default WordPress block styles for viewing.' ),
    623                                                         'type'        => 'boolean',
    624                                                 ),
    625                                         ),
     388                                        'properties'  => array(),
    626389                                ),
    627390                                'theme_uri'      => array(
    … …  
    649412                        ),
    650413                );
     414
     415                foreach ( get_registered_theme_features() as $feature => $config ) {
     416                        if ( ! is_array( $config['show_in_rest'] ) ) {
     417                                continue;
     418                        }
     419
     420                        $name = $config['show_in_rest']['name'];
     421
     422                        $schema['properties']['theme_supports']['properties'][ $name ] = $config['show_in_rest']['schema'];
     423                }
    651424
    652425                $this->schema = $schema;
Note: See TracChangeset for help on using the changeset viewer.