Make WordPress Core


Ignore:
Timestamp:
06/04/2024 11:53:37 AM (2 years ago)
Author:
ellatrix
Message:

Editor: Add theme.json v3 migrations.

See https://github.com/WordPress/wordpress-develop/pull/6616.
See also the original Gutenberg PRs:

Fixes #61282.

Props ajlende, talldanwp, ramonopoly, ellatrix.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-theme-json.php

    r58314 r58328  
    124124         * @since 6.2.0 Added 'shadow' presets.
    125125         * @since 6.3.0 Replaced value_func for duotone with `null`. Custom properties are handled by class-wp-duotone.php.
    126          * @since 6.6.0 Added the `dimensions.aspectRatios` & `dimensions.defaultAspectRatios` preset.
     126         * @since 6.6.0 Added the `dimensions.aspectRatios` and `dimensions.defaultAspectRatios` presets.
     127         *              Updated the 'prevent_override' value for font size presets to use 'typography.defaultFontSizes'
     128         *              and spacing size presets to use `spacing.defaultSpacingSizes`.
    127129         * @var array
    128130         */
     
    170172                array(
    171173                        'path'              => array( 'typography', 'fontSizes' ),
    172                         'prevent_override'  => false,
     174                        'prevent_override'  => array( 'typography', 'defaultFontSizes' ),
    173175                        'use_default_names' => true,
    174176                        'value_func'        => 'wp_get_typography_font_size_value',
     
    188190                array(
    189191                        'path'              => array( 'spacing', 'spacingSizes' ),
    190                         'prevent_override'  => false,
     192                        'prevent_override'  => array( 'spacing', 'defaultSpacingSizes' ),
    191193                        'use_default_names' => true,
    192194                        'value_key'         => 'size',
     
    379381         * @since 6.5.0 Added support for `layout.allowCustomContentAndWideSize`,
    380382         *              `background.backgroundSize` and `dimensions.aspectRatio`.
    381          * @since 6.6.0 Added support for `dimensions.aspectRatios` and `dimensions.defaultAspectRatios`.
     383         * @since 6.6.0 Added support for 'dimensions.aspectRatios', 'dimensions.defaultAspectRatios',
     384         *              'typography.defaultFontSizes', and 'spacing.defaultSpacingSizes'.
    382385         * @var array
    383386         */
     
    434437                ),
    435438                'spacing'                       => array(
    436                         'customSpacingSize' => null,
    437                         'spacingSizes'      => null,
    438                         'spacingScale'      => null,
    439                         'blockGap'          => null,
    440                         'margin'            => null,
    441                         'padding'           => null,
    442                         'units'             => null,
     439                        'customSpacingSize'   => null,
     440                        'defaultSpacingSizes' => null,
     441                        'spacingSizes'        => null,
     442                        'spacingScale'        => null,
     443                        'blockGap'            => null,
     444                        'margin'              => null,
     445                        'padding'             => null,
     446                        'units'               => null,
    443447                ),
    444448                'shadow'                        => array(
     
    447451                ),
    448452                'typography'                    => array(
    449                         'fluid'          => null,
    450                         'customFontSize' => null,
    451                         'dropCap'        => null,
    452                         'fontFamilies'   => null,
    453                         'fontSizes'      => null,
    454                         'fontStyle'      => null,
    455                         'fontWeight'     => null,
    456                         'letterSpacing'  => null,
    457                         'lineHeight'     => null,
    458                         'textAlign'      => null,
    459                         'textColumns'    => null,
    460                         'textDecoration' => null,
    461                         'textTransform'  => null,
    462                         'writingMode'    => null,
     453                        'fluid'            => null,
     454                        'customFontSize'   => null,
     455                        'defaultFontSizes' => null,
     456                        'dropCap'          => null,
     457                        'fontFamilies'     => null,
     458                        'fontSizes'        => null,
     459                        'fontStyle'        => null,
     460                        'fontWeight'       => null,
     461                        'letterSpacing'    => null,
     462                        'lineHeight'       => null,
     463                        'textAlign'        => null,
     464                        'textColumns'      => null,
     465                        'textDecoration'   => null,
     466                        'textTransform'    => null,
     467                        'writingMode'      => null,
    463468                ),
    464469        );
     
    729734         * @since 5.8.0
    730735         * @since 5.9.0 Changed value from 1 to 2.
     736         * @since 6.6.0 Changed value from 2 to 3.
    731737         * @var int
    732738         */
    733         const LATEST_SCHEMA = 2;
     739        const LATEST_SCHEMA = 3;
    734740
    735741        /**
     
    737743         *
    738744         * @since 5.8.0
     745         * @since 6.6.0 Key spacingScale by origin, and Pre-generate the
     746         *              spacingSizes from spacingScale.
    739747         *
    740748         * @param array  $theme_json A structure that follows the theme.json schema.
     
    742750         *                           One of 'default', 'theme', or 'custom'. Default 'theme'.
    743751         */
    744         public function __construct( $theme_json = array(), $origin = 'theme' ) {
     752        public function __construct( $theme_json = array( 'version' => WP_Theme_JSON::LATEST_SCHEMA ), $origin = 'theme' ) {
    745753                if ( ! in_array( $origin, static::VALID_ORIGINS, true ) ) {
    746754                        $origin = 'theme';
     
    751759                $valid_element_names = array_keys( static::ELEMENTS );
    752760                $valid_variations    = static::get_valid_block_style_variations();
    753                 $theme_json          = static::sanitize( $this->theme_json, $valid_block_names, $valid_element_names, $valid_variations );
    754                 $this->theme_json    = static::maybe_opt_in_into_settings( $theme_json );
     761                $this->theme_json    = static::sanitize( $this->theme_json, $valid_block_names, $valid_element_names, $valid_variations );
     762                $this->theme_json    = static::maybe_opt_in_into_settings( $this->theme_json );
    755763
    756764                // Internally, presets are keyed by origin.
     
    770778                                }
    771779                        }
     780                }
     781
     782                // In addition to presets, spacingScale (which generates presets) is also keyed by origin.
     783                $scale_path    = array( 'settings', 'spacing', 'spacingScale' );
     784                $spacing_scale = _wp_array_get( $this->theme_json, $scale_path, null );
     785                if ( null !== $spacing_scale ) {
     786                        // If the spacingScale is not already keyed by origin.
     787                        if ( empty( array_intersect( array_keys( $spacing_scale ), static::VALID_ORIGINS ) ) ) {
     788                                _wp_array_set( $this->theme_json, $scale_path, array( $origin => $spacing_scale ) );
     789                        }
     790                }
     791
     792                // Pre-generate the spacingSizes from spacingScale.
     793                $scale_path    = array( 'settings', 'spacing', 'spacingScale', $origin );
     794                $spacing_scale = _wp_array_get( $this->theme_json, $scale_path, null );
     795                if ( isset( $spacing_scale ) ) {
     796                        $sizes_path           = array( 'settings', 'spacing', 'spacingSizes', $origin );
     797                        $spacing_sizes        = _wp_array_get( $this->theme_json, $sizes_path, array() );
     798                        $spacing_scale_sizes  = static::compute_spacing_sizes( $spacing_scale );
     799                        $merged_spacing_sizes = static::merge_spacing_sizes( $spacing_scale_sizes, $spacing_sizes );
     800                        _wp_array_set( $this->theme_json, $sizes_path, $merged_spacing_sizes );
    772801                }
    773802        }
     
    29152944                $incoming_data    = $incoming->get_raw_data();
    29162945                $this->theme_json = array_replace_recursive( $this->theme_json, $incoming_data );
     2946
     2947                /*
     2948                 * Recompute all the spacing sizes based on the new hierarchy of data. In the constructor
     2949                 * spacingScale and spacingSizes are both keyed by origin and VALID_ORIGINS is ordered, so
     2950                 * we can allow partial spacingScale data to inherit missing data from earlier layers when
     2951                 * computing the spacing sizes.
     2952                 *
     2953                 * This happens before the presets are merged to ensure that default spacing sizes can be
     2954                 * removed from the theme origin if $prevent_override is true.
     2955                 */
     2956                $flattened_spacing_scale = array();
     2957                foreach ( static::VALID_ORIGINS as $origin ) {
     2958                        $scale_path = array( 'settings', 'spacing', 'spacingScale', $origin );
     2959
     2960                        // Apply the base spacing scale to the current layer.
     2961                        $base_spacing_scale      = _wp_array_get( $this->theme_json, $scale_path, array() );
     2962                        $flattened_spacing_scale = array_replace( $flattened_spacing_scale, $base_spacing_scale );
     2963
     2964                        $spacing_scale = _wp_array_get( $incoming_data, $scale_path, null );
     2965                        if ( ! isset( $spacing_scale ) ) {
     2966                                continue;
     2967                        }
     2968
     2969                        // Allow partial scale settings by merging with lower layers.
     2970                        $flattened_spacing_scale = array_replace( $flattened_spacing_scale, $spacing_scale );
     2971
     2972                        // Generate and merge the scales for this layer.
     2973                        $sizes_path           = array( 'settings', 'spacing', 'spacingSizes', $origin );
     2974                        $spacing_sizes        = _wp_array_get( $incoming_data, $sizes_path, array() );
     2975                        $spacing_scale_sizes  = static::compute_spacing_sizes( $flattened_spacing_scale );
     2976                        $merged_spacing_sizes = static::merge_spacing_sizes( $spacing_scale_sizes, $spacing_sizes );
     2977
     2978                        _wp_array_set( $incoming_data, $sizes_path, $merged_spacing_sizes );
     2979                }
    29172980
    29182981                /*
     
    29523015
    29533016                        // Replace the presets.
    2954                         foreach ( static::PRESETS_METADATA as $preset ) {
    2955                                 $override_preset = ! static::get_metadata_boolean( $this->theme_json['settings'], $preset['prevent_override'], true );
     3017                        foreach ( static::PRESETS_METADATA as $preset_metadata ) {
     3018                                $prevent_override = $preset_metadata['prevent_override'];
     3019                                if ( is_array( $prevent_override ) ) {
     3020                                        $prevent_override = _wp_array_get( $this->theme_json['settings'], $preset_metadata['prevent_override'] );
     3021                                }
    29563022
    29573023                                foreach ( static::VALID_ORIGINS as $origin ) {
    29583024                                        $base_path = $node['path'];
    2959                                         foreach ( $preset['path'] as $leaf ) {
     3025                                        foreach ( $preset_metadata['path'] as $leaf ) {
    29603026                                                $base_path[] = $leaf;
    29613027                                        }
     
    29693035                                        }
    29703036
    2971                                         if ( 'theme' === $origin && $preset['use_default_names'] ) {
     3037                                        // Set names for theme presets based on the slug if they are not set and can use default names.
     3038                                        if ( 'theme' === $origin && $preset_metadata['use_default_names'] ) {
    29723039                                                foreach ( $content as $key => $item ) {
    29733040                                                        if ( ! isset( $item['name'] ) ) {
     
    29803047                                        }
    29813048
    2982                                         if (
    2983                                                 ( 'theme' !== $origin ) ||
    2984                                                 ( 'theme' === $origin && $override_preset )
    2985                                         ) {
    2986                                                 _wp_array_set( $this->theme_json, $path, $content );
    2987                                         } else {
    2988                                                 $slugs_node = static::get_default_slugs( $this->theme_json, $node['path'] );
    2989                                                 $slugs      = array_merge_recursive( $slugs_global, $slugs_node );
    2990 
    2991                                                 $slugs_for_preset = _wp_array_get( $slugs, $preset['path'], array() );
    2992                                                 $content          = static::filter_slugs( $content, $slugs_for_preset );
    2993                                                 _wp_array_set( $this->theme_json, $path, $content );
     3049                                        // Filter out default slugs from theme presets when defaults should not be overridden.
     3050                                        if ( 'theme' === $origin && $prevent_override ) {
     3051                                                $slugs_node    = static::get_default_slugs( $this->theme_json, $node['path'] );
     3052                                                $preset_global = _wp_array_get( $slugs_global, $preset_metadata['path'], array() );
     3053                                                $preset_node   = _wp_array_get( $slugs_node, $preset_metadata['path'], array() );
     3054                                                $preset_slugs  = array_merge_recursive( $preset_global, $preset_node );
     3055
     3056                                                $content = static::filter_slugs( $content, $preset_slugs );
    29943057                                        }
     3058
     3059                                        _wp_array_set( $this->theme_json, $path, $content );
    29953060                                }
    29963061                        }
     
    35293594                        }
    35303595                        $theme_settings['settings']['spacing']['padding'] = $settings['enableCustomSpacing'];
     3596                }
     3597
     3598                if ( isset( $settings['spacingSizes'] ) ) {
     3599                        if ( ! isset( $theme_settings['settings']['spacing'] ) ) {
     3600                                $theme_settings['settings']['spacing'] = array();
     3601                        }
     3602                        $theme_settings['settings']['spacing']['spacingSizes'] = $settings['spacingSizes'];
    35313603                }
    35323604
     
    37043776         *
    37053777         * @since 6.1.0
     3778         * @deprecated 6.6.0
     3779         *
     3780         * @param string $origin Optional. What source of data to set the spacing sizes for.
     3781         *                       One of 'default', 'theme', or 'custom'. Default 'default'.
    37063782         *
    37073783         * @return null|void
    37083784         */
    37093785        public function set_spacing_sizes() {
     3786                _deprecated_function( __METHOD__, '6.6.0' );
     3787
    37103788                $spacing_scale = isset( $this->theme_json['settings']['spacing']['spacingScale'] )
    37113789                        ? $this->theme_json['settings']['spacing']['spacingScale']
     
    37413819                }
    37423820
     3821                $spacing_sizes = static::compute_spacing_sizes( $spacing_scale );
     3822
     3823                // If there are 7 or fewer steps in the scale revert to numbers for labels instead of t-shirt sizes.
     3824                if ( $spacing_scale['steps'] <= 7 ) {
     3825                        for ( $spacing_sizes_count = 0; $spacing_sizes_count < count( $spacing_sizes ); $spacing_sizes_count++ ) {
     3826                                $spacing_sizes[ $spacing_sizes_count ]['name'] = (string) ( $spacing_sizes_count + 1 );
     3827                        }
     3828                }
     3829
     3830                _wp_array_set( $this->theme_json, array( 'settings', 'spacing', 'spacingSizes', 'default' ), $spacing_sizes );
     3831        }
     3832
     3833        /**
     3834         * Merges two sets of spacing size presets.
     3835         *
     3836         * @since 6.6.0
     3837         *
     3838         * @param array $base     The base set of spacing sizes.
     3839         * @param array $incoming The set of spacing sizes to merge with the base. Duplicate slugs will override the base values.
     3840         * @return array The merged set of spacing sizes.
     3841         */
     3842        private static function merge_spacing_sizes( $base, $incoming ) {
     3843                // Preserve the order if there are no base (spacingScale) values.
     3844                if ( empty( $base ) ) {
     3845                        return $incoming;
     3846                }
     3847                $merged = array();
     3848                foreach ( $base as $item ) {
     3849                        $merged[ $item['slug'] ] = $item;
     3850                }
     3851                foreach ( $incoming as $item ) {
     3852                        $merged[ $item['slug'] ] = $item;
     3853                }
     3854                ksort( $merged, SORT_NUMERIC );
     3855                return array_values( $merged );
     3856        }
     3857
     3858        /**
     3859         * Generates a set of spacing sizes by starting with a medium size and
     3860         * applying an operator with an increment value to generate the rest of the
     3861         * sizes outward from the medium size. The medium slug is '50' with the rest
     3862         * of the slugs being 10 apart. The generated names use t-shirt sizing.
     3863         *
     3864         * Example:
     3865         *
     3866         *     $spacing_scale = array(
     3867         *         'steps'      => 4,
     3868         *         'mediumStep' => 16,
     3869         *         'unit'       => 'px',
     3870         *         'operator'   => '+',
     3871         *         'increment'  => 2,
     3872         *     );
     3873         *     $spacing_sizes = static::compute_spacing_sizes( $spacing_scale );
     3874         *     // -> array(
     3875         *     //        array( 'name' => 'Small',   'slug' => '40', 'size' => '14px' ),
     3876         *     //        array( 'name' => 'Medium',  'slug' => '50', 'size' => '16px' ),
     3877         *     //        array( 'name' => 'Large',   'slug' => '60', 'size' => '18px' ),
     3878         *     //        array( 'name' => 'X-Large', 'slug' => '70', 'size' => '20px' ),
     3879         *     //    )
     3880         *
     3881         * @since 6.6.0
     3882         *
     3883         * @param array $spacing_scale {
     3884         *      The spacing scale values. All are required.
     3885         *
     3886         *      @type int    $steps      The number of steps in the scale. (up to 10 steps are supported.)
     3887         *      @type float  $mediumStep The middle value that gets the slug '50'. (For even number of steps, this becomes the first middle value.)
     3888         *      @type string $unit       The CSS unit to use for the sizes.
     3889         *      @type string $operator   The mathematical operator to apply to generate the other sizes. Either '+' or '*'.
     3890         *      @type float  $increment  The value used with the operator to generate the other sizes.
     3891         * }
     3892         * @return array The spacing sizes presets or an empty array if some spacing scale values are missing or invalid.
     3893         */
     3894        private static function compute_spacing_sizes( $spacing_scale ) {
     3895                /*
     3896                 * This condition is intentionally missing some checks on ranges for the values in order to
     3897                 * keep backwards compatibility with the previous implementation.
     3898                 */
     3899                if (
     3900                        ! isset( $spacing_scale['steps'] ) ||
     3901                        ! is_numeric( $spacing_scale['steps'] ) ||
     3902                        0 === $spacing_scale['steps'] ||
     3903                        ! isset( $spacing_scale['mediumStep'] ) ||
     3904                        ! is_numeric( $spacing_scale['mediumStep'] ) ||
     3905                        ! isset( $spacing_scale['unit'] ) ||
     3906                        ! isset( $spacing_scale['operator'] ) ||
     3907                        ( '+' !== $spacing_scale['operator'] && '*' !== $spacing_scale['operator'] ) ||
     3908                        ! isset( $spacing_scale['increment'] ) ||
     3909                        ! is_numeric( $spacing_scale['increment'] )
     3910                ) {
     3911                        return array();
     3912                }
     3913
    37433914                $unit            = '%' === $spacing_scale['unit'] ? '%' : sanitize_title( $spacing_scale['unit'] );
    37443915                $current_step    = $spacing_scale['mediumStep'];
     
    38233994                }
    38243995
    3825                 // If there are 7 or fewer steps in the scale revert to numbers for labels instead of t-shirt sizes.
    3826                 if ( $spacing_scale['steps'] <= 7 ) {
    3827                         for ( $spacing_sizes_count = 0; $spacing_sizes_count < count( $spacing_sizes ); $spacing_sizes_count++ ) {
    3828                                 $spacing_sizes[ $spacing_sizes_count ]['name'] = (string) ( $spacing_sizes_count + 1 );
    3829                         }
    3830                 }
    3831 
    3832                 _wp_array_set( $this->theme_json, array( 'settings', 'spacing', 'spacingSizes', 'default' ), $spacing_sizes );
     3996                return $spacing_sizes;
    38333997        }
    38343998
Note: See TracChangeset for help on using the changeset viewer.