Skip to content

Commit c80dc90

Browse files
ajlendeajlendeMaggieCabreraellatrixbgardner
authored andcommitted
Add defaultSpacingSizes option (theme.json v3) (WordPress#61842)
Co-authored-by: ajlende <ajlende@git.wordpress.org> Co-authored-by: MaggieCabrera <onemaggie@git.wordpress.org> Co-authored-by: ellatrix <ellatrix@git.wordpress.org> Co-authored-by: bgardner <bgardner@git.wordpress.org> Co-authored-by: carolinan <poena@git.wordpress.org> Co-authored-by: dabowman <davidabowman@git.wordpress.org> Co-authored-by: hanneslsm <hanneslsm@git.wordpress.org>
1 parent c298beb commit c80dc90

File tree

20 files changed

+400
-118
lines changed

20 files changed

+400
-118
lines changed

backport-changelog/6.6/6616.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
https://github.com/WordPress/wordpress-develop/pull/6616
2+
3+
* https://github.com/WordPress/gutenberg/pull/58409
4+
* https://github.com/WordPress/gutenberg/pull/61328
5+
* https://github.com/WordPress/gutenberg/pull/61842

docs/how-to-guides/themes/global-settings-and-styles.md

+1-10
Original file line numberDiff line numberDiff line change
@@ -336,16 +336,7 @@ The following presets can be defined via `theme.json`:
336336
- `color.palette`:
337337
- generates 3 classes per preset value: color, background-color, and border-color.
338338
- generates a single custom property per preset value.
339-
- `spacing.spacingScale`: used to generate an array of spacing preset sizes for use with padding, margin, and gap settings.
340-
- `operator`: specifies how to calculate the steps with either `*` for multiplier, or `+` for sum.
341-
- `increment`: the amount to increment each step by. Core by default uses a 'perfect 5th' multiplier of `1.5`.
342-
- `steps`: the number of steps to generate in the spacing scale. The default is 7. To prevent the generation of the spacing presets, and to disable the related UI, this can be set to `0`.
343-
- `mediumStep`: the steps in the scale are generated descending and ascending from a medium step, so this should be the size value of the medium space, without the unit. The default medium step is `1.5rem` so the mediumStep value is `1.5`.
344-
- `unit`: the unit the scale uses, eg. `px, rem, em, %`. The default is `rem`.
345-
- `spacing.spacingSizes`: themes can choose to include a static `spacing.spacingSizes` array of spacing preset sizes if they have a sequence of sizes that can't be generated via an increment or multiplier.
346-
- `name`: a human readable name for the size, eg. `Small, Medium, Large`.
347-
- `slug`: the machine readable name. In order to provide the best cross site/theme compatibility the slugs should be in the format, "10","20","30","40","50","60", with "50" representing the `Medium` size value.
348-
- `size`: the size, including the unit, eg. `1.5rem`. It is possible to include fluid values like `clamp(2rem, 10vw, 20rem)`.
339+
- `spacing.spacingSizes`/`spacing.spacingScale`: generates a single custom property per preset value.
349340
- `typography.fontSizes`: generates a single class and custom property per preset value.
350341
- `typography.fontFamilies`: generates a single custom property per preset value.
351342

docs/reference-guides/theme-json-reference/theme-json-living.md

+1
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ Settings related to spacing.
167167
| padding | boolean | false | |
168168
| units | array | px,em,rem,vh,vw,% | |
169169
| customSpacingSize | boolean | true | |
170+
| defaultSpacingSizes | boolean | true | |
170171
| spacingSizes | array | | name, size, slug |
171172
| spacingScale | object | | |
172173

docs/reference-guides/theme-json-reference/theme-json-migrations.md

+21-2
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,27 @@ The new `defaultFontSizes` option gives control over showing default font sizes
8888

8989
It is `true` by default when switching to v3. This is to be consistent with how other `default*` options work such as `settings.color.defaultPalette`, but differs from the behavior in v2.
9090

91-
In theme.json v2, the default font sizes were only shown when theme sizes were not defined. A theme providing font sizes with the same slugs as the defaults would always override the default ones.
92-
9391
To keep behavior similar to v2 with a v3 theme.json:
9492
* If you do not have any `fontSizes` defined, `defaultFontSizes` can be left out or set to `true`.
9593
* If you have some `fontSizes` defined, set `defaultFontSizes` to `false`.
94+
95+
#### `settings.spacing.defaultSpacingSizes`
96+
97+
In theme.json v2, there are two settings that could be used to set theme level spacing sizes: `settings.spacing.spacingSizes` and `settings.spacing.spacingScale`. Setting both `spacingSizes` _and_ `spacingScale` would only use the values from `spacingSizes`. And setting either of them would always replace the entire set of default spacing sizes provided by WordPress.
98+
99+
The default `spacingSizes` slugs provided by WordPress are: `20`, `30`, `40`, `50`, `60`, `70`, and `80`.
100+
101+
The new `defaultSpacingSizes` option gives control over showing default spacing sizes and preventing those defaults from being overridden.
102+
103+
- When set to `true` it will show the default spacing sizes and prevent them from being overridden by the theme.
104+
- When set to `false` it will hide the default spacing sizes and allow the theme to use the default slugs.
105+
106+
`defaultSpacingSizes` is `true` by default when switching to v3. This is to be consistent with how other `default*` options work such as `settings.color.defaultPalette`, but differs from the behavior in v2.
107+
108+
Additionally, in v3 both `spacingSizes` and `spacingScale` can be set at the same time. Presets defined in `spacingSizes` with slugs matching the generated presets from `spacingSizes` will override the generated ones.
109+
110+
To keep behavior similar to v2 with a v3 theme.json:
111+
* If you do not have any `spacingSizes` presets or `spacingScale` config defined, `defaultSpacingSizes` can be left out or set to `true`.
112+
* If you disabled default spacing sizes by setting `spacingScale` to `{ "steps": 0 }`, remove the `spacingScale` config and set `defaultSpacingSizes` to `false`.
113+
* If you defined only one of either `spacingScale` or `spacingSizes` for your presets, set `defaultSpacingSizes` to `false`.
114+
* If you defined both `spacingScale` and `spacingSizes`, remove the `spacingSizes` config _and_ set `defaultSpacingSizes` to `false`.

lib/class-wp-theme-json-gutenberg.php

+168-19
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ class WP_Theme_JSON_Gutenberg {
123123
* @since 6.0.0 Replaced `override` with `prevent_override` and updated the
124124
* `prevent_override` value for `color.duotone` to use `color.defaultDuotone`.
125125
* @since 6.2.0 Added 'shadow' presets.
126+
* @since 6.6.0 Updated the 'prevent_override' value for font size presets to use 'typography.defaultFontSizes' and spacing size presets to use `spacing.defaultSpacingSizes`.
126127
* @since 6.6.0 Added `aspectRatios`.
127128
* @var array
128129
*/
@@ -187,7 +188,7 @@ class WP_Theme_JSON_Gutenberg {
187188
),
188189
array(
189190
'path' => array( 'spacing', 'spacingSizes' ),
190-
'prevent_override' => false,
191+
'prevent_override' => array( 'spacing', 'defaultSpacingSizes' ),
191192
'use_default_names' => true,
192193
'value_key' => 'size',
193194
'css_vars' => '--wp--preset--spacing--$slug',
@@ -427,13 +428,14 @@ class WP_Theme_JSON_Gutenberg {
427428
'sticky' => null,
428429
),
429430
'spacing' => array(
430-
'customSpacingSize' => null,
431-
'spacingSizes' => null,
432-
'spacingScale' => null,
433-
'blockGap' => null,
434-
'margin' => null,
435-
'padding' => null,
436-
'units' => null,
431+
'customSpacingSize' => null,
432+
'defaultSpacingSizes' => null,
433+
'spacingSizes' => null,
434+
'spacingScale' => null,
435+
'blockGap' => null,
436+
'margin' => null,
437+
'padding' => null,
438+
'units' => null,
437439
),
438440
'shadow' => array(
439441
'presets' => null,
@@ -727,6 +729,8 @@ public static function get_element_class_name( $element ) {
727729
* Constructor.
728730
*
729731
* @since 5.8.0
732+
* @since 6.6.0 Key spacingScale by origin, and pre-generate the
733+
* spacingSizes from spacingScale.
730734
*
731735
* @param array $theme_json A structure that follows the theme.json schema.
732736
* @param string $origin Optional. What source of data this object represents.
@@ -742,8 +746,8 @@ public function __construct( $theme_json = array( 'version' => WP_Theme_JSON_Gut
742746
$valid_block_names = array_keys( $registry->get_all_registered() );
743747
$valid_element_names = array_keys( static::ELEMENTS );
744748
$valid_variations = static::get_valid_block_style_variations();
745-
$theme_json = static::sanitize( $this->theme_json, $valid_block_names, $valid_element_names, $valid_variations );
746-
$this->theme_json = static::maybe_opt_in_into_settings( $theme_json );
749+
$this->theme_json = static::sanitize( $this->theme_json, $valid_block_names, $valid_element_names, $valid_variations );
750+
$this->theme_json = static::maybe_opt_in_into_settings( $this->theme_json );
747751

748752
// Internally, presets are keyed by origin.
749753
$nodes = static::get_setting_nodes( $this->theme_json );
@@ -762,6 +766,27 @@ public function __construct( $theme_json = array( 'version' => WP_Theme_JSON_Gut
762766
}
763767
}
764768
}
769+
770+
// In addition to presets, spacingScale (which generates presets) is also keyed by origin.
771+
$scale_path = array( 'settings', 'spacing', 'spacingScale' );
772+
$spacing_scale = _wp_array_get( $this->theme_json, $scale_path, null );
773+
if ( null !== $spacing_scale ) {
774+
// If the spacingScale is not already keyed by origin.
775+
if ( empty( array_intersect( array_keys( $spacing_scale ), static::VALID_ORIGINS ) ) ) {
776+
_wp_array_set( $this->theme_json, $scale_path, array( $origin => $spacing_scale ) );
777+
}
778+
}
779+
780+
// Pre-generate the spacingSizes from spacingScale.
781+
$scale_path = array( 'settings', 'spacing', 'spacingScale', $origin );
782+
$spacing_scale = _wp_array_get( $this->theme_json, $scale_path, null );
783+
if ( isset( $spacing_scale ) ) {
784+
$sizes_path = array( 'settings', 'spacing', 'spacingSizes', $origin );
785+
$spacing_sizes = _wp_array_get( $this->theme_json, $sizes_path, array() );
786+
$spacing_scale_sizes = static::compute_spacing_sizes( $spacing_scale );
787+
$merged_spacing_sizes = static::merge_spacing_sizes( $spacing_scale_sizes, $spacing_sizes );
788+
_wp_array_set( $this->theme_json, $sizes_path, $merged_spacing_sizes );
789+
}
765790
}
766791

767792
/**
@@ -2947,13 +2972,49 @@ protected static function get_metadata_boolean( $data, $path, $default_value = f
29472972
*
29482973
* @since 5.8.0
29492974
* @since 5.9.0 Duotone preset also has origins.
2975+
* @since 6.6.0 Use the spacingScale keyed by origin, and re-generate the
2976+
* spacingSizes from spacingScale.
29502977
*
29512978
* @param WP_Theme_JSON_Gutenberg $incoming Data to merge.
29522979
*/
29532980
public function merge( $incoming ) {
29542981
$incoming_data = $incoming->get_raw_data();
29552982
$this->theme_json = array_replace_recursive( $this->theme_json, $incoming_data );
29562983

2984+
/*
2985+
* Recompute all the spacing sizes based on the new hierarchy of data. In the constructor
2986+
* spacingScale and spacingSizes are both keyed by origin and VALID_ORIGINS is ordered, so
2987+
* we can allow partial spacingScale data to inherit missing data from earlier layers when
2988+
* computing the spacing sizes.
2989+
*
2990+
* This happens before the presets are merged to ensure that default spacing sizes can be
2991+
* removed from the theme origin if $prevent_override is true.
2992+
*/
2993+
$flattened_spacing_scale = array();
2994+
foreach ( static::VALID_ORIGINS as $origin ) {
2995+
$scale_path = array( 'settings', 'spacing', 'spacingScale', $origin );
2996+
2997+
// Apply the base spacing scale to the current layer.
2998+
$base_spacing_scale = _wp_array_get( $this->theme_json, $scale_path, array() );
2999+
$flattened_spacing_scale = array_replace( $flattened_spacing_scale, $base_spacing_scale );
3000+
3001+
$spacing_scale = _wp_array_get( $incoming_data, $scale_path, null );
3002+
if ( ! isset( $spacing_scale ) ) {
3003+
continue;
3004+
}
3005+
3006+
// Allow partial scale settings by merging with lower layers.
3007+
$flattened_spacing_scale = array_replace( $flattened_spacing_scale, $spacing_scale );
3008+
3009+
// Generate and merge the scales for this layer.
3010+
$sizes_path = array( 'settings', 'spacing', 'spacingSizes', $origin );
3011+
$spacing_sizes = _wp_array_get( $incoming_data, $sizes_path, array() );
3012+
$spacing_scale_sizes = static::compute_spacing_sizes( $flattened_spacing_scale );
3013+
$merged_spacing_sizes = static::merge_spacing_sizes( $spacing_scale_sizes, $spacing_sizes );
3014+
3015+
_wp_array_set( $incoming_data, $sizes_path, $merged_spacing_sizes );
3016+
}
3017+
29573018
/*
29583019
* The array_replace_recursive algorithm merges at the leaf level,
29593020
* but we don't want leaf arrays to be merged, so we overwrite it.
@@ -3733,12 +3794,19 @@ public function get_data() {
37333794
/**
37343795
* Sets the spacingSizes array based on the spacingScale values from theme.json.
37353796
*
3797+
* No longer used since theme.json version 3 as the spacingSizes are now
3798+
* automatically generated during construction and merge instead of manually
3799+
* set in the resolver.
3800+
*
37363801
* @since 6.1.0
3802+
* @deprecated 6.6.0
37373803
*
37383804
* @return null|void
37393805
*/
37403806
public function set_spacing_sizes() {
3741-
$spacing_scale = $this->theme_json['settings']['spacing']['spacingScale'] ?? array();
3807+
_deprecated_function( __METHOD__, '6.6.0' );
3808+
3809+
$spacing_scale = $this->theme_json['settings']['spacing']['spacingScale']['default'] ?? array();
37423810

37433811
// Gutenberg didn't have the 1st isset check.
37443812
if ( ! isset( $spacing_scale['steps'] )
@@ -3762,6 +3830,94 @@ public function set_spacing_sizes() {
37623830
return null;
37633831
}
37643832

3833+
$spacing_sizes = static::compute_spacing_sizes( $spacing_scale );
3834+
3835+
// If there are 7 or less steps in the scale revert to numbers for labels instead of t-shirt sizes.
3836+
if ( $spacing_scale['steps'] <= 7 ) {
3837+
for ( $spacing_sizes_count = 0; $spacing_sizes_count < count( $spacing_sizes ); $spacing_sizes_count++ ) {
3838+
$spacing_sizes[ $spacing_sizes_count ]['name'] = (string) ( $spacing_sizes_count + 1 );
3839+
}
3840+
}
3841+
3842+
_wp_array_set( $this->theme_json, array( 'settings', 'spacing', 'spacingSizes', 'default' ), $spacing_sizes );
3843+
}
3844+
3845+
/**
3846+
* Merges two sets of spacing size presets.
3847+
*
3848+
* @since 6.6.0
3849+
*
3850+
* @param array $base The base set of spacing sizes.
3851+
* @param array $incoming The set of spacing sizes to merge with the base. Duplicate slugs will override the base values.
3852+
* @return array The merged set of spacing sizes.
3853+
*/
3854+
private static function merge_spacing_sizes( $base, $incoming ) {
3855+
$merged = array();
3856+
foreach ( $base as $item ) {
3857+
$merged[ $item['slug'] ] = $item;
3858+
}
3859+
foreach ( $incoming as $item ) {
3860+
$merged[ $item['slug'] ] = $item;
3861+
}
3862+
return array_values( $merged );
3863+
}
3864+
3865+
/**
3866+
* Generates a set of spacing sizes by starting with a medium size and
3867+
* applying an operator with an increment value to generate the rest of the
3868+
* sizes outward from the medium size. The medium slug is '50' with the rest
3869+
* of the slugs being 10 apart. The generated names use t-shirt sizing.
3870+
*
3871+
* Example:
3872+
*
3873+
* $spacing_scale = array(
3874+
* 'steps' => 4,
3875+
* 'mediumStep' => 16,
3876+
* 'unit' => 'px',
3877+
* 'operator' => '+',
3878+
* 'increment' => 2,
3879+
* );
3880+
* $spacing_sizes = static::compute_spacing_sizes( $spacing_scale );
3881+
* // -> array(
3882+
* // array( 'name' => 'Small', 'slug' => '40', 'size' => '14px' ),
3883+
* // array( 'name' => 'Medium', 'slug' => '50', 'size' => '16px' ),
3884+
* // array( 'name' => 'Large', 'slug' => '60', 'size' => '18px' ),
3885+
* // array( 'name' => 'X-Large', 'slug' => '70', 'size' => '20px' ),
3886+
* // )
3887+
*
3888+
* @since 6.6.0
3889+
*
3890+
* @param array $spacing_scale {
3891+
* The spacing scale values. All are required.
3892+
*
3893+
* @type int $steps The number of steps in the scale. (up to 10 steps are supported.)
3894+
* @type float $mediumStep The middle value that gets the slug '50'. (For even number of steps, this becomes the first middle value.)
3895+
* @type string $unit The CSS unit to use for the sizes.
3896+
* @type string $operator The mathematical operator to apply to generate the other sizes. Either '+' or '*'.
3897+
* @type float $increment The value used with the operator to generate the other sizes.
3898+
* }
3899+
* @return array The spacing sizes presets or an empty array if some spacing scale values are missing or invalid.
3900+
*/
3901+
private static function compute_spacing_sizes( $spacing_scale ) {
3902+
/*
3903+
* This condition is intentionally missing some checks on ranges for the values in order to
3904+
* keep backwards compatibility with the previous implementation.
3905+
*/
3906+
if (
3907+
! isset( $spacing_scale['steps'] ) ||
3908+
! is_numeric( $spacing_scale['steps'] ) ||
3909+
0 === $spacing_scale['steps'] ||
3910+
! isset( $spacing_scale['mediumStep'] ) ||
3911+
! is_numeric( $spacing_scale['mediumStep'] ) ||
3912+
! isset( $spacing_scale['unit'] ) ||
3913+
! isset( $spacing_scale['operator'] ) ||
3914+
( '+' !== $spacing_scale['operator'] && '*' !== $spacing_scale['operator'] ) ||
3915+
! isset( $spacing_scale['increment'] ) ||
3916+
! is_numeric( $spacing_scale['increment'] )
3917+
) {
3918+
return array();
3919+
}
3920+
37653921
$unit = '%' === $spacing_scale['unit'] ? '%' : sanitize_title( $spacing_scale['unit'] );
37663922
$current_step = $spacing_scale['mediumStep'];
37673923
$steps_mid_point = round( $spacing_scale['steps'] / 2, 0 );
@@ -3844,14 +4000,7 @@ public function set_spacing_sizes() {
38444000
$spacing_sizes[] = $above_sizes_item;
38454001
}
38464002

3847-
// If there are 7 or less steps in the scale revert to numbers for labels instead of t-shirt sizes.
3848-
if ( $spacing_scale['steps'] <= 7 ) {
3849-
for ( $spacing_sizes_count = 0; $spacing_sizes_count < count( $spacing_sizes ); $spacing_sizes_count++ ) {
3850-
$spacing_sizes[ $spacing_sizes_count ]['name'] = (string) ( $spacing_sizes_count + 1 );
3851-
}
3852-
}
3853-
3854-
_wp_array_set( $this->theme_json, array( 'settings', 'spacing', 'spacingSizes', 'default' ), $spacing_sizes );
4003+
return $spacing_sizes;
38554004
}
38564005

38574006
/**

lib/class-wp-theme-json-resolver-gutenberg.php

-3
Original file line numberDiff line numberDiff line change
@@ -600,7 +600,6 @@ public static function get_merged_data( $origin = 'custom' ) {
600600
$result = new WP_Theme_JSON_Gutenberg();
601601
$result->merge( static::get_core_data() );
602602
if ( 'default' === $origin ) {
603-
$result->set_spacing_sizes();
604603
return $result;
605604
}
606605

@@ -611,12 +610,10 @@ public static function get_merged_data( $origin = 'custom' ) {
611610

612611
$result->merge( static::get_theme_data() );
613612
if ( 'theme' === $origin ) {
614-
$result->set_spacing_sizes();
615613
return $result;
616614
}
617615

618616
$result->merge( static::get_user_data() );
619-
$result->set_spacing_sizes();
620617
return $result;
621618
}
622619

0 commit comments

Comments
 (0)