Skip to content

Commit

Permalink
Do not remove theme presets if defaults are hidden (#37008)
Browse files Browse the repository at this point in the history
  • Loading branch information
oandregal authored Dec 9, 2021
1 parent 52012ee commit fa37c89
Show file tree
Hide file tree
Showing 2 changed files with 222 additions and 30 deletions.
88 changes: 61 additions & 27 deletions lib/compat/wordpress-5.9/class-wp-theme-json-gutenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class WP_Theme_JSON_Gutenberg {
const PRESETS_METADATA = array(
array(
'path' => array( 'color', 'palette' ),
'override' => false,
'override' => array( 'color', 'defaultPalette' ),
'value_key' => 'color',
'css_vars' => '--wp--preset--color--$slug',
'classes' => array(
Expand All @@ -108,7 +108,7 @@ class WP_Theme_JSON_Gutenberg {
),
array(
'path' => array( 'color', 'gradients' ),
'override' => false,
'override' => array( 'color', 'defaultGradients' ),
'value_key' => 'gradient',
'css_vars' => '--wp--preset--gradient--$slug',
'classes' => array( '.has-$slug-gradient-background' => 'background' ),
Expand Down Expand Up @@ -1412,9 +1412,9 @@ public function merge( $incoming ) {
* we remove it from the theme presets.
*/
$nodes = self::get_setting_nodes( $incoming_data );
$slugs_global = self::get_slugs_not_to_override( $this->theme_json );
$slugs_global = self::get_default_slugs( $this->theme_json, array( 'settings' ) );
foreach ( $nodes as $node ) {
$slugs_node = self::get_slugs_not_to_override( $this->theme_json, $node['path'] );
$slugs_node = self::get_default_slugs( $this->theme_json, $node['path'] );
$slugs = array_merge_recursive( $slugs_global, $slugs_node );

// Replace the spacing.units.
Expand All @@ -1426,6 +1426,8 @@ public function merge( $incoming ) {

// Replace the presets.
foreach ( self::PRESETS_METADATA as $preset ) {
$override_preset = self::should_override_preset( $this->theme_json, $node['path'], $preset['override'] );

foreach ( self::VALID_ORIGINS as $origin ) {
$path = array_merge( $node['path'], $preset['path'], array( $origin ) );
$content = _wp_array_get( $incoming_data, $path, null );
Expand All @@ -1435,13 +1437,12 @@ public function merge( $incoming ) {

if (
( 'theme' !== $origin ) ||
( 'theme' === $origin && $preset['override'] )
( 'theme' === $origin && $override_preset )
) {
_wp_array_set( $this->theme_json, $path, $content );
}

if ( 'theme' === $origin && ! $preset['override'] ) {
$content = self::filter_slugs( $content, $preset['path'], $slugs );
} else {
$slugs_for_preset = _wp_array_get( $slugs, $preset['path'], array() );
$content = self::filter_slugs( $content, $slugs_for_preset );
_wp_array_set( $this->theme_json, $path, $content );
}
}
Expand All @@ -1450,38 +1451,73 @@ public function merge( $incoming ) {
}

/**
* Returns the slugs for all the presets that cannot be overriden
* in the given path. It returns an associative array
* Returns whether a presets should be overriden or not.
*
* @param array $theme_json The theme.json like structure to inspect.
* @param array $path Path to inspect.
* @param bool|array $override Data to compute whether to override the preset.
* @return boolean
*/
private static function should_override_preset( $theme_json, $path, $override ) {
if ( is_bool( $override ) ) {
return $override;
}

// The relationship between whether to override the defaults
// and whether the defaults are enabled is inverse:
//
// - If defaults are enabled => theme presets should not be overriden
// - If defaults are disabled => theme presets should be overriden
//
// For example, a theme sets defaultPalette to false,
// making the default palette hidden from the user.
// In that case, we want all the theme presets to be present,
// so they should override the defaults.
if ( is_array( $override ) ) {
$value = _wp_array_get( $theme_json, array_merge( $path, $override ) );
if ( isset( $value ) ) {
return ! $value;
}

// Search the top-level key if none was found for this node.
$value = _wp_array_get( $theme_json, array_merge( array( 'settings' ), $override ) );
if ( isset( $value ) ) {
return ! $value;
}

return true;
}
}

/**
* Returns the default slugs for all the presets in an associative array
* whose keys are the preset paths and the leafs is the list of slugs.
*
* For example:
*
* array(
* array(
* 'color' => array(
* 'palette' => array( 'slug-1', 'slug-2' ),
* 'gradients' => array( 'slug-3', 'slug-4' ),
* ),
* )
*
* @param array $data A theme.json like structure to inspect.
* @param array $data A theme.json like structure.
* @param array $node_path The path to inspect. It's 'settings' by default.
*
* @return array An associative array containing the slugs for the given path.
* @return array
*/
private static function get_slugs_not_to_override( $data, $node_path = array( 'settings' ) ) {
private static function get_default_slugs( $data, $node_path ) {
$slugs = array();
foreach ( self::PRESETS_METADATA as $metadata ) {
if ( $metadata['override'] ) {
continue;
}

$slugs_for_preset = array();
$path = array_merge( $node_path, $metadata['path'], array( 'default' ) );
$preset = _wp_array_get( $data, $path, null );
foreach ( self::PRESETS_METADATA as $metadata ) {
$path = array_merge( $node_path, $metadata['path'], array( 'default' ) );
$preset = _wp_array_get( $data, $path, null );
if ( ! isset( $preset ) ) {
continue;
}

$slugs_for_preset = array();
$slugs_for_preset = array_map(
function( $value ) {
return isset( $value['slug'] ) ? $value['slug'] : null;
Expand All @@ -1498,20 +1534,18 @@ function( $value ) {
* Removes the preset values whose slug is equal to any of given slugs.
*
* @param array $node The node with the presets to validate.
* @param array $path The path to the preset type to inspect.
* @param array $slugs The slugs that should not be overriden.
*
* @return array The new node
*/
private static function filter_slugs( $node, $path, $slugs ) {
$slugs_for_preset = _wp_array_get( $slugs, $path, array() );
if ( empty( $slugs_for_preset ) ) {
private static function filter_slugs( $node, $slugs ) {
if ( empty( $slugs ) ) {
return $node;
}

$new_node = array();
foreach ( $node as $value ) {
if ( isset( $value['slug'] ) && ! in_array( $value['slug'], $slugs_for_preset, true ) ) {
if ( isset( $value['slug'] ) && ! in_array( $value['slug'], $slugs, true ) ) {
$new_node[] = $value;
}
}
Expand Down
164 changes: 161 additions & 3 deletions phpunit/class-wp-theme-json-test.php
Original file line number Diff line number Diff line change
Expand Up @@ -1081,13 +1081,14 @@ public function test_merge_incoming_data_null_presets() {
$this->assertEqualSetsWithIndex( $expected, $actual );
}

public function test_merge_incoming_data_removes_theme_presets_with_slugs_as_default_presets() {
public function test_merge_incoming_data_color_presets_with_same_slugs_as_default_are_removed() {
$defaults = new WP_Theme_JSON_Gutenberg(
array(
'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA,
'settings' => array(
'color' => array(
'palette' => array(
'defaultPalette' => true,
'palette' => array(
array(
'slug' => 'red',
'color' => 'red',
Expand Down Expand Up @@ -1166,7 +1167,7 @@ public function test_merge_incoming_data_removes_theme_presets_with_slugs_as_def
'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA,
'settings' => array(
'color' => array(
'palette' => array(
'palette' => array(
'default' => array(
array(
'slug' => 'red',
Expand All @@ -1187,6 +1188,7 @@ public function test_merge_incoming_data_removes_theme_presets_with_slugs_as_def
),
),
),
'defaultPalette' => true,
),
'blocks' => array(
'core/paragraph' => array(
Expand Down Expand Up @@ -1219,6 +1221,162 @@ public function test_merge_incoming_data_removes_theme_presets_with_slugs_as_def
$this->assertEqualSetsWithIndex( $expected, $actual );
}

public function test_merge_incoming_data_color_presets_with_same_slugs_as_default_are_not_removed_if_defaults_are_disabled() {
$defaults = new WP_Theme_JSON_Gutenberg(
array(
'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA,
'settings' => array(
'color' => array(
'defaultPalette' => true, // Emulate the defaults from core theme.json.
'palette' => array(
array(
'slug' => 'red',
'color' => 'red',
'name' => 'Red',
),
array(
'slug' => 'green',
'color' => 'green',
'name' => 'Green',
),
),
),
'blocks' => array(
'core/paragraph' => array(
'color' => array(
'palette' => array(
array(
'slug' => 'blue',
'color' => 'blue',
'name' => 'Blue',
),
),
),
),
),
),
),
'default'
);
$theme = new WP_Theme_JSON_Gutenberg(
array(
'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA,
'settings' => array(
'color' => array(
'defaultPalette' => false,
'palette' => array(
array(
'slug' => 'pink',
'color' => 'pink',
'name' => 'Pink',
),
array(
'slug' => 'green',
'color' => 'green',
'name' => 'Greenish',
),
),
),
'blocks' => array(
'core/paragraph' => array(
'color' => array(
'palette' => array(
array(
'slug' => 'blue',
'color' => 'blue',
'name' => 'Bluish',
),
array(
'slug' => 'yellow',
'color' => 'yellow',
'name' => 'Yellow',
),
array(
'slug' => 'green',
'color' => 'green',
'name' => 'Block Green',
),
),
),
),
),
),
)
);

$expected = array(
'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA,
'settings' => array(
'color' => array(
'defaultPalette' => false,
'palette' => array(
'default' => array(
array(
'slug' => 'red',
'color' => 'red',
'name' => 'Red',
),
array(
'slug' => 'green',
'color' => 'green',
'name' => 'Green',
),
),
'theme' => array(
array(
'slug' => 'pink',
'color' => 'pink',
'name' => 'Pink',
),
array(
'slug' => 'green',
'color' => 'green',
'name' => 'Greenish',
),
),
),
),
'blocks' => array(
'core/paragraph' => array(
'color' => array(
'palette' => array(
'default' => array(
array(
'slug' => 'blue',
'color' => 'blue',
'name' => 'Blue',
),
),
'theme' => array(
array(
'slug' => 'blue',
'color' => 'blue',
'name' => 'Bluish',
),
array(
'slug' => 'yellow',
'color' => 'yellow',
'name' => 'Yellow',
),
array(
'slug' => 'green',
'color' => 'green',
'name' => 'Block Green',
),
),
),
),
),
),
),
);

$defaults->merge( $theme );
$actual = $defaults->get_raw_data();

$this->assertEqualSetsWithIndex( $expected, $actual );
}

function test_remove_insecure_properties_removes_unsafe_styles() {
$actual = WP_Theme_JSON_Gutenberg::remove_insecure_properties(
array(
Expand Down

0 comments on commit fa37c89

Please sign in to comment.