Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
343fafc
Refactor magic number to constant
ajlende May 21, 2024
21cf2ba
Add defaultSpacingSizes option
ajlende May 30, 2024
119bff1
Add migration docs
ajlende May 22, 2024
f19da26
Update API docs
ajlende May 22, 2024
9ede3bb
Refactor to not need constants
ajlende May 22, 2024
b3f304b
Update PHPUnit tests
ajlende May 22, 2024
666fc4e
Fix PHP lint
ajlende May 22, 2024
0301b49
Fix PHP lint
ajlende May 22, 2024
f5010ef
Make sure all spread vairables cannot be null
ajlende May 22, 2024
6fbb99f
Code cleanup
ajlende May 22, 2024
b1126b7
Add backport-changelog
ajlende May 23, 2024
8a5f339
Prevent spacingSizes from entirely replacing presets generated from s…
ajlende May 29, 2024
73d63a7
Be more specific about limits in the schema
ajlende May 29, 2024
ada604b
Move comment
ajlende May 29, 2024
882f02e
Increase limit to 10
ajlende May 30, 2024
3415b6a
Fix merging of origins
ajlende May 30, 2024
8529aef
Use old when checking for existance in migration
ajlende May 30, 2024
5d2762a
Fix copy/paste mistake
ajlende May 30, 2024
8093334
Fix some v2 backcompat
ajlende May 30, 2024
59eaac3
Don't bother with skipping pre-generation on v2 for filters
ajlende May 30, 2024
1aafb16
Switch back to numbers for labels in the range control
ajlende May 30, 2024
21e6de7
Deprecate set_spacing_sizes
ajlende May 30, 2024
d42932b
Remove comment
ajlende May 30, 2024
c5778d0
Remove incorrect doc param
ajlende May 30, 2024
31ac387
Clarify comment
ajlende May 30, 2024
17db2d4
Add method version docs
ajlende May 30, 2024
25dc819
Fix PHPUnit tests
ajlende May 30, 2024
144dc5a
Fix PHPUnit tests
ajlende May 30, 2024
a592617
Revert to bugged spacing scale check
ajlende May 30, 2024
1a3d0c2
Add comment about bad conditional
ajlende May 30, 2024
12edffa
Do sorting on all presets in UI only
ajlende May 30, 2024
44bf7b8
Add a check that slug begins with a number for sorting
ajlende May 30, 2024
de077ad
Reorder schema keys
ajlende May 30, 2024
d9c5c85
Quick fix for redundant info in the defaultFontSizes migration docs
ajlende May 31, 2024
1dfcaa3
Update defaultSpacingSizes migration docs to include merging of spaci…
ajlende May 31, 2024
2af96a3
Update the global settings and styles guide
ajlende May 31, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Prevent spacingSizes from entirely replacing presets generated from s…
…pacingScale
  • Loading branch information
ajlende committed May 30, 2024
commit 8a5f339b3cc3b2a149c75cddc7a3fb22d5aecf2f
224 changes: 207 additions & 17 deletions lib/class-wp-theme-json-gutenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ class WP_Theme_JSON_Gutenberg {
* @since 6.0.0 Replaced `override` with `prevent_override` and updated the
* `prevent_override` value for `color.duotone` to use `color.defaultDuotone`.
* @since 6.2.0 Added 'shadow' presets.
* @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`.
* @since 6.6.0 Added `aspectRatios`.
* @var array
*/
Expand Down Expand Up @@ -617,6 +618,51 @@ class WP_Theme_JSON_Gutenberg {
'typography' => 'typography',
);

/**
* List of valid settings.spacing.spacingScale.units values.
*
* @since 6.6.0
* @var array
*/
const VALID_SPACING_UNITS = array(
'px',
'em',
'rem',
'%',
'vw',
'svw',
'lvw',
'dvw',
'vh',
'svh',
'lvh',
'dvh',
'vi',
'svi',
'lvi',
'dvi',
'vb',
'svb',
'lvb',
'dvb',
'vmin',
'svmin',
'lvmin',
'dvmin',
'vmax',
'svmax',
'lvmax',
'dvmax',
);

/**
* List of valid settings.spacing.spacingScale.operator values.
*
* @since 6.6.0
* @var array
*/
const VALID_SPACING_OPERATORS = array( '+', '*' );

/**
* Return the input schema at the root and per origin.
*
Expand Down Expand Up @@ -728,6 +774,7 @@ public static function get_element_class_name( $element ) {
* Constructor.
*
* @since 5.8.0
* @since 6.6.0 Pre-generate the spacingSizes from spacingScale.
*
* @param array $theme_json A structure that follows the theme.json schema.
* @param string $origin Optional. What source of data this object represents.
Expand All @@ -743,13 +790,8 @@ public function __construct( $theme_json = array( 'version' => WP_Theme_JSON_Gut
$valid_block_names = array_keys( $registry->get_all_registered() );
$valid_element_names = array_keys( static::ELEMENTS );
$valid_variations = static::get_valid_block_style_variations();
$theme_json = static::sanitize( $this->theme_json, $valid_block_names, $valid_element_names, $valid_variations );
$this->theme_json = static::maybe_opt_in_into_settings( $theme_json );

// Set directly on the origin so it doesn't have to be moved below.
if ( empty( $this->theme_json['settings']['spacing']['spacingSizes'] ) ) {
$this->set_spacing_sizes( $origin );
}
$this->theme_json = static::sanitize( $this->theme_json, $valid_block_names, $valid_element_names, $valid_variations );
$this->theme_json = static::maybe_opt_in_into_settings( $this->theme_json );

// Internally, presets are keyed by origin.
$nodes = static::get_setting_nodes( $this->theme_json );
Expand All @@ -768,6 +810,32 @@ public function __construct( $theme_json = array( 'version' => WP_Theme_JSON_Gut
}
}
}

// In addition to presets, spacingScale (which generates presets) is also keyed by origin.
$scale_path = array( 'settings', 'spacing', 'spacingScale' );
$spacing_scale = _wp_array_get( $this->theme_json, $scale_path, null );
if ( null !== $spacing_scale ) {
// If the spacingScale is not already keyed by origin.
if ( empty( array_intersect( array_keys( $spacing_scale ), static::VALID_ORIGINS ) ) ) {
_wp_array_set( $this->theme_json, $scale_path, array( $origin => $spacing_scale ) );
}
}

/*
* Prior to version 3, spacingSizes were generated in WP_Theme_JSON_Resolver_Gutenberg::get_merged_data().
*
* It's important to use the original $theme_json here because WP_Theme_JSON_Schema_Gutenberg::migrate()
* has already updated the version to latest for $this->theme_json.
*/
if ( $theme_json['version'] >= 3 ) {
$sizes_path = array( 'settings', 'spacing', 'spacingSizes', $origin );
$scale_path = array( 'settings', 'spacing', 'spacingScale', $origin );
$spacing_sizes = _wp_array_get( $this->theme_json, $sizes_path, array() );
$spacing_scale = _wp_array_get( $this->theme_json, $scale_path, array() );
$spacing_scale_sizes = static::compute_spacing_sizes( $spacing_scale );
$merged_spacing_sizes = static::merge_spacing_sizes( $spacing_scale_sizes, $spacing_sizes );
_wp_array_set( $this->theme_json, $sizes_path, $merged_spacing_sizes );
}
}

/**
Expand Down Expand Up @@ -2960,6 +3028,38 @@ public function merge( $incoming ) {
$incoming_data = $incoming->get_raw_data();
$this->theme_json = array_replace_recursive( $this->theme_json, $incoming_data );

// Prior to version 3, spacingSizes were generated in WP_Theme_JSON_Resolver_Gutenberg::get_merged_data().
if ( $incoming_data['version'] >= 3 ) {
/*
* Recompute all the spacing sizes based on the new hierarchy of data. In the constructor
* spacingScale and spacingSizes are both keyed by origin and VALID_ORIGINS is ordered, so
* we can allow partial spacingScale data to inherit missing data from earlier layers when
* computing the spacing sizes.
*
* This happens before the presets are merged to ensure that default spacing sizes can be
* removed from the theme origin if $prevent_override is true.
*/
$flattened_spacing_scale = array();
foreach ( static::VALID_ORIGINS as $origin ) {
$scale_path = array( 'settings', 'spacing', 'spacingScale', $origin );
$spacing_scale = _wp_array_get( $incoming_data, $scale_path, null );
if ( ! isset( $spacing_scale ) ) {
continue;
}

// Allow partial scale settings by merging with lower layers.
$flattened_spacing_scale = array_replace( $flattened_spacing_scale, $spacing_scale );

// Generate and merge the scales for this layer.
$sizes_path = array( 'settings', 'spacing', 'spacingSizes', $origin );
$spacing_sizes = _wp_array_get( $incoming_data, $sizes_path, array() );
$spacing_scale_sizes = static::compute_spacing_sizes( $flattened_spacing_scale );
$merged_spacing_sizes = static::merge_spacing_sizes( $spacing_scale_sizes, $spacing_sizes );

_wp_array_set( $this->theme_json, $sizes_path, $merged_spacing_sizes );
}
}

/*
* The array_replace_recursive algorithm merges at the leaf level,
* but we don't want leaf arrays to be merged, so we overwrite it.
Expand Down Expand Up @@ -3739,15 +3839,21 @@ public function get_data() {
/**
* Sets the spacingSizes array based on the spacingScale values from theme.json.
*
* No longer used since theme.json version 3 as the spacingSizes are now
* automatically generated during construction and merge instead of manually
* set in the resolver.
*
* @since 6.1.0
* @since 6.6.0 Added the `$origin` parameter.
* @since 6.6.0 Added the $origin parameter.
*
* @param string $origin Optional. What source of data to set the spacing sizes for.
* One of 'default', 'theme', or 'custom'. Default 'default'.
* @return null|void
*/
public function set_spacing_sizes( $origin = 'default' ) {
$spacing_scale = $this->theme_json['settings']['spacing']['spacingScale'] ?? array();
$default_spacing_scale = $this->theme_json['settings']['spacing']['spacingScale']['default'] ?? array();
$origin_spacing_scale = $this->theme_json['settings']['spacing']['spacingScale'][ $origin ] ?? array();
$spacing_scale = array_replace( $default_spacing_scale, $origin_spacing_scale );

// Gutenberg didn't have the 1st isset check.
if ( ! isset( $spacing_scale['steps'] )
Expand All @@ -3771,6 +3877,97 @@ public function set_spacing_sizes( $origin = 'default' ) {
return null;
}

$spacing_sizes = static::compute_spacing_sizes( $spacing_scale );

// If there are 7 or less steps in the scale revert to numbers for labels instead of t-shirt sizes.
if ( $spacing_scale['steps'] <= 7 ) {
for ( $spacing_sizes_count = 0; $spacing_sizes_count < count( $spacing_sizes ); $spacing_sizes_count++ ) {
$spacing_sizes[ $spacing_sizes_count ]['name'] = (string) ( $spacing_sizes_count + 1 );
}
}

_wp_array_set( $this->theme_json, array( 'settings', 'spacing', 'spacingSizes', $origin ), $spacing_sizes );
}

/**
* Merges two sets of spacing size presets and sorts them by slug using the natsort algorithm
* so slugs beginning with 5 end up before slugs starting with 10, for example.
*
* @since 6.6.0
*
* @param array $base The base set of spacing sizes.
* @param array $incoming The set of spacing sizes to merge with the base. Duplicate slugs will override the base values.
* @return array The merged set of spacing sizes.
*/
private static function merge_spacing_sizes( $base, $incoming ) {
$merged = array();
foreach ( $base as $item ) {
$merged[ $item['slug'] ] = $item;
}
foreach ( $incoming as $item ) {
$merged[ $item['slug'] ] = $item;
}
ksort( $merged, SORT_NATURAL );
return array_values( $merged );
}

/**
* Generates a set of spacing sizes by starting with a medium size and
* applying an operator with an increment value to generate the rest of the
* sizes outward from the medium size. The medium slug is '50' with the rest
* of the slugs being 10 apart. The generated names use t-shirt sizing.
*
* Example:
*
* $spacing_scale = array(
* 'steps' => 4,
* 'mediumStep' => 16,
* 'unit' => 'px',
* 'operator' => '+',
* 'increment' => 2,
* );
* $spacing_sizes = static::compute_spacing_sizes( $spacing_scale );
* // -> array(
* // array( 'name' => 'Small', 'slug' => '40', 'size' => '14px' ),
* // array( 'name' => 'Medium', 'slug' => '50', 'size' => '16px' ),
* // array( 'name' => 'Large', 'slug' => '60', 'size' => '18px' ),
* // array( 'name' => 'X-Large', 'slug' => '70', 'size' => '20px' ),
* // )
*
* @since 6.6.0
*
* @param array $spacing_scale {
* The spacing scale values. All are required.
*
* @type int $steps The number of steps in the scale. (up to 9 steps are supported.)
* @type float $mediumStep The middle value that gets the slug '50'. (For even number of steps, this becomes the first middle value.)
* @type string $unit The CSS unit to use for the sizes.
* @type string $operator The mathematical operator to apply to generate the other sizes. Either '+' or '*'.
* @type float $increment The value used with the operator to generate the other sizes.
* }
* @return array The spacing sizes presets or an empty array if some spacing scale values are missing or invalid.
*/
private static function compute_spacing_sizes( $spacing_scale ) {
if (
! isset( $spacing_scale['steps'] ) ||
! is_numeric( $spacing_scale['steps'] ) ||
! is_int( $spacing_scale['steps'] + 0 ) ||
$spacing_scale['steps'] <= 0 ||
$spacing_scale['steps'] > 9 ||
! isset( $spacing_scale['mediumStep'] ) ||
! is_numeric( $spacing_scale['mediumStep'] ) ||
$spacing_scale['mediumStep'] <= 0 ||
! isset( $spacing_scale['unit'] ) ||
! in_array( $spacing_scale['unit'], static::VALID_SPACING_UNITS, true ) ||
! isset( $spacing_scale['operator'] ) ||
! in_array( $spacing_scale['operator'], static::VALID_SPACING_OPERATORS, true ) ||
! isset( $spacing_scale['increment'] ) ||
! is_numeric( $spacing_scale['increment'] ) ||
$spacing_scale['increment'] <= 0
) {
return array();
}

$unit = '%' === $spacing_scale['unit'] ? '%' : sanitize_title( $spacing_scale['unit'] );
$current_step = $spacing_scale['mediumStep'];
$steps_mid_point = round( $spacing_scale['steps'] / 2, 0 );
Expand Down Expand Up @@ -3853,14 +4050,7 @@ public function set_spacing_sizes( $origin = 'default' ) {
$spacing_sizes[] = $above_sizes_item;
}

// If there are 7 or less steps in the scale revert to numbers for labels instead of t-shirt sizes.
if ( $spacing_scale['steps'] <= 7 ) {
for ( $spacing_sizes_count = 0; $spacing_sizes_count < count( $spacing_sizes ); $spacing_sizes_count++ ) {
$spacing_sizes[ $spacing_sizes_count ]['name'] = (string) ( $spacing_sizes_count + 1 );
}
}

_wp_array_set( $this->theme_json, array( 'settings', 'spacing', 'spacingSizes', $origin ), $spacing_sizes );
return $spacing_sizes;
}

/**
Expand Down
7 changes: 6 additions & 1 deletion lib/class-wp-theme-json-resolver-gutenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -608,8 +608,13 @@ public static function get_merged_data( $origin = 'custom' ) {
return $result;
}

$result->merge( static::get_theme_data() );
$theme_data = static::get_theme_data();
$result->merge( $theme_data );
if ( 'theme' === $origin ) {
// Since theme.json version 3, spacingSizes are generated in (WP_Theme_JSON_Gutenberg) $theme_json->merge().
if ( $theme_data->get_raw_data()['version'] < 3 ) {
$result->set_spacing_sizes( $origin );
}
return $result;
}

Expand Down