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/theme.php

    r48169 r48171  
    29952995
    29962996/**
     2997 * Registers a theme feature for use in {@see add_theme_support}.
     2998 *
     2999 * This does not indicate that the current theme supports the feature, it only describes the feature's supported options.
     3000 *
     3001 * @since 5.5.0
     3002 *
     3003 * @global $_wp_registered_theme_features
     3004 *
     3005 * @param string $feature The name uniquely identifying the feature.
     3006 * @param array $args {
     3007 *      Data used to describe the theme
     3008 *
     3009 *      @type string     $type         The type of data associated with this feature. Defaults to 'boolean'.
     3010 *                                     Valid values are 'string', 'boolean', 'integer', 'number', 'array', and 'object'.
     3011 *      @type boolean    $variadic     Does this feature utilize the variadic support of {@see add_theme_support()},
     3012 *                                     or are all arguments specified as the second parameter. Must be used with the "array" type.
     3013 *      @type string     $description  A short description of the feature. Included in the Themes REST API schema. Intended for developers.
     3014 *      @type bool|array $show_in_rest {
     3015 *          Whether this feature should be included in the Themes REST API endpoint. Defaults to not being included.
     3016 *          When registering an 'array' or 'object' type, this argument must be an array with the 'schema' key.
     3017 *
     3018 *          @type array    $schema           Specifies the JSON Schema definition describing the feature. If any objects in the schema
     3019 *                                           do not include the 'additionalProperties' keyword, it is set to false.
     3020 *          @type string   $name             An alternate name to be use as the property name in the REST API.
     3021 *          @type callable $prepare_callback A function used to format the theme support in the REST API. Receives the raw theme support value.
     3022 *      }
     3023 * }
     3024 * @return true|WP_Error True if the theme feature was successfully registered, a WP_Error object if not.
     3025 */
     3026function register_theme_feature( $feature, $args = array() ) {
     3027        global $_wp_registered_theme_features;
     3028
     3029        if ( ! is_array( $_wp_registered_theme_features ) ) {
     3030                $_wp_registered_theme_features = array();
     3031        }
     3032
     3033        $defaults = array(
     3034                'type'         => 'boolean',
     3035                'variadic'     => false,
     3036                'description'  => '',
     3037                'show_in_rest' => false,
     3038        );
     3039
     3040        $args = wp_parse_args( $args, $defaults );
     3041
     3042        if ( true === $args['show_in_rest'] ) {
     3043                $args['show_in_rest'] = array();
     3044        }
     3045
     3046        if ( is_array( $args['show_in_rest'] ) ) {
     3047                $args['show_in_rest'] = wp_parse_args(
     3048                        $args['show_in_rest'],
     3049                        array(
     3050                                'schema'           => array(),
     3051                                'name'             => $feature,
     3052                                'prepare_callback' => null,
     3053                        )
     3054                );
     3055        }
     3056
     3057        if ( ! in_array( $args['type'], array( 'string', 'boolean', 'integer', 'number', 'array', 'object' ), true ) ) {
     3058                return new WP_Error( 'invalid_type', __( 'The feature "type" is not valid JSON Schema type.' ) );
     3059        }
     3060
     3061        if ( true === $args['variadic'] && 'array' !== $args['type'] ) {
     3062                return new WP_Error( 'variadic_must_be_array', __( 'When registering a "variadic" theme feature, the "type" must be an "array".' ) );
     3063        }
     3064
     3065        if ( false !== $args['show_in_rest'] && in_array( $args['type'], array( 'array', 'object' ), true ) ) {
     3066                if ( ! is_array( $args['show_in_rest'] ) || empty( $args['show_in_rest']['schema'] ) ) {
     3067                        return new WP_Error( 'missing_schema', __( 'When registering an "array" or "object" feature to show in the REST API, the feature\'s schema must also be defined.' ) );
     3068                }
     3069
     3070                if ( 'array' === $args['type'] && ! isset( $args['show_in_rest']['schema']['items'] ) ) {
     3071                        return new WP_Error( 'missing_schema_items', __( 'When registering an "array" feature, the feature\'s schema must include the "items" keyword.' ) );
     3072                }
     3073
     3074                if ( 'object' === $args['type'] && ! isset( $args['show_in_rest']['schema']['properties'] ) ) {
     3075                        return new WP_Error( 'missing_schema_properties', __( 'When registering an "object" feature, the feature\'s schema must include the "properties" keyword.' ) );
     3076                }
     3077        }
     3078
     3079        if ( is_array( $args['show_in_rest'] ) ) {
     3080                if ( isset( $args['show_in_rest']['prepare_callback'] ) && ! is_callable( $args['show_in_rest']['prepare_callback'] ) ) {
     3081                        return new WP_Error( 'invalid_rest_prepare_callback', __( 'The prepare_callback must be a callable function.' ) );
     3082                }
     3083
     3084                $args['show_in_rest']['schema'] = wp_parse_args(
     3085                        $args['show_in_rest']['schema'],
     3086                        array(
     3087                                'description' => $args['description'],
     3088                                'type'        => $args['type'],
     3089                                'default'     => false,
     3090                        )
     3091                );
     3092
     3093                if ( is_bool( $args['show_in_rest']['schema']['default'] ) && ! in_array( 'boolean', (array) $args['show_in_rest']['schema']['type'], true ) ) {
     3094                        // Automatically include the "boolean" type when the default value is a boolean.
     3095                        $args['show_in_rest']['schema']['type'] = (array) $args['show_in_rest']['schema']['type'];
     3096                        array_unshift( $args['show_in_rest']['schema']['type'], 'boolean' );
     3097                }
     3098
     3099                $args['show_in_rest']['schema'] = rest_default_additional_properties_to_false( $args['show_in_rest']['schema'] );
     3100        }
     3101
     3102        $_wp_registered_theme_features[ $feature ] = $args;
     3103
     3104        return true;
     3105}
     3106
     3107/**
     3108 * Gets the list of registered theme features.
     3109 *
     3110 * @since 5.5.0
     3111 *
     3112 * @global $_wp_registered_theme_features
     3113 *
     3114 * @return array[] List of theme features, keyed by their name.
     3115 */
     3116function get_registered_theme_features() {
     3117        global $_wp_registered_theme_features;
     3118
     3119        if ( ! is_array( $_wp_registered_theme_features ) ) {
     3120                return array();
     3121        }
     3122
     3123        return $_wp_registered_theme_features;
     3124}
     3125
     3126/**
     3127 * Gets the registration config for a theme feature.
     3128 *
     3129 * @since 5.5.0
     3130 *
     3131 * @global $_wp_registered_theme_features
     3132 *
     3133 * @param string $feature The feature name.
     3134 * @return array|null The registration args, or null if the feature was not registered.
     3135 */
     3136function get_registered_theme_feature( $feature ) {
     3137        global $_wp_registered_theme_features;
     3138
     3139        if ( ! is_array( $_wp_registered_theme_features ) ) {
     3140                return null;
     3141        }
     3142
     3143        return isset( $_wp_registered_theme_features[ $feature ] ) ? $_wp_registered_theme_features[ $feature ] : null;
     3144}
     3145
     3146/**
    29973147 * Checks an attachment being deleted to see if it's a header or background image.
    29983148 *
     
    34633613        }
    34643614}
     3615
     3616/**
     3617 * Creates the initial theme features when the 'setup_theme' action is fired.
     3618 *
     3619 * See {@see 'setup_theme'}.
     3620 *
     3621 * @since 5.5.0
     3622 */
     3623function create_initial_theme_features() {
     3624        register_theme_feature(
     3625                'align-wide',
     3626                array(
     3627                        'description'  => __( 'Whether theme opts in to wide alignment CSS class.' ),
     3628                        'show_in_rest' => true,
     3629                )
     3630        );
     3631        register_theme_feature(
     3632                'automatic-feed-links',
     3633                array(
     3634                        'description'  => __( 'Whether posts and comments RSS feed links are added to head.' ),
     3635                        'show_in_rest' => true,
     3636                )
     3637        );
     3638        register_theme_feature(
     3639                'custom-background',
     3640                array(
     3641                        'description'  => __( 'Custom background if defined by the theme.' ),
     3642                        'type'         => 'object',
     3643                        'show_in_rest' => array(
     3644                                'schema' => array(
     3645                                        'properties' => array(
     3646                                                'default-image'      => array(
     3647                                                        'type'   => 'string',
     3648                                                        'format' => 'uri',
     3649                                                ),
     3650                                                'default-preset'     => array(
     3651                                                        'type' => 'string',
     3652                                                        'enum' => array(
     3653                                                                'default',
     3654                                                                'fill',
     3655                                                                'fit',
     3656                                                                'repeat',
     3657                                                                'custom',
     3658                                                        ),
     3659                                                ),
     3660                                                'default-position-x' => array(
     3661                                                        'type' => 'string',
     3662                                                        'enum' => array(
     3663                                                                'left',
     3664                                                                'center',
     3665                                                                'right',
     3666                                                        ),
     3667                                                ),
     3668                                                'default-position-y' => array(
     3669                                                        'type' => 'string',
     3670                                                        'enum' => array(
     3671                                                                'left',
     3672                                                                'center',
     3673                                                                'right',
     3674                                                        ),
     3675                                                ),
     3676                                                'default-size'       => array(
     3677                                                        'type' => 'string',
     3678                                                        'enum' => array(
     3679                                                                'auto',
     3680                                                                'contain',
     3681                                                                'cover',
     3682                                                        ),
     3683                                                ),
     3684                                                'default-repeat'     => array(
     3685                                                        'type' => 'string',
     3686                                                        'enum' => array(
     3687                                                                'repeat-x',
     3688                                                                'repeat-y',
     3689                                                                'repeat',
     3690                                                                'no-repeat',
     3691                                                        ),
     3692                                                ),
     3693                                                'default-attachment' => array(
     3694                                                        'type' => 'string',
     3695                                                        'enum' => array(
     3696                                                                'scroll',
     3697                                                                'fixed',
     3698                                                        ),
     3699                                                ),
     3700                                                'default-color'      => array(
     3701                                                        'type' => 'string',
     3702                                                ),
     3703                                        ),
     3704                                ),
     3705                        ),
     3706                )
     3707        );
     3708        register_theme_feature(
     3709                'custom-header',
     3710                array(
     3711                        'description'  => __( 'Custom header if defined by the theme.' ),
     3712                        'type'         => 'object',
     3713                        'show_in_rest' => array(
     3714                                'schema' => array(
     3715                                        'properties' => array(
     3716                                                'default-image'      => array(
     3717                                                        'type'   => 'string',
     3718                                                        'format' => 'uri',
     3719                                                ),
     3720                                                'random-default'     => array(
     3721                                                        'type' => 'boolean',
     3722                                                ),
     3723                                                'width'              => array(
     3724                                                        'type' => 'integer',
     3725                                                ),
     3726                                                'height'             => array(
     3727                                                        'type' => 'integer',
     3728                                                ),
     3729                                                'flex-height'        => array(
     3730                                                        'type' => 'boolean',
     3731                                                ),
     3732                                                'flex-width'         => array(
     3733                                                        'type' => 'boolean',
     3734                                                ),
     3735                                                'default-text-color' => array(
     3736                                                        'type' => 'string',
     3737                                                ),
     3738                                                'header-text'        => array(
     3739                                                        'type' => 'boolean',
     3740                                                ),
     3741                                                'uploads'            => array(
     3742                                                        'type' => 'boolean',
     3743                                                ),
     3744                                                'video'              => array(
     3745                                                        'type' => 'boolean',
     3746                                                ),
     3747                                        ),
     3748                                ),
     3749                        ),
     3750                )
     3751        );
     3752        register_theme_feature(
     3753                'custom-logo',
     3754                array(
     3755                        'type'         => 'object',
     3756                        'description'  => __( 'Custom logo if defined by the theme.' ),
     3757                        'show_in_rest' => array(
     3758                                'schema' => array(
     3759                                        'properties' => array(
     3760                                                'width'       => array(
     3761                                                        'type' => 'integer',
     3762                                                ),
     3763                                                'height'      => array(
     3764                                                        'type' => 'integer',
     3765                                                ),
     3766                                                'flex-width'  => array(
     3767                                                        'type' => 'boolean',
     3768                                                ),
     3769                                                'flex-height' => array(
     3770                                                        'type' => 'boolean',
     3771                                                ),
     3772                                                'header-text' => array(
     3773                                                        'type'  => 'array',
     3774                                                        'items' => array(
     3775                                                                'type' => 'string',
     3776                                                        ),
     3777                                                ),
     3778                                        ),
     3779                                ),
     3780                        ),
     3781                )
     3782        );
     3783        register_theme_feature(
     3784                'customize-selective-refresh-widgets',
     3785                array(
     3786                        'description'  => __( 'Whether the theme enables Selective Refresh for Widgets being managed with the Customizer.' ),
     3787                        'show_in_rest' => true,
     3788                )
     3789        );
     3790        register_theme_feature(
     3791                'dark-editor-style',
     3792                array(
     3793                        'description'  => __( 'Whether theme opts in to the dark editor style UI.' ),
     3794                        'show_in_rest' => true,
     3795                )
     3796        );
     3797        register_theme_feature(
     3798                'disable-custom-colors',
     3799                array(
     3800                        'description'  => __( 'Whether the theme disables custom colors.' ),
     3801                        'show_in_rest' => true,
     3802                )
     3803        );
     3804        register_theme_feature(
     3805                'disable-custom-font-sizes',
     3806                array(
     3807                        'description'  => __( 'Whether the theme disables custom font sizes.' ),
     3808                        'show_in_rest' => true,
     3809                )
     3810        );
     3811        register_theme_feature(
     3812                'disable-custom-gradients',
     3813                array(
     3814                        'description'  => __( 'Whether the theme disables custom gradients.' ),
     3815                        'show_in_rest' => true,
     3816                )
     3817        );
     3818        register_theme_feature(
     3819                'editor-color-palette',
     3820                array(
     3821                        'type'         => 'array',
     3822                        'description'  => __( 'Custom color palette if defined by the theme.' ),
     3823                        'show_in_rest' => array(
     3824                                'schema' => array(
     3825                                        'items' => array(
     3826                                                'type'       => 'object',
     3827                                                'properties' => array(
     3828                                                        'name'  => array(
     3829                                                                'type' => 'string',
     3830                                                        ),
     3831                                                        'slug'  => array(
     3832                                                                'type' => 'string',
     3833                                                        ),
     3834                                                        'color' => array(
     3835                                                                'type' => 'string',
     3836                                                        ),
     3837                                                ),
     3838                                        ),
     3839                                ),
     3840                        ),
     3841                )
     3842        );
     3843        register_theme_feature(
     3844                'editor-font-sizes',
     3845                array(
     3846                        'type'         => 'array',
     3847                        'description'  => __( 'Custom font sizes if defined by the theme.' ),
     3848                        'show_in_rest' => array(
     3849                                'schema' => array(
     3850                                        'items' => array(
     3851                                                'type'       => 'object',
     3852                                                'properties' => array(
     3853                                                        'name' => array(
     3854                                                                'type' => 'string',
     3855                                                        ),
     3856                                                        'size' => array(
     3857                                                                'type' => 'number',
     3858                                                        ),
     3859                                                        'slug' => array(
     3860                                                                'type' => 'string',
     3861                                                        ),
     3862                                                ),
     3863                                        ),
     3864                                ),
     3865                        ),
     3866                )
     3867        );
     3868        register_theme_feature(
     3869                'editor-gradient-presets',
     3870                array(
     3871                        'type'         => 'array',
     3872                        'description'  => __( 'Custom gradient presets if defined by the theme.' ),
     3873                        'show_in_rest' => array(
     3874                                'schema' => array(
     3875                                        'items' => array(
     3876                                                'type'       => 'object',
     3877                                                'properties' => array(
     3878                                                        'name'     => array(
     3879                                                                'type' => 'string',
     3880                                                        ),
     3881                                                        'gradient' => array(
     3882                                                                'type' => 'string',
     3883                                                        ),
     3884                                                        'slug'     => array(
     3885                                                                'type' => 'string',
     3886                                                        ),
     3887                                                ),
     3888                                        ),
     3889                                ),
     3890                        ),
     3891                )
     3892        );
     3893        register_theme_feature(
     3894                'editor-styles',
     3895                array(
     3896                        'description'  => __( 'Whether theme opts in to the editor styles CSS wrapper.' ),
     3897                        'show_in_rest' => true,
     3898                )
     3899        );
     3900        register_theme_feature(
     3901                'html5',
     3902                array(
     3903                        'type'         => 'array',
     3904                        'description'  => __( 'Allows use of HTML5 markup for search forms, comment forms, comment lists, gallery, and caption.' ),
     3905                        'show_in_rest' => array(
     3906                                'schema' => array(
     3907                                        'items' => array(
     3908                                                'type' => 'string',
     3909                                                'enum' => array(
     3910                                                        'search-form',
     3911                                                        'comment-form',
     3912                                                        'comment-list',
     3913                                                        'gallery',
     3914                                                        'caption',
     3915                                                        'script',
     3916                                                        'style',
     3917                                                ),
     3918                                        ),
     3919                                ),
     3920                        ),
     3921                )
     3922        );
     3923        register_theme_feature(
     3924                'post-formats',
     3925                array(
     3926                        'type'         => 'array',
     3927                        'description'  => __( 'Post formats supported.' ),
     3928                        'show_in_rest' => array(
     3929                                'name'             => 'formats',
     3930                                'schema'           => array(
     3931                                        'items'   => array(
     3932                                                'type' => 'string',
     3933                                                'enum' => get_post_format_slugs(),
     3934                                        ),
     3935                                        'default' => array( 'standard' ),
     3936                                ),
     3937                                'prepare_callback' => static function ( $formats ) {
     3938                                        $formats = is_array( $formats ) ? array_values( $formats[0] ) : array();
     3939                                        $formats = array_merge( array( 'standard' ), $formats );
     3940
     3941                                        return $formats;
     3942                                },
     3943                        ),
     3944                )
     3945        );
     3946        register_theme_feature(
     3947                'post-thumbnails',
     3948                array(
     3949                        'type'         => 'array',
     3950                        'description'  => __( 'The post types that support thumbnails or true if all post types are supported.' ),
     3951                        'show_in_rest' => array(
     3952                                'type'   => array( 'boolean', 'array' ),
     3953                                'schema' => array(
     3954                                        'items' => array(
     3955                                                'type' => 'string',
     3956                                        ),
     3957                                ),
     3958                        ),
     3959                )
     3960        );
     3961        register_theme_feature(
     3962                'responsive-embeds',
     3963                array(
     3964                        'description'  => __( 'Whether the theme supports responsive embedded content.' ),
     3965                        'show_in_rest' => true,
     3966                )
     3967        );
     3968        register_theme_feature(
     3969                'title-tag',
     3970                array(
     3971                        'description'  => __( 'Whether the theme can manage the document title tag.' ),
     3972                        'show_in_rest' => true,
     3973                )
     3974        );
     3975        register_theme_feature(
     3976                'wp-block-styles',
     3977                array(
     3978                        'description'  => __( 'Whether theme opts in to default WordPress block styles for viewing.' ),
     3979                        'show_in_rest' => true,
     3980                )
     3981        );
     3982}
Note: See TracChangeset for help on using the changeset viewer.