Make WordPress Core


Ignore:
Timestamp:
06/25/2020 10:11:09 PM (4 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.