From b7f859d763e90079edafb9f62c230bb9e2a1c157 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Mon, 11 Jan 2021 18:00:53 +0100 Subject: [PATCH 01/65] Switch key hierarchy --- lib/experimental-default-theme.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/experimental-default-theme.json b/lib/experimental-default-theme.json index 1ad199567df11b..d4c363788d7eb3 100644 --- a/lib/experimental-default-theme.json +++ b/lib/experimental-default-theme.json @@ -1,6 +1,6 @@ { - "global": { - "settings": { + "settings": { + "global": { "color": { "palette": [ { From 7c4a4748d9acb502eb7b49eeee141ebd4bc880e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Mon, 11 Jan 2021 18:22:14 +0100 Subject: [PATCH 02/65] Update docs --- .../developers/themes/theme-json.md | 77 ++++++------------- 1 file changed, 24 insertions(+), 53 deletions(-) diff --git a/docs/designers-developers/developers/themes/theme-json.md b/docs/designers-developers/developers/themes/theme-json.md index dad83773b1e3cd..222040b2514859 100644 --- a/docs/designers-developers/developers/themes/theme-json.md +++ b/docs/designers-developers/developers/themes/theme-json.md @@ -34,44 +34,18 @@ By providing the block style properties in a structured way, the Block Editor ca ## Specification -The `experimental-theme.json` file is divided into sections known as "contexts", that represent a different CSS selector. For example, the `core/paragraph` context maps to `p` while `core/group` maps to `.wp-block-group`. In general, one block will map to a single context as in the cases mentioned. There are cases where one block can generate multiple contexts (different CSS selectors). For example, the heading block generates six different contexts (`core/heading/h1`, `core/heading/h2`, etc), one for each different selector (h1, h2, etc). +The `experimental-theme.json` file declares how a theme wants the editor configured (`settings`) as well as the style properties it sets (`styles`). ``` { - "global": { ... }, - "core/paragraph": { ... }, - "core/group": { ... }, - "core/heading/h1": { ... }, - "core/heading/h2": { ... }, - "core/heading/h3": { ... }, - "core/heading/h4": { ... }, - "core/heading/h5": { ... }, - "core/heading/h6": { ... } + "settings": { ... }, + "styles": { ... } } ``` -Every context has the same structure, divided in two sections: `settings` and `styles`. The `settings` are used to control the editor (enable/disable certain features, declare presets), taking over what was previously declared via `add_theme_support`. The `styles` will be used to create new style rules to be appended to a new stylesheet `global-styles-inline-css` enqueued in the front-end and post editor. +Each one of these sections is sub-divided into "contexts" that loosely map to a block. In general, one block will create one single context ―the paragraph block can be addressed via `core/paragraph`― but there are also cases where one block will create multiple contexts ―the heading block represents different HTML elements, h1 to h6, so it creates one context for each such `core/heading/h1`, `core/heading/h2`, etc. Every context has the same inner structure. -``` -{ - "some/context": { - "settings": { - "border": [ ... ], - "color": [ ... ], - "custom": [ ... ], - "spacing": [ ... ], - "typography": [ ... ] - }, - "styles": { - "border": { ... }, - "color": { ... }, - "typography": { ... } - } - } -} -``` - -This structure is the same for the three different origins that exist: core, themes, and users. Themes can override core's defaults by creating a file called `experimental-theme.json`. Users, via the site editor, will also be also to override theme's or core's preferences via an user interface that is being worked on. +This specification is the same for the three different origins that use this format: core, themes, and users. Themes can override core's defaults by creating a file called `experimental-theme.json`. Users, via the site editor, will also be also to override theme's or core's preferences via an user interface that is being worked on. ### Settings @@ -79,8 +53,8 @@ The settings section has the following structure and default values: ``` { - "some/context": { - "settings": { + "settings": { + "some/context": { "border": { "customRadius": false /* true to opt-in */ }, @@ -114,26 +88,25 @@ The settings section has the following structure and default values: } ``` -To retain backward compatibility, `add_theme_support` declarations are retrofit in the proper categories. If a theme uses `add_theme_support('disable-custom-colors')`, it'll be the same as set `global.settings.color.custom` to `false`. If the `experimental-theme.json` contains any settings, these will take precedence over the values declared via `add_theme_support`. +To retain backward compatibility, `add_theme_support` declarations are retrofit in the proper categories. If a theme uses `add_theme_support('disable-custom-colors')`, it'll be the same as set `settings.global.color.custom` to `false`. If the `experimental-theme.json` contains any settings, these will take precedence over the values declared via `add_theme_support`. Settings can also be controlled by context, providing a more fine-grained control over what exists via `add_theme_support`. As an example, let's say that a theme author wants to enable custom colors for the paragraph block exclusively. This is how it'd be done: ```json { - "global": { - "settings": { + "settings": { + "global": { "color": { "custom": false } - } - }, - "core/paragraph": { - "settings": { + }, + "core/paragraph": { "color": { "custom": true } } } +} ``` Note, however, that not all settings are relevant for all contexts and the blocks they represent. The settings section provides an opt-in/opt-out mechanism for themes, but it's the block's responsibility to add support for the features that are relevant to it. For example, if a block doesn't implement the `dropCap` feature, a theme can't enable it for such a block through `experimental-theme.json`. @@ -146,8 +119,8 @@ For example, for this input: ```json { - "global": { - "settings": { + "settings": { + "global": { "color": { "palette": [ { @@ -204,14 +177,14 @@ The goal is that presets can be defined using this format, although, right now, #### Free-form CSS Custom Properties -In addition to create CSS Custom Properties for the presets, the theme.json also allows for themes to create their own, so they don't have to be enqueued separately. Any values declared within the `settings.custom` section will be transformed to CSS Custom Properties following this naming schema: `--wp--custom--`. +In addition to create CSS Custom Properties for the presets, the theme.json also allows for themes to create their own, so they don't have to be enqueued separately. Any values declared within the `settings..custom` section will be transformed to CSS Custom Properties following this naming schema: `--wp--custom--`. For example, for this input: ```json { - "global": { - "settings": { + "settings": { + "global": { "custom": { "base-font": 16, "line-height": { @@ -244,8 +217,8 @@ Each block declares which style properties it exposes. This has been coined as " ```json { - "some/context": { - "styles": { + "styles": { + "some/context": { "border": { "radius": "value" }, @@ -281,18 +254,16 @@ For example, an input like this: ```json { - "core/heading/h1": { - "styles": { + "styles": { + "core/heading/h1": { "color": { "text": "var(--wp--preset--color--primary)" }, "typography": { "fontSize": "calc(1px * var(--wp--preset--font-size--huge))" } - } - }, - "core/heading/h4": { - "styles": { + }, + "core/heading/h4": { "color": { "text": "var(--wp--preset--color--secondary)" }, From 7e3e2dda06ec861867dbacdfc91d7c7ba8d3e8b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Mon, 11 Jan 2021 18:36:39 +0100 Subject: [PATCH 03/65] Update tests --- phpunit/class-wp-theme-json-test.php | 144 ++++++++++++++------------- 1 file changed, 74 insertions(+), 70 deletions(-) diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index 057f340cfca7cd..786d4d4f5ff009 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -11,15 +11,13 @@ class WP_Theme_JSON_Test extends WP_UnitTestCase { function test_contexts_not_valid_are_skipped() { $theme_json = new WP_Theme_JSON( array( - 'global' => array( - 'settings' => array( + 'settings' => array( + 'global' => array( 'color' => array( 'custom' => 'false', ), ), - ), - 'core/invalid' => array( - 'settings' => array( + 'core/invalid' => array( 'color' => array( 'custom' => 'false', ), @@ -30,8 +28,8 @@ function test_contexts_not_valid_are_skipped() { $result = $theme_json->get_raw_data(); $expected = array( - 'global' => array( - 'settings' => array( + 'settings' => array( + 'global' => array( 'color' => array( 'custom' => 'false', ), @@ -45,9 +43,9 @@ function test_contexts_not_valid_are_skipped() { function test_properties_not_valid_are_skipped() { $theme_json = new WP_Theme_JSON( array( - 'global' => array( - 'invalidKey' => 'invalid value', - 'settings' => array( + 'invalidKey' => 'invalid value', + 'settings' => array( + 'global' => array( 'color' => array( 'custom' => 'false', 'invalidKey' => 'invalid value', @@ -56,7 +54,9 @@ function test_properties_not_valid_are_skipped() { 'invalidKey' => 'invalid value', ), ), - 'styles' => array( + ), + 'styles' => array( + 'global' => array( 'typography' => array( 'fontSize' => '12', 'invalidProperty' => 'invalid value', @@ -64,20 +64,22 @@ function test_properties_not_valid_are_skipped() { 'invalidSection' => array( 'invalidProperty' => 'invalid value', ), - ), + ) ), ) ); $result = $theme_json->get_raw_data(); $expected = array( - 'global' => array( - 'settings' => array( + 'settings' => array( + 'global' => array( 'color' => array( 'custom' => 'false', ), ), - 'styles' => array( + ), + 'styles' => array( + 'global' => array( 'typography' => array( 'fontSize' => '12', ), @@ -92,8 +94,8 @@ function test_get_settings() { // See schema at WP_Theme_JSON::SCHEMA. $theme_json = new WP_Theme_JSON( array( - 'global' => array( - 'settings' => array( + 'settings' => array( + 'global' => array( 'color' => array( 'link' => 'value', ), @@ -101,12 +103,14 @@ function test_get_settings() { 'typography' => 'value', 'misc' => 'value', ), - 'styles' => array( + ), + 'styles' => array( + 'global' => array( 'color' => 'value', 'misc' => 'value', - ), - 'misc' => 'value', + ) ), + 'misc' => 'value', ) ); @@ -124,8 +128,8 @@ function test_get_stylesheet() { // See schema at WP_Theme_JSON::SCHEMA. $theme_json = new WP_Theme_JSON( array( - 'global' => array( - 'settings' => array( + 'settings' => array( + 'global' => array( 'color' => array( 'text' => 'value', 'palette' => array( @@ -149,17 +153,16 @@ function test_get_stylesheet() { ), 'misc' => 'value', ), - 'styles' => array( + ), + 'styles' => array( + 'global' => array( 'color' => array( 'link' => '#111', 'text' => 'var:preset|color|grey', ), 'misc' => 'value', ), - 'misc' => 'value', - ), - 'core/group' => array( - 'styles' => array( + 'core/group' => array( 'spacing' => array( 'padding' => array( 'top' => '12px', @@ -168,6 +171,7 @@ function test_get_stylesheet() { ), ), ), + 'misc' => 'value', ) ); @@ -187,8 +191,8 @@ function test_get_stylesheet() { public function test_merge_incoming_data() { $initial = array( - 'global' => array( - 'settings' => array( + 'settings' => array( + 'global' => array( 'color' => array( 'custom' => 'false', 'palette' => array( @@ -203,29 +207,31 @@ public function test_merge_incoming_data() { ), ), ), - 'styles' => array( - 'typography' => array( - 'fontSize' => '12', - ), - ), - ), - 'core/paragraph' => array( - 'settings' => array( + 'core/paragraph' => array( 'color' => array( 'custom' => 'false', ), ), ), + 'styles' => array( + 'global' => array( + 'typography' => array( + 'fontSize' => '12', + ), + ) + ), ); $add_new_context = array( - 'core/list' => array( - 'settings' => array( + 'settings' => array( + 'core/list' => array( 'color' => array( 'custom' => 'false', ), ), - 'styles' => array( + ), + 'styles' => array( + 'core/list' => array( 'typography' => array( 'fontSize' => '12', ), @@ -238,8 +244,8 @@ public function test_merge_incoming_data() { ); $add_key_in_settings = array( - 'global' => array( - 'settings' => array( + 'settings' => array( + 'global' => array( 'color' => array( 'customGradient' => 'true', ), @@ -248,8 +254,8 @@ public function test_merge_incoming_data() { ); $update_key_in_settings = array( - 'global' => array( - 'settings' => array( + 'settings' => array( + 'global' => array( 'color' => array( 'custom' => 'true', ), @@ -258,8 +264,8 @@ public function test_merge_incoming_data() { ); $add_styles = array( - 'core/paragraph' => array( - 'styles' => array( + 'styles' => array( + 'core/paragraph' => array( 'typography' => array( 'fontSize' => '12', ), @@ -271,8 +277,8 @@ public function test_merge_incoming_data() { ); $add_key_in_styles = array( - 'core/paragraph' => array( - 'styles' => array( + 'styles' => array( + 'core/paragraph' => array( 'typography' => array( 'lineHeight' => '12', ), @@ -281,8 +287,8 @@ public function test_merge_incoming_data() { ); $add_invalid_context = array( - 'core/para' => array( - 'styles' => array( + 'styles' => array( + 'core/para' => array( 'typography' => array( 'lineHeight' => '12', ), @@ -291,8 +297,8 @@ public function test_merge_incoming_data() { ); $update_presets = array( - 'global' => array( - 'settings' => array( + 'settings' => array( + 'global' => array( 'color' => array( 'palette' => array( array( @@ -326,8 +332,8 @@ public function test_merge_incoming_data() { ); $expected = array( - 'global' => array( - 'settings' => array( + 'settings' => array( + 'global' => array( 'color' => array( 'custom' => 'true', 'customGradient' => 'true', @@ -359,19 +365,24 @@ public function test_merge_incoming_data() { ), ), ), - 'styles' => array( - 'typography' => array( - 'fontSize' => '12', + 'core/paragraph' => array( + 'color' => array( + 'custom' => 'false', ), ), - ), - 'core/paragraph' => array( - 'settings' => array( + 'core/list' => array( 'color' => array( 'custom' => 'false', ), ), - 'styles' => array( + ), + 'styles' => array( + 'global' => array( + 'typography' => array( + 'fontSize' => '12', + ), + ), + 'core/paragraph' => array( 'typography' => array( 'fontSize' => '12', 'lineHeight' => '12', @@ -380,14 +391,7 @@ public function test_merge_incoming_data() { 'link' => 'pink', ), ), - ), - 'core/list' => array( - 'settings' => array( - 'color' => array( - 'custom' => 'false', - ), - ), - 'styles' => array( + 'core/list' => array( 'typography' => array( 'fontSize' => '12', ), @@ -395,7 +399,7 @@ public function test_merge_incoming_data() { 'link' => 'pink', 'background' => 'brown', ), - ), + ) ), ); From 2db32c6e68ca532c67f0c5818091d8dfddbe34eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Thu, 14 Jan 2021 12:36:45 +0100 Subject: [PATCH 04/65] Filters out invalide top-level keys & block selectors --- lib/class-wp-theme-json.php | 87 ++-- phpunit/class-wp-theme-json-test.php | 646 ++++++++++++--------------- 2 files changed, 323 insertions(+), 410 deletions(-) diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index a4ecd2760e6c08..4c35524c3a6435 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -16,7 +16,7 @@ class WP_Theme_JSON { * * @var array */ - private $contexts = null; + private $theme_json = null; /** * Holds block metadata extracted from block.json @@ -292,56 +292,35 @@ class WP_Theme_JSON { /** * Constructor. * - * @param array $contexts A structure that follows the theme.json schema. + * @param array $theme_json A structure that follows the theme.json schema. */ - public function __construct( $contexts = array() ) { - $this->contexts = array(); + public function __construct( $theme_json = array() ) { + $this->theme_json = array(); - if ( ! is_array( $contexts ) ) { + if ( ! is_array( $theme_json ) ) { return; } - $metadata = $this->get_blocks_metadata(); - foreach ( $contexts as $key => $context ) { - if ( ! isset( $metadata[ $key ] ) ) { - // Skip incoming contexts that can't be found - // within the contexts registered. - continue; - } + // Filter out top-level keys that aren't valid according to the schema. + $this->theme_json = array_intersect_key( $theme_json, self::SCHEMA ); - // Filter out top-level keys that aren't valid according to the schema. - $context = array_intersect_key( $context, self::SCHEMA ); - - // Process styles subtree. - $this->process_key( 'styles', $context, self::SCHEMA ); - if ( isset( $context['styles'] ) ) { - $this->process_key( 'border', $context['styles'], self::SCHEMA['styles'] ); - $this->process_key( 'color', $context['styles'], self::SCHEMA['styles'] ); - $this->process_key( 'spacing', $context['styles'], self::SCHEMA['styles'] ); - $this->process_key( 'typography', $context['styles'], self::SCHEMA['styles'] ); - - if ( empty( $context['styles'] ) ) { - unset( $context['styles'] ); - } else { - $this->contexts[ $key ]['styles'] = $context['styles']; - } + // Filter out all block selectors that aren't registered for styles & settings. + $block_metadata = $this->get_blocks_metadata(); + + if ( isset( $this->theme_json['styles'] ) ) { + $this->theme_json['styles'] = array_intersect_key( $this->theme_json['styles'], $block_metadata ); + if ( empty( $this->theme_json['styles'] ) ) { + unset( $this->theme_json['styles'] ); } + } - // Process settings subtree. - $this->process_key( 'settings', $context, self::SCHEMA ); - if ( isset( $context['settings'] ) ) { - $this->process_key( 'border', $context['settings'], self::SCHEMA['settings'] ); - $this->process_key( 'color', $context['settings'], self::SCHEMA['settings'] ); - $this->process_key( 'spacing', $context['settings'], self::SCHEMA['settings'] ); - $this->process_key( 'typography', $context['settings'], self::SCHEMA['settings'] ); - - if ( empty( $context['settings'] ) ) { - unset( $context['settings'] ); - } else { - $this->contexts[ $key ]['settings'] = $context['settings']; - } + if ( isset( $this->theme_json['settings'] ) ) { + $this->theme_json['settings'] = array_intersect_key( $this->theme_json['settings'], $block_metadata ); + if ( empty( $this->theme_json['settings'] ) ) { + unset( $this->theme_json['settings'] ); } } + } /** @@ -879,7 +858,7 @@ function ( $carry, $element ) { private function get_css_variables() { $stylesheet = ''; $metadata = $this->get_blocks_metadata(); - foreach ( $this->contexts as $context_name => $context ) { + foreach ( $this->theme_json as $context_name => $context ) { if ( empty( $metadata[ $context_name ]['selector'] ) ) { continue; } @@ -935,7 +914,7 @@ private function get_css_variables() { private function get_block_styles() { $stylesheet = ''; $metadata = $this->get_blocks_metadata(); - foreach ( $this->contexts as $context_name => $context ) { + foreach ( $this->theme_json as $context_name => $context ) { if ( empty( $metadata[ $context_name ]['selector'] ) || empty( $metadata[ $context_name ]['supports'] ) ) { continue; } @@ -976,7 +955,7 @@ private function get_block_styles() { */ public function get_settings() { return array_filter( - array_map( array( $this, 'extract_settings' ), $this->contexts ), + array_map( array( $this, 'extract_settings' ), $this->theme_json ), function ( $element ) { return null !== $element; } @@ -1015,8 +994,8 @@ public function merge( $theme_json ) { continue; } - if ( ! isset( $this->contexts[ $context ][ $subtree ] ) ) { - $this->contexts[ $context ][ $subtree ] = $incoming_data[ $context ][ $subtree ]; + if ( ! isset( $this->theme_json[ $context ][ $subtree ] ) ) { + $this->theme_json[ $context ][ $subtree ] = $incoming_data[ $context ][ $subtree ]; continue; } @@ -1025,13 +1004,13 @@ public function merge( $theme_json ) { continue; } - if ( ! isset( $this->contexts[ $context ][ $subtree ][ $leaf ] ) ) { - $this->contexts[ $context ][ $subtree ][ $leaf ] = $incoming_data[ $context ][ $subtree ][ $leaf ]; + if ( ! isset( $this->theme_json[ $context ][ $subtree ][ $leaf ] ) ) { + $this->theme_json[ $context ][ $subtree ][ $leaf ] = $incoming_data[ $context ][ $subtree ][ $leaf ]; continue; } - $this->contexts[ $context ][ $subtree ][ $leaf ] = array_merge( - $this->contexts[ $context ][ $subtree ][ $leaf ], + $this->theme_json[ $context ][ $subtree ][ $leaf ] = array_merge( + $this->theme_json[ $context ][ $subtree ][ $leaf ], $incoming_data[ $context ][ $subtree ][ $leaf ] ); } @@ -1044,10 +1023,10 @@ public function merge( $theme_json ) { */ public function remove_insecure_properties() { $blocks_metadata = self::get_blocks_metadata(); - foreach ( $this->contexts as $context_name => &$context ) { + foreach ( $this->theme_json as $context_name => &$context ) { // Escape the context key. if ( empty( $blocks_metadata[ $context_name ] ) ) { - unset( $this->contexts[ $context_name ] ); + unset( $this->theme_json[ $context_name ] ); continue; } @@ -1134,7 +1113,7 @@ public function remove_insecure_properties() { } if ( null === $escaped_settings && null === $escaped_styles ) { - unset( $this->contexts[ $context_name ] ); + unset( $this->theme_json[ $context_name ] ); } elseif ( null !== $escaped_settings && null !== $escaped_styles ) { $context = array( 'styles' => $escaped_styles, @@ -1158,7 +1137,7 @@ public function remove_insecure_properties() { * @return array Raw data. */ public function get_raw_data() { - return $this->contexts; + return $this->theme_json; } } diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index 786d4d4f5ff009..0c31dceca82fc5 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -8,14 +8,20 @@ class WP_Theme_JSON_Test extends WP_UnitTestCase { - function test_contexts_not_valid_are_skipped() { + function test_schema_validation() { $theme_json = new WP_Theme_JSON( array( - 'settings' => array( + 'invalid/key' => 'content', + 'styles' => array( 'global' => array( 'color' => array( - 'custom' => 'false', + 'custom' => false, + 'background' => 'red', ), + 'unsupported/property' => array( + 'custom' => false, + 'background' => 'red', + ) ), 'core/invalid' => array( 'color' => array( @@ -23,65 +29,22 @@ function test_contexts_not_valid_are_skipped() { ), ), ), - ) - ); - $result = $theme_json->get_raw_data(); - - $expected = array( - 'settings' => array( - 'global' => array( - 'color' => array( - 'custom' => 'false', - ), - ), - ), - ); - - $this->assertEqualSetsWithIndex( $expected, $result ); - } - - function test_properties_not_valid_are_skipped() { - $theme_json = new WP_Theme_JSON( - array( - 'invalidKey' => 'invalid value', - 'settings' => array( - 'global' => array( - 'color' => array( - 'custom' => 'false', - 'invalidKey' => 'invalid value', - ), - 'invalidSection' => array( - 'invalidKey' => 'invalid value', + 'settings' => array( + 'core/invalid' => array( + 'color' => array( + 'custom' => false, ), ), ), - 'styles' => array( - 'global' => array( - 'typography' => array( - 'fontSize' => '12', - 'invalidProperty' => 'invalid value', - ), - 'invalidSection' => array( - 'invalidProperty' => 'invalid value', - ), - ) - ), ) ); $result = $theme_json->get_raw_data(); $expected = array( - 'settings' => array( + 'styles' => array( 'global' => array( 'color' => array( - 'custom' => 'false', - ), - ), - ), - 'styles' => array( - 'global' => array( - 'typography' => array( - 'fontSize' => '12', + 'background' => 'red', ), ), ), @@ -90,332 +53,303 @@ function test_properties_not_valid_are_skipped() { $this->assertEqualSetsWithIndex( $expected, $result ); } - function test_get_settings() { - // See schema at WP_Theme_JSON::SCHEMA. + function test_schema_validation_works_with_partial_data() { $theme_json = new WP_Theme_JSON( array( - 'settings' => array( - 'global' => array( - 'color' => array( - 'link' => 'value', - ), - 'custom' => 'value', - 'typography' => 'value', - 'misc' => 'value', - ), - ), - 'styles' => array( - 'global' => array( - 'color' => 'value', - 'misc' => 'value', - ) - ), - 'misc' => 'value', - ) - ); - - $result = $theme_json->get_settings(); - - $this->assertArrayHasKey( 'global', $result ); - $this->assertCount( 1, $result ); - - $this->assertArrayHasKey( 'color', $result['global'] ); - $this->assertArrayHasKey( 'custom', $result['global'] ); - $this->assertCount( 2, $result['global'] ); - } - - function test_get_stylesheet() { - // See schema at WP_Theme_JSON::SCHEMA. - $theme_json = new WP_Theme_JSON( - array( - 'settings' => array( - 'global' => array( - 'color' => array( - 'text' => 'value', - 'palette' => array( - array( - 'slug' => 'grey', - 'color' => 'grey', - ), - ), - ), - 'typography' => array( - 'fontFamilies' => array( - array( - 'slug' => 'small', - 'fontFamily' => '14px', - ), - array( - 'slug' => 'big', - 'fontFamily' => '41px', - ), - ), - ), - 'misc' => 'value', - ), - ), - 'styles' => array( + 'invalid/key' => 'content', + 'styles' => array( 'global' => array( 'color' => array( - 'link' => '#111', - 'text' => 'var:preset|color|grey', + 'custom' => false, + 'background' => 'red', ), - 'misc' => 'value', + 'unsupported/property' => array( + 'custom' => false, + 'background' => 'red', + ) ), - 'core/group' => array( - 'spacing' => array( - 'padding' => array( - 'top' => '12px', - 'bottom' => '24px', - ), - ), - ), - ), - 'misc' => 'value', - ) - ); - - $this->assertEquals( - ':root{--wp--preset--color--grey: grey;--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}:root{--wp--style--color--link: #111;color: var(--wp--preset--color--grey);}.has-grey-color{color: grey;}.has-grey-background-color{background-color: grey;}.wp-block-group{padding-top: 12px;padding-bottom: 24px;}', - $theme_json->get_stylesheet() - ); - $this->assertEquals( - ':root{--wp--style--color--link: #111;color: var(--wp--preset--color--grey);}.has-grey-color{color: grey;}.has-grey-background-color{background-color: grey;}.wp-block-group{padding-top: 12px;padding-bottom: 24px;}', - $theme_json->get_stylesheet( 'block_styles' ) - ); - $this->assertEquals( - ':root{--wp--preset--color--grey: grey;--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}', - $theme_json->get_stylesheet( 'css_variables' ) - ); - } - - public function test_merge_incoming_data() { - $initial = array( - 'settings' => array( - 'global' => array( - 'color' => array( - 'custom' => 'false', - 'palette' => array( - array( - 'slug' => 'red', - 'color' => 'red', - ), - array( - 'slug' => 'blue', - 'color' => 'blue', - ), + 'core/invalid' => array( + 'color' => array( + 'custom' => 'false', ), ), - ), - 'core/paragraph' => array( - 'color' => array( - 'custom' => 'false', - ), - ), - ), - 'styles' => array( - 'global' => array( - 'typography' => array( - 'fontSize' => '12', - ), ) - ), - ); - - $add_new_context = array( - 'settings' => array( - 'core/list' => array( - 'color' => array( - 'custom' => 'false', - ), - ), - ), - 'styles' => array( - 'core/list' => array( - 'typography' => array( - 'fontSize' => '12', - ), - 'color' => array( - 'link' => 'pink', - 'background' => 'brown', - ), - ), - ), - ); - - $add_key_in_settings = array( - 'settings' => array( - 'global' => array( - 'color' => array( - 'customGradient' => 'true', - ), - ), - ), - ); - - $update_key_in_settings = array( - 'settings' => array( - 'global' => array( - 'color' => array( - 'custom' => 'true', - ), - ), - ), - ); - - $add_styles = array( - 'styles' => array( - 'core/paragraph' => array( - 'typography' => array( - 'fontSize' => '12', - ), - 'color' => array( - 'link' => 'pink', - ), - ), - ), - ); - - $add_key_in_styles = array( - 'styles' => array( - 'core/paragraph' => array( - 'typography' => array( - 'lineHeight' => '12', - ), - ), - ), - ); - - $add_invalid_context = array( - 'styles' => array( - 'core/para' => array( - 'typography' => array( - 'lineHeight' => '12', - ), - ), - ), - ); - - $update_presets = array( - 'settings' => array( - 'global' => array( - 'color' => array( - 'palette' => array( - array( - 'slug' => 'color', - 'color' => 'color', - ), - ), - 'gradients' => array( - array( - 'slug' => 'gradient', - 'gradient' => 'gradient', - ), - ), - ), - 'typography' => array( - 'fontSizes' => array( - array( - 'slug' => 'fontSize', - 'size' => 'fontSize', - ), - ), - 'fontFamilies' => array( - array( - 'slug' => 'fontFamily', - 'fontFamily' => 'fontFamily', - ), - ), - ), - ), - ), + ) ); + $result = $theme_json->get_raw_data(); $expected = array( - 'settings' => array( + 'styles' => array( 'global' => array( - 'color' => array( - 'custom' => 'true', - 'customGradient' => 'true', - 'palette' => array( - array( - 'slug' => 'color', - 'color' => 'color', - ), - ), - 'gradients' => array( - array( - 'slug' => 'gradient', - 'gradient' => 'gradient', - ), - ), - ), - 'typography' => array( - 'fontSizes' => array( - array( - 'slug' => 'fontSize', - 'size' => 'fontSize', - ), - ), - 'fontFamilies' => array( - array( - 'slug' => 'fontFamily', - 'fontFamily' => 'fontFamily', - ), - ), - ), - ), - 'core/paragraph' => array( 'color' => array( - 'custom' => 'false', - ), - ), - 'core/list' => array( - 'color' => array( - 'custom' => 'false', - ), - ), - ), - 'styles' => array( - 'global' => array( - 'typography' => array( - 'fontSize' => '12', + 'background' => 'red', ), ), - 'core/paragraph' => array( - 'typography' => array( - 'fontSize' => '12', - 'lineHeight' => '12', - ), - 'color' => array( - 'link' => 'pink', - ), - ), - 'core/list' => array( - 'typography' => array( - 'fontSize' => '12', - ), - 'color' => array( - 'link' => 'pink', - 'background' => 'brown', - ), - ) ), ); - $theme_json = new WP_Theme_JSON( $initial ); - $theme_json->merge( new WP_Theme_JSON( $add_new_context ) ); - $theme_json->merge( new WP_Theme_JSON( $add_key_in_settings ) ); - $theme_json->merge( new WP_Theme_JSON( $update_key_in_settings ) ); - $theme_json->merge( new WP_Theme_JSON( $add_styles ) ); - $theme_json->merge( new WP_Theme_JSON( $add_key_in_styles ) ); - $theme_json->merge( new WP_Theme_JSON( $add_invalid_context ) ); - $theme_json->merge( new WP_Theme_JSON( $update_presets ) ); - $result = $theme_json->get_raw_data(); - $this->assertEqualSetsWithIndex( $expected, $result ); } + // function test_properties_not_valid_are_skipped() { + // $theme_json = new WP_Theme_JSON( + // array( + // 'invalidKey' => 'invalid value', + // 'settings' => array( + // 'global' => array( + // 'color' => array( + // 'custom' => 'false', + // 'invalidKey' => 'invalid value', + // ), + // 'invalidSection' => array( + // 'invalidKey' => 'invalid value', + // ), + // ), + // ), + // 'styles' => array( + // 'global' => array( + // 'typography' => array( + // 'fontSize' => '12', + // 'invalidProperty' => 'invalid value', + // ), + // 'invalidSection' => array( + // 'invalidProperty' => 'invalid value', + // ), + // ) + // ), + // ) + // ); + // $result = $theme_json->get_raw_data(); + + // $expected = array( + // 'settings' => array( + // 'global' => array( + // 'color' => array( + // 'custom' => 'false', + // ), + // ), + // ), + // 'styles' => array( + // 'global' => array( + // 'typography' => array( + // 'fontSize' => '12', + // ), + // ), + // ), + // ); + + // $this->assertEqualSetsWithIndex( $expected, $result ); + // } + + // function test_get_settings() { + // // See schema at WP_Theme_JSON::SCHEMA. + // $theme_json = new WP_Theme_JSON( + // array( + // 'settings' => array( + // 'global' => array( + // 'color' => array( + // 'link' => 'value', + // ), + // 'custom' => 'value', + // 'typography' => 'value', + // 'misc' => 'value', + // ), + // ), + // 'styles' => array( + // 'global' => array( + // 'color' => 'value', + // 'misc' => 'value', + // ) + // ), + // 'misc' => 'value', + // ) + // ); + + // $result = $theme_json->get_settings(); + + // $this->assertArrayHasKey( 'global', $result ); + // $this->assertCount( 1, $result ); + + // $this->assertArrayHasKey( 'color', $result['global'] ); + // $this->assertArrayHasKey( 'custom', $result['global'] ); + // $this->assertCount( 2, $result['global'] ); + // } + + // function test_get_stylesheet() { + // // See schema at WP_Theme_JSON::SCHEMA. + // $theme_json = new WP_Theme_JSON( + // array( + // 'settings' => array( + // 'global' => array( + // 'color' => array( + // 'text' => 'value', + // 'palette' => array( + // array( + // 'slug' => 'grey', + // 'color' => 'grey', + // ), + // ), + // ), + // 'typography' => array( + // 'fontFamilies' => array( + // array( + // 'slug' => 'small', + // 'fontFamily' => '14px', + // ), + // array( + // 'slug' => 'big', + // 'fontFamily' => '41px', + // ), + // ), + // ), + // 'misc' => 'value', + // ), + // ), + // 'styles' => array( + // 'global' => array( + // 'color' => array( + // 'link' => '#111', + // 'text' => 'var:preset|color|grey', + // ), + // 'misc' => 'value', + // ), + // 'core/group' => array( + // 'spacing' => array( + // 'padding' => array( + // 'top' => '12px', + // 'bottom' => '24px', + // ), + // ), + // ), + // ), + // 'misc' => 'value', + // ) + // ); + + // $this->assertEquals( + // ':root{--wp--preset--color--grey: grey;--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}:root{--wp--style--color--link: #111;color: var(--wp--preset--color--grey);}.has-grey-color{color: grey;}.has-grey-background-color{background-color: grey;}.wp-block-group{padding-top: 12px;padding-bottom: 24px;}', + // $theme_json->get_stylesheet() + // ); + // $this->assertEquals( + // ':root{--wp--style--color--link: #111;color: var(--wp--preset--color--grey);}.has-grey-color{color: grey;}.has-grey-background-color{background-color: grey;}.wp-block-group{padding-top: 12px;padding-bottom: 24px;}', + // $theme_json->get_stylesheet( 'block_styles' ) + // ); + // $this->assertEquals( + // ':root{--wp--preset--color--grey: grey;--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}', + // $theme_json->get_stylesheet( 'css_variables' ) + // ); + // } + + // public function test_merge_incoming_data() { + // $initial = array( + // 'settings' => array( + // 'global' => array( + // 'color' => array( + // 'custom' => 'false', + // 'palette' => array( + // array( + // 'slug' => 'red', + // 'color' => 'red', + // ), + // array( + // 'slug' => 'blue', + // 'color' => 'blue', + // ), + // ), + // ), + // ), + // 'core/paragraph' => array( + // 'color' => array( + // 'custom' => 'false', + // ), + // ), + // ), + // 'styles' => array( + // 'global' => array( + // 'typography' => array( + // 'fontSize' => '12', + // ), + // ) + // ), + // ); + + // $add_new_context = array( + // 'settings' => array( + // 'core/list' => array( + // 'color' => array( + // 'custom' => 'false', + // ), + // ), + // ), + // 'styles' => array( + // 'core/list' => array( + // 'typography' => array( + // 'fontSize' => '12', + // ), + // 'color' => array( + // 'link' => 'pink', + // 'background' => 'brown', + // ), + // ), + // ), + // ); + + // $add_key_in_settings = array( + // 'settings' => array( + // 'global' => array( + // 'color' => array( + // 'customGradient' => 'true', + // ), + // ), + // ), + // ); + + // $update_key_in_settings = array( + // 'settings' => array( + // 'global' => array( + // 'color' => array( + // 'custom' => 'true', + // ), + // ), + // ), + // ); + + // $add_styles = array( + // 'styles' => array( + // 'core/paragraph' => array( + // 'typography' => array( + // 'fontSize' => '12', + // ), + // 'color' => array( + // 'link' => 'pink', + // ), + // ), + // ), + // ); + + // $add_key_in_styles = array( + // 'styles' => array( + // 'core/paragraph' => array( + // 'typography' => array( + // 'lineHeight' => '12', + // ), + // ), + // ), + // ); + + // $add_invalid_context = array( + // 'styles' => array( + // 'core/para' => array( + // 'typography' => array( + // 'lineHeight' => '12', + // ), + // ), + // ), + // ); + + // $this->assertEqualSetsWithIndex( $expected, $result ); + // } + function test_remove_insecure_properties_removes_invalid_contexts() { $theme_json = new WP_Theme_JSON( array( From f5241a6c10a32a35fbb9f4c22d18c2d6fcbf7143 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Thu, 14 Jan 2021 12:42:57 +0100 Subject: [PATCH 05/65] Filters out top-level keys within settings/styles subtrees --- lib/class-wp-theme-json.php | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index 4c35524c3a6435..b35ca329313b4f 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -321,6 +321,24 @@ public function __construct( $theme_json = array() ) { } } + // Filter out styles subtree according to the schema. + foreach( $block_metadata as $block_selector => $metadata ) { + if ( isset( $this->theme_json['styles'][ $block_selector] ) ) { + self::process_subtree( $this->theme_json['styles'][ $block_selector ], self::SCHEMA['styles'] ); + + if ( empty( $this->theme_json['styles'][ $block_selector ] ) ) { + unset( $this->theme_json['styles'][ $block_selector ] ); + } + } + + if ( isset( $this->theme_json['settings'][ $block_selector] ) ) { + self::process_subtree( $this->theme_json['settings'][ $block_selector ], self::SCHEMA['settings'] ); + + if ( empty( $this->theme_json['settings'][ $block_selector ] ) ) { + unset( $this->theme_json['settings'][ $block_selector ] ); + } + } + } } /** @@ -495,6 +513,10 @@ private static function get_blocks_metadata() { return self::$blocks_metadata; } + private static function process_subtree( &$subtree, $schema ) { + $subtree = array_intersect_key( $subtree, $schema ); + } + /** * Normalize the subtree according to the given schema. * This function modifies the given input by removing From 9eb5f5449e99249cde0d4bd7528a66aaca425df5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Thu, 14 Jan 2021 12:45:59 +0100 Subject: [PATCH 06/65] Recursively iterate over schema --- lib/class-wp-theme-json.php | 6 ++++++ phpunit/class-wp-theme-json-test.php | 12 +++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index b35ca329313b4f..2d4193085e638f 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -515,6 +515,12 @@ private static function get_blocks_metadata() { private static function process_subtree( &$subtree, $schema ) { $subtree = array_intersect_key( $subtree, $schema ); + + foreach( $schema as $key => $data ) { + if ( is_array( $schema[ $key ] ) && isset( $subtree[ $key ] ) ) { + self::process_subtree( $subtree[ $key ], $schema[ $key ] ); + } + } } /** diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index 0c31dceca82fc5..3b58fb849f6a2a 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -21,7 +21,12 @@ function test_schema_validation() { 'unsupported/property' => array( 'custom' => false, 'background' => 'red', - ) + ), + 'spacing' => array( + 'padding' => array( + 'top' => '10px', + ), + ), ), 'core/invalid' => array( 'color' => array( @@ -46,6 +51,11 @@ function test_schema_validation() { 'color' => array( 'background' => 'red', ), + 'spacing' => array( + 'padding' => array( + 'top' => '10px', + ), + ), ), ), ); From b1318e6b10e9160e6cc2c0ed057506bae293988a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Thu, 14 Jan 2021 12:56:10 +0100 Subject: [PATCH 07/65] Refactor to compact the code --- lib/class-wp-theme-json.php | 24 ++++-------- phpunit/class-wp-theme-json-test.php | 58 +++++++++++++++++++++++++--- 2 files changed, 61 insertions(+), 21 deletions(-) diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index 2d4193085e638f..475e0e1247ee74 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -306,14 +306,12 @@ public function __construct( $theme_json = array() ) { // Filter out all block selectors that aren't registered for styles & settings. $block_metadata = $this->get_blocks_metadata(); - if ( isset( $this->theme_json['styles'] ) ) { $this->theme_json['styles'] = array_intersect_key( $this->theme_json['styles'], $block_metadata ); if ( empty( $this->theme_json['styles'] ) ) { unset( $this->theme_json['styles'] ); } } - if ( isset( $this->theme_json['settings'] ) ) { $this->theme_json['settings'] = array_intersect_key( $this->theme_json['settings'], $block_metadata ); if ( empty( $this->theme_json['settings'] ) ) { @@ -321,21 +319,15 @@ public function __construct( $theme_json = array() ) { } } - // Filter out styles subtree according to the schema. - foreach( $block_metadata as $block_selector => $metadata ) { - if ( isset( $this->theme_json['styles'][ $block_selector] ) ) { - self::process_subtree( $this->theme_json['styles'][ $block_selector ], self::SCHEMA['styles'] ); + // Filter out the styles & settings subtrees for each block selector. + foreach( $block_metadata as $block_selector => $metadata ) { + foreach( [ 'styles', 'settings '] as $key => $subtree ) { + if ( isset( $this->theme_json[ $subtree ][ $block_selector] ) ) { + self::process_subtree( $this->theme_json[ $subtree ][ $block_selector ], self::SCHEMA[ $subtree ] ); - if ( empty( $this->theme_json['styles'][ $block_selector ] ) ) { - unset( $this->theme_json['styles'][ $block_selector ] ); - } - } - - if ( isset( $this->theme_json['settings'][ $block_selector] ) ) { - self::process_subtree( $this->theme_json['settings'][ $block_selector ], self::SCHEMA['settings'] ); - - if ( empty( $this->theme_json['settings'][ $block_selector ] ) ) { - unset( $this->theme_json['settings'][ $block_selector ] ); + if ( empty( $this->theme_json[ $subtree ][ $block_selector ] ) ) { + unset( $this->theme_json[ $subtree ][ $block_selector ] ); + } } } } diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index 3b58fb849f6a2a..904a08a8763052 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -15,10 +15,11 @@ function test_schema_validation() { 'styles' => array( 'global' => array( 'color' => array( - 'custom' => false, - 'background' => 'red', + 'custom' => false, + 'background' => 'red', + 'invalid/key' => true, ), - 'unsupported/property' => array( + 'invalid/key' => array( 'custom' => false, 'background' => 'red', ), @@ -28,18 +29,23 @@ function test_schema_validation() { ), ), ), - 'core/invalid' => array( + 'invalid/key' => array( 'color' => array( 'custom' => 'false', ), ), ), 'settings' => array( - 'core/invalid' => array( + 'invalid/key' => array( 'color' => array( 'custom' => false, ), ), + 'global' => array( + 'color' => array( + 'custom' => false, + ) + ) ), ) ); @@ -58,6 +64,13 @@ function test_schema_validation() { ), ), ), + 'settings' => array( + 'global' => array( + 'color' => array( + 'custom' => false, + ), + ), + ), ); $this->assertEqualSetsWithIndex( $expected, $result ); @@ -101,6 +114,41 @@ function test_schema_validation_works_with_partial_data() { $this->assertEqualSetsWithIndex( $expected, $result ); } + function test_schema_validation_subtree_is_removed_if_empty() { + $theme_json = new WP_Theme_JSON( + array( + 'invalid/key' => 'content', + 'styles' => array( + 'invalid/key' => array( + 'color' => array( + 'background' => 'red', + ), + ), + ), + 'settings' => array( + 'global' => array( + 'color' => array( + 'custom' => false, + ), + ), + ), + ) + ); + $result = $theme_json->get_raw_data(); + + $expected = array( + 'settings' => array( + 'global' => array( + 'color' => array( + 'custom' => false, + ), + ), + ), + ); + + $this->assertEqualSetsWithIndex( $expected, $result ); + } + // function test_properties_not_valid_are_skipped() { // $theme_json = new WP_Theme_JSON( // array( From b99380ca16490a74d553f61d3facca53176aa7d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Thu, 14 Jan 2021 13:00:10 +0100 Subject: [PATCH 08/65] Prepare code & test for get_settings --- lib/class-wp-theme-json.php | 22 +----- phpunit/class-wp-theme-json-test.php | 110 ++++++++------------------- 2 files changed, 31 insertions(+), 101 deletions(-) diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index 475e0e1247ee74..3d39e6b61a15e6 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -549,21 +549,6 @@ private static function process_key( $key, &$input, $schema ) { } } - /** - * Given a context, it returns its settings subtree. - * - * @param array $context Context adhering to the theme.json schema. - * - * @return array|null The settings subtree. - */ - private static function extract_settings( $context ) { - if ( empty( $context['settings'] ) ) { - return null; - } - - return $context['settings']; - } - /** * Given a tree, it creates a flattened one * by merging the keys and binding the leaf values @@ -974,12 +959,7 @@ private function get_block_styles() { * @return array Settings per context. */ public function get_settings() { - return array_filter( - array_map( array( $this, 'extract_settings' ), $this->theme_json ), - function ( $element ) { - return null !== $element; - } - ); + return $this->theme_json['settings']; } /** diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index 904a08a8763052..ec0e4ed49485da 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -149,89 +149,39 @@ function test_schema_validation_subtree_is_removed_if_empty() { $this->assertEqualSetsWithIndex( $expected, $result ); } - // function test_properties_not_valid_are_skipped() { - // $theme_json = new WP_Theme_JSON( - // array( - // 'invalidKey' => 'invalid value', - // 'settings' => array( - // 'global' => array( - // 'color' => array( - // 'custom' => 'false', - // 'invalidKey' => 'invalid value', - // ), - // 'invalidSection' => array( - // 'invalidKey' => 'invalid value', - // ), - // ), - // ), - // 'styles' => array( - // 'global' => array( - // 'typography' => array( - // 'fontSize' => '12', - // 'invalidProperty' => 'invalid value', - // ), - // 'invalidSection' => array( - // 'invalidProperty' => 'invalid value', - // ), - // ) - // ), - // ) - // ); - // $result = $theme_json->get_raw_data(); - - // $expected = array( - // 'settings' => array( - // 'global' => array( - // 'color' => array( - // 'custom' => 'false', - // ), - // ), - // ), - // 'styles' => array( - // 'global' => array( - // 'typography' => array( - // 'fontSize' => '12', - // ), - // ), - // ), - // ); - - // $this->assertEqualSetsWithIndex( $expected, $result ); - // } - - // function test_get_settings() { - // // See schema at WP_Theme_JSON::SCHEMA. - // $theme_json = new WP_Theme_JSON( - // array( - // 'settings' => array( - // 'global' => array( - // 'color' => array( - // 'link' => 'value', - // ), - // 'custom' => 'value', - // 'typography' => 'value', - // 'misc' => 'value', - // ), - // ), - // 'styles' => array( - // 'global' => array( - // 'color' => 'value', - // 'misc' => 'value', - // ) - // ), - // 'misc' => 'value', - // ) - // ); + function test_get_settings() { + // See schema at WP_Theme_JSON::SCHEMA. + $theme_json = new WP_Theme_JSON( + array( + 'settings' => array( + 'global' => array( + 'color' => array( + 'link' => 'value', + ), + 'custom' => 'value', + 'typography' => 'value', + 'misc' => 'value', + ), + ), + 'styles' => array( + 'global' => array( + 'color' => 'value', + 'misc' => 'value', + ) + ), + 'misc' => 'value', + ) + ); - // $result = $theme_json->get_settings(); + $result = $theme_json->get_settings(); - // $this->assertArrayHasKey( 'global', $result ); - // $this->assertCount( 1, $result ); + $this->assertArrayHasKey( 'global', $result ); + $this->assertCount( 1, $result ); - // $this->assertArrayHasKey( 'color', $result['global'] ); - // $this->assertArrayHasKey( 'custom', $result['global'] ); - // $this->assertCount( 2, $result['global'] ); - // } + $this->assertArrayHasKey( 'color', $result['global'] ); + $this->assertArrayHasKey( 'custom', $result['global'] ); + $this->assertCount( 2, $result['global'] ); + } // function test_get_stylesheet() { // // See schema at WP_Theme_JSON::SCHEMA. From bb8af54b4bcc5ca776a1559a4aab437a219a8029 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Thu, 14 Jan 2021 13:36:15 +0100 Subject: [PATCH 09/65] Improve test clarity --- phpunit/class-wp-theme-json-test.php | 78 ++++------------------------ 1 file changed, 10 insertions(+), 68 deletions(-) diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index ec0e4ed49485da..0320371146568a 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -8,44 +8,32 @@ class WP_Theme_JSON_Test extends WP_UnitTestCase { - function test_schema_validation() { + function test_schema_validation_invalid_keys_are_removed() { $theme_json = new WP_Theme_JSON( array( 'invalid/key' => 'content', 'styles' => array( - 'global' => array( + 'invalid/key' => array( 'color' => array( - 'custom' => false, - 'background' => 'red', - 'invalid/key' => true, + 'custom' => 'false', ), + ), + 'global' => array( 'invalid/key' => array( 'custom' => false, 'background' => 'red', ), + 'color' => array( + 'invalid/key' => true, + 'background' => 'red', + ), 'spacing' => array( 'padding' => array( + 'invalid/key' => false, 'top' => '10px', ), ), ), - 'invalid/key' => array( - 'color' => array( - 'custom' => 'false', - ), - ), - ), - 'settings' => array( - 'invalid/key' => array( - 'color' => array( - 'custom' => false, - ), - ), - 'global' => array( - 'color' => array( - 'custom' => false, - ) - ) ), ) ); @@ -63,53 +51,8 @@ function test_schema_validation() { ), ), ), - ), - 'settings' => array( - 'global' => array( - 'color' => array( - 'custom' => false, - ), - ), - ), - ); - - $this->assertEqualSetsWithIndex( $expected, $result ); - } - - function test_schema_validation_works_with_partial_data() { - $theme_json = new WP_Theme_JSON( - array( - 'invalid/key' => 'content', - 'styles' => array( - 'global' => array( - 'color' => array( - 'custom' => false, - 'background' => 'red', - ), - 'unsupported/property' => array( - 'custom' => false, - 'background' => 'red', - ) - ), - 'core/invalid' => array( - 'color' => array( - 'custom' => 'false', - ), - ), - ) ) ); - $result = $theme_json->get_raw_data(); - - $expected = array( - 'styles' => array( - 'global' => array( - 'color' => array( - 'background' => 'red', - ), - ), - ), - ); $this->assertEqualSetsWithIndex( $expected, $result ); } @@ -117,7 +60,6 @@ function test_schema_validation_works_with_partial_data() { function test_schema_validation_subtree_is_removed_if_empty() { $theme_json = new WP_Theme_JSON( array( - 'invalid/key' => 'content', 'styles' => array( 'invalid/key' => array( 'color' => array( From 9efc1dc580f464d99cac46524c5ca40c1b504c5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Thu, 14 Jan 2021 17:49:46 +0100 Subject: [PATCH 10/65] Fix test_get_settings --- lib/class-wp-theme-json.php | 2 +- phpunit/class-wp-theme-json-test.php | 27 ++++++++++++++------------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index 3d39e6b61a15e6..a806140aaa2a88 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -321,7 +321,7 @@ public function __construct( $theme_json = array() ) { // Filter out the styles & settings subtrees for each block selector. foreach( $block_metadata as $block_selector => $metadata ) { - foreach( [ 'styles', 'settings '] as $key => $subtree ) { + foreach( [ 'styles', 'settings' ] as $key => $subtree ) { if ( isset( $this->theme_json[ $subtree ][ $block_selector] ) ) { self::process_subtree( $this->theme_json[ $subtree ][ $block_selector ], self::SCHEMA[ $subtree ] ); diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index 0320371146568a..0031bb2f47754a 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -98,31 +98,32 @@ function test_get_settings() { 'settings' => array( 'global' => array( 'color' => array( - 'link' => 'value', + 'custom' => false, ), - 'custom' => 'value', - 'typography' => 'value', - 'misc' => 'value', + 'invalid/key' => 'value', ), ), 'styles' => array( 'global' => array( - 'color' => 'value', - 'misc' => 'value', - ) + 'color' => array( + 'link' => 'blue', + ), + ), ), - 'misc' => 'value', ) ); $result = $theme_json->get_settings(); - $this->assertArrayHasKey( 'global', $result ); - $this->assertCount( 1, $result ); + $expected = array( + 'global' => array( + 'color' => array( + 'custom' => false, + ), + ), + ); - $this->assertArrayHasKey( 'color', $result['global'] ); - $this->assertArrayHasKey( 'custom', $result['global'] ); - $this->assertCount( 2, $result['global'] ); + $this->assertEqualSetsWithIndex( $expected, $result ); } // function test_get_stylesheet() { From 8fcd1d58104018851b84a056bda217a1d922e62d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Thu, 14 Jan 2021 17:56:24 +0100 Subject: [PATCH 11/65] Delete any subtree that is empty --- lib/class-wp-theme-json.php | 4 ++++ phpunit/class-wp-theme-json-test.php | 20 ++++++++++++++------ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index a806140aaa2a88..495d8a7e9e37ab 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -511,6 +511,10 @@ private static function process_subtree( &$subtree, $schema ) { foreach( $schema as $key => $data ) { if ( is_array( $schema[ $key ] ) && isset( $subtree[ $key ] ) ) { self::process_subtree( $subtree[ $key ], $schema[ $key ] ); + + if ( empty( $subtree[ $key ] ) ) { + unset( $subtree[ $key ] ); + } } } } diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index 0031bb2f47754a..7be3fef8b19419 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -60,17 +60,25 @@ function test_schema_validation_invalid_keys_are_removed() { function test_schema_validation_subtree_is_removed_if_empty() { $theme_json = new WP_Theme_JSON( array( - 'styles' => array( + 'settings' => array( 'invalid/key' => array( 'color' => array( - 'background' => 'red', + 'custom' => false, ), ), ), - 'settings' => array( + 'styles' => array( 'global' => array( 'color' => array( - 'custom' => false, + 'link' => 'blue', + ), + 'typography' => array( + 'invalid/key' => false, + ), + 'spacing' => array( + 'padding' => array( + 'invalid/key' => '10px', + ), ), ), ), @@ -79,10 +87,10 @@ function test_schema_validation_subtree_is_removed_if_empty() { $result = $theme_json->get_raw_data(); $expected = array( - 'settings' => array( + 'styles' => array( 'global' => array( 'color' => array( - 'custom' => false, + 'link' => 'blue', ), ), ), From 1f6ea63b8ea9c1f2da89a34eca69667de5d2a5e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Thu, 14 Jan 2021 18:16:41 +0100 Subject: [PATCH 12/65] Remove styles & settings if they are not arrays --- lib/class-wp-theme-json.php | 18 ++++++++---------- phpunit/class-wp-theme-json-test.php | 13 +++++++++++++ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index 495d8a7e9e37ab..8eb0ff233f14f4 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -306,16 +306,14 @@ public function __construct( $theme_json = array() ) { // Filter out all block selectors that aren't registered for styles & settings. $block_metadata = $this->get_blocks_metadata(); - if ( isset( $this->theme_json['styles'] ) ) { - $this->theme_json['styles'] = array_intersect_key( $this->theme_json['styles'], $block_metadata ); - if ( empty( $this->theme_json['styles'] ) ) { - unset( $this->theme_json['styles'] ); - } - } - if ( isset( $this->theme_json['settings'] ) ) { - $this->theme_json['settings'] = array_intersect_key( $this->theme_json['settings'], $block_metadata ); - if ( empty( $this->theme_json['settings'] ) ) { - unset( $this->theme_json['settings'] ); + foreach( [ 'settings', 'styles' ] as $key => $subtree ) { + if ( isset( $this->theme_json[ $subtree ] ) && ! is_array( $this->theme_json[ $subtree ] ) ) { + unset( $this->theme_json[ $subtree ] ); + } elseif ( isset( $this->theme_json[ $subtree ] ) ) { + $this->theme_json[ $subtree ] = array_intersect_key( $this->theme_json[ $subtree ], $block_metadata ); + if ( empty( $this->theme_json[ $subtree ] ) ) { + unset( $this->theme_json[ $subtree ] ); + } } } diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index 7be3fef8b19419..991f1b67004c4e 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -57,6 +57,19 @@ function test_schema_validation_invalid_keys_are_removed() { $this->assertEqualSetsWithIndex( $expected, $result ); } + function test_schema_validation_subtree_is_removed_if_not_array() { + $theme_json = new WP_Theme_JSON( + array( + 'styles' => 'invalid/not/array', + ) + ); + + $actual = $theme_json->get_raw_data(); + $expected = array(); + + $this->assertEqualSetsWithIndex( $expected, $actual ); + } + function test_schema_validation_subtree_is_removed_if_empty() { $theme_json = new WP_Theme_JSON( array( From 7079ce557e1a9023eaf93391ff9211d7406ebb42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Thu, 14 Jan 2021 18:22:34 +0100 Subject: [PATCH 13/65] Improve readibility --- lib/class-wp-theme-json.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index 8eb0ff233f14f4..1e305cfc041b9e 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -303,13 +303,16 @@ public function __construct( $theme_json = array() ) { // Filter out top-level keys that aren't valid according to the schema. $this->theme_json = array_intersect_key( $theme_json, self::SCHEMA ); + foreach( [ 'settings', 'styles'] as $key => $subtree ) { + if ( isset( $this->theme_json[ $subtree ] ) && ! is_array( $this->theme_json[ $subtree ] ) ) { + unset( $this->theme_json[ $subtree ] ); + } + } - // Filter out all block selectors that aren't registered for styles & settings. + // Filter out all block selectors within settings & styles that aren't registered. $block_metadata = $this->get_blocks_metadata(); foreach( [ 'settings', 'styles' ] as $key => $subtree ) { - if ( isset( $this->theme_json[ $subtree ] ) && ! is_array( $this->theme_json[ $subtree ] ) ) { - unset( $this->theme_json[ $subtree ] ); - } elseif ( isset( $this->theme_json[ $subtree ] ) ) { + if ( isset( $this->theme_json[ $subtree ] ) ) { $this->theme_json[ $subtree ] = array_intersect_key( $this->theme_json[ $subtree ], $block_metadata ); if ( empty( $this->theme_json[ $subtree ] ) ) { unset( $this->theme_json[ $subtree ] ); From 02f6b64328f1858ff4854a99e771829606745ece Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Thu, 14 Jan 2021 18:24:57 +0100 Subject: [PATCH 14/65] Remove block selectors if they are not arrays --- lib/class-wp-theme-json.php | 5 +++++ phpunit/class-wp-theme-json-test.php | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index 1e305cfc041b9e..f34480733a668c 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -324,6 +324,11 @@ public function __construct( $theme_json = array() ) { foreach( $block_metadata as $block_selector => $metadata ) { foreach( [ 'styles', 'settings' ] as $key => $subtree ) { if ( isset( $this->theme_json[ $subtree ][ $block_selector] ) ) { + if ( ! is_array( $this->theme_json[ $subtree ][ $block_selector] ) ) { + unset( $this->theme_json[ $subtree ][ $block_selector] ); + continue; + } + self::process_subtree( $this->theme_json[ $subtree ][ $block_selector ], self::SCHEMA[ $subtree ] ); if ( empty( $this->theme_json[ $subtree ][ $block_selector ] ) ) { diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index 991f1b67004c4e..ede1fee8960fe0 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -61,6 +61,9 @@ function test_schema_validation_subtree_is_removed_if_not_array() { $theme_json = new WP_Theme_JSON( array( 'styles' => 'invalid/not/array', + 'settings' => array( + 'global' => 'invalid/not/array', + ) ) ); @@ -79,6 +82,9 @@ function test_schema_validation_subtree_is_removed_if_empty() { 'custom' => false, ), ), + 'global' => array( + 'invalid/key' => false, + ), ), 'styles' => array( 'global' => array( From c9fa0a339d058e3b8ed5186468bb1f66b645eeca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Thu, 14 Jan 2021 18:27:37 +0100 Subject: [PATCH 15/65] Remove styles&settinsg if they are empty at the end of the processing --- lib/class-wp-theme-json.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index f34480733a668c..53b6f154cf8354 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -314,9 +314,6 @@ public function __construct( $theme_json = array() ) { foreach( [ 'settings', 'styles' ] as $key => $subtree ) { if ( isset( $this->theme_json[ $subtree ] ) ) { $this->theme_json[ $subtree ] = array_intersect_key( $this->theme_json[ $subtree ], $block_metadata ); - if ( empty( $this->theme_json[ $subtree ] ) ) { - unset( $this->theme_json[ $subtree ] ); - } } } @@ -337,6 +334,14 @@ public function __construct( $theme_json = array() ) { } } } + + // Filter if they're empty. + foreach( [ 'settings', 'styles' ] as $key => $subtree ) { + if ( empty( $this->theme_json[ $subtree ] ) ) { + unset( $this->theme_json[ $subtree ] ); + } + } + } /** From ce754eb95097afe23fbbc84247d2f09e15f77ae1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Thu, 14 Jan 2021 18:33:21 +0100 Subject: [PATCH 16/65] Expand test not array --- phpunit/class-wp-theme-json-test.php | 34 ++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index ede1fee8960fe0..80aab1fa976b02 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -60,15 +60,41 @@ function test_schema_validation_invalid_keys_are_removed() { function test_schema_validation_subtree_is_removed_if_not_array() { $theme_json = new WP_Theme_JSON( array( - 'styles' => 'invalid/not/array', - 'settings' => array( + 'settings' => 'invalid/not/array', + 'styles' => array( 'global' => 'invalid/not/array', - ) + 'core/paragraph' => array( + 'invalid/not/array' => false, + ), + 'core/group' => array( + 'invalid/not/array' => false, + 'color' => array( + 'invalid/not/array' => true, + ), + 'typography' => array( + 'invalid/key' => false, + 'lineHeight' => '2', + ), + 'spacing' => array( + 'padding' => array( + 'invalid/not/array' => '10px' + ), + ), + ), + ), ) ); $actual = $theme_json->get_raw_data(); - $expected = array(); + $expected = array( + 'styles' => array( + 'core/group' => array( + 'typography' => array( + 'lineHeight' => '2', + ), + ), + ), + ); $this->assertEqualSetsWithIndex( $expected, $actual ); } From 252d40b5d85553a25b1d558bd0e9cea7c126ca4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Thu, 14 Jan 2021 18:51:46 +0100 Subject: [PATCH 17/65] Improve readibility, add comments --- lib/class-wp-theme-json.php | 42 ++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index 53b6f154cf8354..fc2915fbcd235f 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -301,33 +301,37 @@ public function __construct( $theme_json = array() ) { return; } - // Filter out top-level keys that aren't valid according to the schema. + // Remove top-level keys that aren't present in the schema. $this->theme_json = array_intersect_key( $theme_json, self::SCHEMA ); - foreach( [ 'settings', 'styles'] as $key => $subtree ) { + + $block_metadata = $this->get_blocks_metadata(); + foreach( [ 'settings', 'styles' ] as $key => $subtree ) { + // Remove settings & styles if they aren't arrays. if ( isset( $this->theme_json[ $subtree ] ) && ! is_array( $this->theme_json[ $subtree ] ) ) { unset( $this->theme_json[ $subtree ] ); } - } - // Filter out all block selectors within settings & styles that aren't registered. - $block_metadata = $this->get_blocks_metadata(); - foreach( [ 'settings', 'styles' ] as $key => $subtree ) { + // Remove block selectors within settings & styles if that aren't registered. if ( isset( $this->theme_json[ $subtree ] ) ) { $this->theme_json[ $subtree ] = array_intersect_key( $this->theme_json[ $subtree ], $block_metadata ); } } - // Filter out the styles & settings subtrees for each block selector. + // Future optimization: at this point, we could iterate over the block selectors present + // in either styles or settings instead of iterating over all registered. foreach( $block_metadata as $block_selector => $metadata ) { foreach( [ 'styles', 'settings' ] as $key => $subtree ) { if ( isset( $this->theme_json[ $subtree ][ $block_selector] ) ) { + // Remove the block selector subtree if it's not an array. if ( ! is_array( $this->theme_json[ $subtree ][ $block_selector] ) ) { unset( $this->theme_json[ $subtree ][ $block_selector] ); continue; } - self::process_subtree( $this->theme_json[ $subtree ][ $block_selector ], self::SCHEMA[ $subtree ] ); + // Remove the properties within the styles & settings subtrees if they aren't present in the schema. + self::remove_keys_not_in_schema( $this->theme_json[ $subtree ][ $block_selector ], self::SCHEMA[ $subtree ] ); + // Remove the block selector subtree if it is empty after having processed it. if ( empty( $this->theme_json[ $subtree ][ $block_selector ] ) ) { unset( $this->theme_json[ $subtree ][ $block_selector ] ); } @@ -335,7 +339,7 @@ public function __construct( $theme_json = array() ) { } } - // Filter if they're empty. + // Remove the settings & styles subtrees if they're empty after having processed them. foreach( [ 'settings', 'styles' ] as $key => $subtree ) { if ( empty( $this->theme_json[ $subtree ] ) ) { unset( $this->theme_json[ $subtree ] ); @@ -516,15 +520,23 @@ private static function get_blocks_metadata() { return self::$blocks_metadata; } - private static function process_subtree( &$subtree, $schema ) { - $subtree = array_intersect_key( $subtree, $schema ); + /** + * Given a tree, removes the keys that are not present in the schema. + * + * It is recursive and modifies the input in-place. + * + * @param array $tree Input to process. + * @param array $schema Schema to adhere to. + */ + private static function remove_keys_not_in_schema( &$tree, $schema ) { + $tree = array_intersect_key( $tree, $schema ); foreach( $schema as $key => $data ) { - if ( is_array( $schema[ $key ] ) && isset( $subtree[ $key ] ) ) { - self::process_subtree( $subtree[ $key ], $schema[ $key ] ); + if ( is_array( $schema[ $key ] ) && isset( $tree[ $key ] ) ) { + self::remove_keys_not_in_schema( $tree[ $key ], $schema[ $key ] ); - if ( empty( $subtree[ $key ] ) ) { - unset( $subtree[ $key ] ); + if ( empty( $tree[ $key ] ) ) { + unset( $tree[ $key ] ); } } } From 1970ba92d84ea360cc85ee60e20abeb2acd40e8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Thu, 14 Jan 2021 18:52:39 +0100 Subject: [PATCH 18/65] Remove unused method --- lib/class-wp-theme-json.php | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index fc2915fbcd235f..64ef9ad3415a11 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -542,40 +542,6 @@ private static function remove_keys_not_in_schema( &$tree, $schema ) { } } - /** - * Normalize the subtree according to the given schema. - * This function modifies the given input by removing - * the nodes that aren't valid per the schema. - * - * @param string $key Key of the subtree to normalize. - * @param array $input Whole tree to normalize. - * @param array $schema Schema to use for normalization. - */ - private static function process_key( $key, &$input, $schema ) { - if ( ! isset( $input[ $key ] ) ) { - return; - } - - // Consider valid the input value. - if ( null === $schema[ $key ] ) { - return; - } - - if ( ! is_array( $input[ $key ] ) ) { - unset( $input[ $key ] ); - return; - } - - $input[ $key ] = array_intersect_key( - $input[ $key ], - $schema[ $key ] - ); - - if ( 0 === count( $input[ $key ] ) ) { - unset( $input[ $key ] ); - } - } - /** * Given a tree, it creates a flattened one * by merging the keys and binding the leaf values From d82bbcbf0669df56eb91acc2cadd2a26326ece90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Thu, 14 Jan 2021 19:02:17 +0100 Subject: [PATCH 19/65] Prepare test --- phpunit/class-wp-theme-json-test.php | 204 +++++++++++++-------------- 1 file changed, 102 insertions(+), 102 deletions(-) diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index 80aab1fa976b02..cff0af278669dd 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -244,115 +244,115 @@ function test_get_settings() { // ); // } - // public function test_merge_incoming_data() { - // $initial = array( - // 'settings' => array( - // 'global' => array( - // 'color' => array( - // 'custom' => 'false', - // 'palette' => array( - // array( - // 'slug' => 'red', - // 'color' => 'red', - // ), - // array( - // 'slug' => 'blue', - // 'color' => 'blue', - // ), - // ), - // ), - // ), - // 'core/paragraph' => array( - // 'color' => array( - // 'custom' => 'false', - // ), - // ), - // ), - // 'styles' => array( - // 'global' => array( - // 'typography' => array( - // 'fontSize' => '12', - // ), - // ) - // ), - // ); + public function test_merge_incoming_data() { + $initial = array( + 'settings' => array( + 'global' => array( + 'color' => array( + 'custom' => 'false', + 'palette' => array( + array( + 'slug' => 'red', + 'color' => 'red', + ), + array( + 'slug' => 'blue', + 'color' => 'blue', + ), + ), + ), + ), + 'core/paragraph' => array( + 'color' => array( + 'custom' => 'false', + ), + ), + ), + 'styles' => array( + 'global' => array( + 'typography' => array( + 'fontSize' => '12', + ), + ) + ), + ); - // $add_new_context = array( - // 'settings' => array( - // 'core/list' => array( - // 'color' => array( - // 'custom' => 'false', - // ), - // ), - // ), - // 'styles' => array( - // 'core/list' => array( - // 'typography' => array( - // 'fontSize' => '12', - // ), - // 'color' => array( - // 'link' => 'pink', - // 'background' => 'brown', - // ), - // ), - // ), - // ); + $add_new_context = array( + 'settings' => array( + 'core/list' => array( + 'color' => array( + 'custom' => 'false', + ), + ), + ), + 'styles' => array( + 'core/list' => array( + 'typography' => array( + 'fontSize' => '12', + ), + 'color' => array( + 'link' => 'pink', + 'background' => 'brown', + ), + ), + ), + ); - // $add_key_in_settings = array( - // 'settings' => array( - // 'global' => array( - // 'color' => array( - // 'customGradient' => 'true', - // ), - // ), - // ), - // ); + $add_key_in_settings = array( + 'settings' => array( + 'global' => array( + 'color' => array( + 'customGradient' => 'true', + ), + ), + ), + ); - // $update_key_in_settings = array( - // 'settings' => array( - // 'global' => array( - // 'color' => array( - // 'custom' => 'true', - // ), - // ), - // ), - // ); + $update_key_in_settings = array( + 'settings' => array( + 'global' => array( + 'color' => array( + 'custom' => 'true', + ), + ), + ), + ); - // $add_styles = array( - // 'styles' => array( - // 'core/paragraph' => array( - // 'typography' => array( - // 'fontSize' => '12', - // ), - // 'color' => array( - // 'link' => 'pink', - // ), - // ), - // ), - // ); + $add_styles = array( + 'styles' => array( + 'core/paragraph' => array( + 'typography' => array( + 'fontSize' => '12', + ), + 'color' => array( + 'link' => 'pink', + ), + ), + ), + ); - // $add_key_in_styles = array( - // 'styles' => array( - // 'core/paragraph' => array( - // 'typography' => array( - // 'lineHeight' => '12', - // ), - // ), - // ), - // ); + $add_key_in_styles = array( + 'styles' => array( + 'core/paragraph' => array( + 'typography' => array( + 'lineHeight' => '12', + ), + ), + ), + ); - // $add_invalid_context = array( - // 'styles' => array( - // 'core/para' => array( - // 'typography' => array( - // 'lineHeight' => '12', - // ), - // ), - // ), - // ); + $add_invalid_context = array( + 'styles' => array( + 'core/para' => array( + 'typography' => array( + 'lineHeight' => '12', + ), + ), + ), + ); - // $this->assertEqualSetsWithIndex( $expected, $result ); - // } + $this->assertEqualSetsWithIndex( $expected, $result ); + } function test_remove_insecure_properties_removes_invalid_contexts() { $theme_json = new WP_Theme_JSON( From ee639720f01c0b9560e42c73d3d5daaf01455429 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Fri, 15 Jan 2021 11:52:29 +0100 Subject: [PATCH 20/65] Rename test --- phpunit/class-wp-theme-json-test.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index cff0af278669dd..197d7547be8068 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -8,7 +8,7 @@ class WP_Theme_JSON_Test extends WP_UnitTestCase { - function test_schema_validation_invalid_keys_are_removed() { + function test_schema_validation_subtree_is_removed_if_key_invalid() { $theme_json = new WP_Theme_JSON( array( 'invalid/key' => 'content', From 6f545aadc0da7e11663b83cbe6105a0944b59a2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Fri, 15 Jan 2021 11:57:27 +0100 Subject: [PATCH 21/65] Adapt remove insecure props test to new theme.json shape --- phpunit/class-wp-theme-json-test.php | 80 +++++++++++++--------------- 1 file changed, 37 insertions(+), 43 deletions(-) diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index 197d7547be8068..a521e61d1b6c59 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -357,16 +357,14 @@ public function test_merge_incoming_data() { function test_remove_insecure_properties_removes_invalid_contexts() { $theme_json = new WP_Theme_JSON( array( - 'global' => array( - 'styles' => array( + 'styles' => array( + 'global' => array( 'color' => array( 'background' => 'green', 'text' => 'var:preset|color|dark-gray', ), ), - ), - '.my-class' => array( - 'styles' => array( + '.my-class' => array( 'color' => array( 'background' => 'green', 'text' => 'var:preset|color|dark-gray', @@ -379,8 +377,8 @@ function test_remove_insecure_properties_removes_invalid_contexts() { $theme_json->remove_insecure_properties(); $result = $theme_json->get_raw_data(); $expected = array( - 'global' => array( - 'styles' => array( + 'styles' => array( + 'global' => array( 'color' => array( 'background' => 'green', 'text' => 'var:preset|color|dark-gray', @@ -394,8 +392,8 @@ function test_remove_insecure_properties_removes_invalid_contexts() { function test_remove_insecure_properties_removes_invalid_properties() { $theme_json = new WP_Theme_JSON( array( - 'global' => array( - 'styles' => array( + 'styles' => array( + 'global' => array( 'color' => array( 'gradient' => 'linear-gradient(55deg,rgba(6,147,227,1) 0%,rgb(84,177,218) 54%,rgb(155,81,224) 100%)', 'text' => 'var:preset|color|dark-gray', @@ -411,8 +409,8 @@ function test_remove_insecure_properties_removes_invalid_properties() { $theme_json->remove_insecure_properties(); $result = $theme_json->get_raw_data(); $expected = array( - 'global' => array( - 'styles' => array( + 'styles' => array( + 'global' => array( 'color' => array( 'gradient' => 'linear-gradient(55deg,rgba(6,147,227,1) 0%,rgb(84,177,218) 54%,rgb(155,81,224) 100%)', 'text' => 'var:preset|color|dark-gray', @@ -426,8 +424,8 @@ function test_remove_insecure_properties_removes_invalid_properties() { function test_remove_insecure_properties_removes_unsafe_properties() { $theme_json = new WP_Theme_JSON( array( - 'global' => array( - 'styles' => array( + 'styles' => array( + 'global' => array( 'color' => array( 'gradient' => 'url(\'data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxMCcgaGVpZ2h0PScxMCc+PHNjcmlwdD5hbGVydCgnb2snKTwvc2NyaXB0PjxsaW5lYXJHcmFkaWVudCBpZD0nZ3JhZGllbnQnPjxzdG9wIG9mZnNldD0nMTAlJyBzdG9wLWNvbG9yPScjRjAwJy8+PHN0b3Agb2Zmc2V0PSc5MCUnIHN0b3AtY29sb3I9JyNmY2MnLz4gPC9saW5lYXJHcmFkaWVudD48cmVjdCBmaWxsPSd1cmwoI2dyYWRpZW50KScgeD0nMCcgeT0nMCcgd2lkdGg9JzEwMCUnIGhlaWdodD0nMTAwJScvPjwvc3ZnPg==\')', 'text' => 'var:preset|color|dark-gray', @@ -443,8 +441,8 @@ function test_remove_insecure_properties_removes_unsafe_properties() { $theme_json->remove_insecure_properties(); $result = $theme_json->get_raw_data(); $expected = array( - 'global' => array( - 'styles' => array( + 'styles' => array( + 'global' => array( 'color' => array( 'text' => 'var:preset|color|dark-gray', ), @@ -457,10 +455,10 @@ function test_remove_insecure_properties_removes_unsafe_properties() { function test_remove_insecure_properties_removes_properties_when_not_allowed_in_a_context() { $theme_json = new WP_Theme_JSON( array( - 'global' => array( - 'styles' => array( - 'color' => array( - 'text' => 'var:preset|color|dark-gray', + 'styles' => array( + 'global' => array( + 'color' => array( + 'text' => 'var:preset|color|dark-gray', ), 'spacing' => array( 'padding' => array( @@ -474,9 +472,7 @@ function test_remove_insecure_properties_removes_properties_when_not_allowed_in_ 'invalid' => array( 'background' => 'green', ), - ), - 'core/group' => array( - 'styles' => array( + 'core/group' => array( 'spacing' => array( 'padding' => array( 'top' => '1px', @@ -493,15 +489,13 @@ function test_remove_insecure_properties_removes_properties_when_not_allowed_in_ $theme_json->remove_insecure_properties(); $result = $theme_json->get_raw_data(); $expected = array( - 'global' => array( - 'styles' => array( + 'styles' => array( + 'global' => array( 'color' => array( 'text' => 'var:preset|color|dark-gray', ), ), - ), - 'core/group' => array( - 'styles' => array( + 'core/group' => array( 'spacing' => array( 'padding' => array( 'top' => '1px', @@ -519,8 +513,8 @@ function test_remove_insecure_properties_removes_properties_when_not_allowed_in_ function test_remove_insecure_properties_removes_unsafe_sub_properties() { $theme_json = new WP_Theme_JSON( array( - 'core/group' => array( - 'styles' => array( + 'styles' => array( + 'core/group' => array( 'spacing' => array( 'padding' => array( 'top' => '1px', @@ -537,8 +531,8 @@ function test_remove_insecure_properties_removes_unsafe_sub_properties() { $theme_json->remove_insecure_properties(); $result = $theme_json->get_raw_data(); $expected = array( - 'core/group' => array( - 'styles' => array( + 'styles' => array( + 'core/group' => array( 'spacing' => array( 'padding' => array( 'top' => '1px', @@ -555,10 +549,10 @@ function test_remove_insecure_properties_removes_unsafe_sub_properties() { function test_remove_insecure_properties_removes_non_preset_settings() { $theme_json = new WP_Theme_JSON( array( - 'global' => array( - 'settings' => array( - 'color' => array( - 'custom' => true, + 'settings' => array( + 'global' => array( + 'color' => array( + 'custom' => true, 'palette' => array( array( 'name' => 'Red', @@ -588,8 +582,8 @@ function test_remove_insecure_properties_removes_non_preset_settings() { $theme_json->remove_insecure_properties(); $result = $theme_json->get_raw_data(); $expected = array( - 'global' => array( - 'settings' => array( + 'settings' => array( + 'global' => array( 'color' => array( 'palette' => array( array( @@ -618,9 +612,9 @@ function test_remove_insecure_properties_removes_non_preset_settings() { function test_remove_insecure_properties_removes_unsafe_preset_settings() { $theme_json = new WP_Theme_JSON( array( - 'global' => array( - 'settings' => array( - 'color' => array( + 'settings' => array( + 'global' => array( + 'color' => array( 'palette' => array( array( 'name' => 'Red/>ok', @@ -676,9 +670,9 @@ function test_remove_insecure_properties_removes_unsafe_preset_settings() { $theme_json->remove_insecure_properties(); $result = $theme_json->get_raw_data(); $expected = array( - 'global' => array( - 'settings' => array( - 'color' => array( + 'settings' => array( + 'global' => array( + 'color' => array( 'palette' => array( array( 'name' => 'Pink', From 6d56160afb7c375415928e9333ee9350df92a030 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Fri, 15 Jan 2021 13:53:09 +0100 Subject: [PATCH 22/65] Adapt to section/styles being top-level --- lib/class-wp-theme-json.php | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index 64ef9ad3415a11..e807eeacb67f7e 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -976,35 +976,36 @@ public function get_stylesheet( $type = 'all' ) { /** * Merge new incoming data. * - * @param WP_Theme_JSON $theme_json Data to merge. + * @param WP_Theme_JSON $incoming Data to merge. */ - public function merge( $theme_json ) { - $incoming_data = $theme_json->get_raw_data(); + public function merge( $incoming ) { + $incoming_data = $incoming ->get_raw_data(); + $blocks_metadata = self::get_blocks_metadata(); - foreach ( array_keys( $incoming_data ) as $context ) { + foreach ( $blocks_metadata as $block_selector => $metadata ) { foreach ( array( 'settings', 'styles' ) as $subtree ) { - if ( ! isset( $incoming_data[ $context ][ $subtree ] ) ) { + if ( ! isset( $incoming_data[ $subtree ][ $block_selector ] ) ) { continue; } - if ( ! isset( $this->theme_json[ $context ][ $subtree ] ) ) { - $this->theme_json[ $context ][ $subtree ] = $incoming_data[ $context ][ $subtree ]; + if ( ! isset( $this->theme_json[ $subtree ][ $block_selector ] ) ) { + $this->theme_json[ $subtree ][ $block_selector ] = $incoming_data[ $subtree ][ $block_selector ]; continue; } - foreach ( array_keys( self::SCHEMA[ $subtree ] ) as $leaf ) { - if ( ! isset( $incoming_data[ $context ][ $subtree ][ $leaf ] ) ) { + foreach ( array_keys( self::SCHEMA[ $subtree ] ) as $section ) { + if ( ! isset( $incoming_data[ $subtree ][ $block_selector ][ $section ] ) ) { continue; } - if ( ! isset( $this->theme_json[ $context ][ $subtree ][ $leaf ] ) ) { - $this->theme_json[ $context ][ $subtree ][ $leaf ] = $incoming_data[ $context ][ $subtree ][ $leaf ]; + if ( ! isset( $this->theme_json[ $subtree ][ $block_selector ][ $section ] ) ) { + $this->theme_json[ $subtree ][ $block_selector ][ $section ] = $incoming_data[ $subtree ][ $block_selector ][ $section ]; continue; } - $this->theme_json[ $context ][ $subtree ][ $leaf ] = array_merge( - $this->theme_json[ $context ][ $subtree ][ $leaf ], - $incoming_data[ $context ][ $subtree ][ $leaf ] + $this->theme_json[ $subtree ][ $block_selector ][ $section ] = array_merge( + $this->theme_json[ $subtree ][ $block_selector ][ $section ], + $incoming_data[ $subtree ][ $block_selector ][ $section ] ); } } From c7332d514e4afcc4967ade22c588a5b97a10ee10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Fri, 15 Jan 2021 13:53:19 +0100 Subject: [PATCH 23/65] Add failing test to demonstrate bug --- phpunit/class-wp-theme-json-test.php | 529 +++++++++++++++++++++------ 1 file changed, 418 insertions(+), 111 deletions(-) diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index a521e61d1b6c59..b0ab3e8a632d43 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -249,7 +249,7 @@ public function test_merge_incoming_data() { 'settings' => array( 'global' => array( 'color' => array( - 'custom' => 'false', + 'custom' => false, 'palette' => array( array( 'slug' => 'red', @@ -264,7 +264,7 @@ public function test_merge_incoming_data() { ), 'core/paragraph' => array( 'color' => array( - 'custom' => 'false', + 'custom' => false, ), ), ), @@ -273,20 +273,20 @@ public function test_merge_incoming_data() { 'typography' => array( 'fontSize' => '12', ), - ) + ), ), ); - $add_new_context = array( + $add_new_block = array( 'settings' => array( 'core/list' => array( 'color' => array( - 'custom' => 'false', + 'custom' => false, ), ), ), - 'styles' => array( - 'core/list' => array( + 'styles' => array( + 'core/list' => array( 'typography' => array( 'fontSize' => '12', ), @@ -302,7 +302,7 @@ public function test_merge_incoming_data() { 'settings' => array( 'global' => array( 'color' => array( - 'customGradient' => 'true', + 'customGradient' => true, ), ), ), @@ -312,7 +312,7 @@ public function test_merge_incoming_data() { 'settings' => array( 'global' => array( 'color' => array( - 'custom' => 'true', + 'custom' => true, ), ), ), @@ -321,11 +321,10 @@ public function test_merge_incoming_data() { $add_styles = array( 'styles' => array( 'core/paragraph' => array( - 'typography' => array( - 'fontSize' => '12', - ), - 'color' => array( - 'link' => 'pink', + 'spacing' => array( + 'padding' => array( + 'top' => '12px' + ) ), ), ), @@ -334,8 +333,10 @@ public function test_merge_incoming_data() { $add_key_in_styles = array( 'styles' => array( 'core/paragraph' => array( - 'typography' => array( - 'lineHeight' => '12', + 'spacing' => array( + 'padding' => array( + 'bottom' => '12px', + ), ), ), ), @@ -571,128 +572,434 @@ function test_remove_insecure_properties_removes_non_preset_settings() { ), ), ), - 'spacing' => array( - 'customPadding' => false, - ), ), ), ), - true ); - $theme_json->remove_insecure_properties(); - $result = $theme_json->get_raw_data(); + $expected = array( 'settings' => array( - 'global' => array( - 'color' => array( - 'palette' => array( - array( - 'name' => 'Red', - 'slug' => 'red', - 'color' => '#ff0000', - ), + 'global' => array( + 'color' => array( + 'custom' => true, + 'customGradient' => true, + 'palette' => array( array( - 'name' => 'Green', - 'slug' => 'green', - 'color' => '#00ff00', + 'slug' => 'color', + 'color' => 'color', ), + ), + 'gradients' => array( array( - 'name' => 'Blue', - 'slug' => 'blue', - 'color' => '#0000ff', + 'slug' => 'gradient', + 'gradient' => 'gradient', ), ), ), - ), - ), - ); - $this->assertEqualSetsWithIndex( $expected, $result ); - } - - function test_remove_insecure_properties_removes_unsafe_preset_settings() { - $theme_json = new WP_Theme_JSON( - array( - 'settings' => array( - 'global' => array( - 'color' => array( - 'palette' => array( - array( - 'name' => 'Red/>ok', - 'slug' => 'red', - 'color' => '#ff0000', - ), - array( - 'name' => 'Green', - 'slug' => 'a" attr', - 'color' => '#00ff00', - ), - array( - 'name' => 'Blue', - 'slug' => 'blue', - 'color' => 'var(--custom-v1)', - ), - array( - 'name' => 'Pink', - 'slug' => 'pink', - 'color' => '#FFC0CB', - ), + 'typography' => array( + 'fontSizes' => array( + array( + 'slug' => 'fontSize', + 'size' => 'fontSize', ), ), - 'typography' => array( - 'fontFamilies' => array( - array( - 'name' => 'Helvetica Arial/>test', - 'slug' => 'helvetica-arial', - 'fontFamily' => 'Helvetica Neue, Helvetica, Arial, sans-serif', - ), - array( - 'name' => 'Geneva', - 'slug' => 'geneva#asa', - 'fontFamily' => 'Geneva, Tahoma, Verdana, sans-serif', - ), - array( - 'name' => 'Cambria', - 'slug' => 'cambria', - 'fontFamily' => 'Cambria, Georgia, serif', - ), - array( - 'name' => 'Helvetica Arial', - 'slug' => 'helvetica-arial', - 'fontFamily' => 'var(--custom-var-1)', - ), + 'fontFamilies' => array( + array( + 'slug' => 'fontFamily', + 'fontFamily' => 'fontFamily', ), ), ), ), + 'core/paragraph' => array( + 'color' => array( + 'custom' => false, + ), + ), + 'core/list' => array( + 'color' => array( + 'custom' => false, + ), + ), ), - true - ); - $theme_json->remove_insecure_properties(); - $result = $theme_json->get_raw_data(); - $expected = array( - 'settings' => array( + 'styles' => array( 'global' => array( - 'color' => array( - 'palette' => array( - array( - 'name' => 'Pink', - 'slug' => 'pink', - 'color' => '#FFC0CB', - ), + 'typography' => array( + 'fontSize' => '12', + ), + ), + 'core/paragraph' => array( + 'spacing' => array( + 'padding' => array( + 'top' => '12px', + 'bottom' => '12px', ), ), + ), + 'core/list' => array( 'typography' => array( - 'fontFamilies' => array( - array( - 'name' => 'Cambria', - 'slug' => 'cambria', - 'fontFamily' => 'Cambria, Georgia, serif', - ), - ), + 'fontSize' => '12', + ), + 'color' => array( + 'link' => 'pink', + 'background' => 'brown', ), ), ), ); + + $theme_json = new WP_Theme_JSON( $initial ); + $theme_json->merge( new WP_Theme_JSON( $add_new_block ) ); + $theme_json->merge( new WP_Theme_JSON( $add_key_in_settings ) ); + $theme_json->merge( new WP_Theme_JSON( $update_key_in_settings ) ); + $theme_json->merge( new WP_Theme_JSON( $add_styles ) ); + $theme_json->merge( new WP_Theme_JSON( $add_key_in_styles ) ); + $theme_json->merge( new WP_Theme_JSON( $add_invalid_context ) ); + $theme_json->merge( new WP_Theme_JSON( $update_presets ) ); + $result = $theme_json->get_raw_data(); + $this->assertEqualSetsWithIndex( $expected, $result ); } + + // function test_remove_insecure_properties_removes_invalid_contexts() { + // $theme_json = new WP_Theme_JSON( + // array( + // 'styles' => array( + // 'global' => array( + // 'color' => array( + // 'background' => 'green', + // 'text' => 'var:preset|color|dark-gray', + // ), + // ), + // '.my-class' => array( + // 'color' => array( + // 'background' => 'green', + // 'text' => 'var:preset|color|dark-gray', + // ), + // ), + // ), + // ), + // true + // ); + // $theme_json->remove_insecure_properties(); + // $result = $theme_json->get_raw_data(); + // $expected = array( + // 'styles' => array( + // 'global' => array( + // 'color' => array( + // 'background' => 'green', + // 'text' => 'var:preset|color|dark-gray', + // ), + // ), + // ), + // ); + // $this->assertEqualSetsWithIndex( $expected, $result ); + // } + + // function test_remove_insecure_properties_removes_invalid_properties() { + // $theme_json = new WP_Theme_JSON( + // array( + // 'styles' => array( + // 'global' => array( + // 'color' => array( + // 'gradient' => 'linear-gradient(55deg,rgba(6,147,227,1) 0%,rgb(84,177,218) 54%,rgb(155,81,224) 100%)', + // 'text' => 'var:preset|color|dark-gray', + // ), + // ), + // 'invalid' => array( + // 'background' => 'green', + // ), + // ), + // ), + // true + // ); + // $theme_json->remove_insecure_properties(); + // $result = $theme_json->get_raw_data(); + // $expected = array( + // 'styles' => array( + // 'global' => array( + // 'color' => array( + // 'gradient' => 'linear-gradient(55deg,rgba(6,147,227,1) 0%,rgb(84,177,218) 54%,rgb(155,81,224) 100%)', + // 'text' => 'var:preset|color|dark-gray', + // ), + // ), + // ), + // ); + // $this->assertEqualSetsWithIndex( $expected, $result ); + // } + + // function test_remove_insecure_properties_removes_unsafe_properties() { + // $theme_json = new WP_Theme_JSON( + // array( + // 'styles' => array( + // 'global' => array( + // 'color' => array( + // 'gradient' => 'url(\'data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxMCcgaGVpZ2h0PScxMCc+PHNjcmlwdD5hbGVydCgnb2snKTwvc2NyaXB0PjxsaW5lYXJHcmFkaWVudCBpZD0nZ3JhZGllbnQnPjxzdG9wIG9mZnNldD0nMTAlJyBzdG9wLWNvbG9yPScjRjAwJy8+PHN0b3Agb2Zmc2V0PSc5MCUnIHN0b3AtY29sb3I9JyNmY2MnLz4gPC9saW5lYXJHcmFkaWVudD48cmVjdCBmaWxsPSd1cmwoI2dyYWRpZW50KScgeD0nMCcgeT0nMCcgd2lkdGg9JzEwMCUnIGhlaWdodD0nMTAwJScvPjwvc3ZnPg==\')', + // 'text' => 'var:preset|color|dark-gray', + // ), + // ), + // 'invalid' => array( + // 'background' => 'green', + // ), + // ), + // ), + // true + // ); + // $theme_json->remove_insecure_properties(); + // $result = $theme_json->get_raw_data(); + // $expected = array( + // 'styles' => array( + // 'global' => array( + // 'color' => array( + // 'text' => 'var:preset|color|dark-gray', + // ), + // ), + // ), + // ); + // $this->assertEqualSetsWithIndex( $expected, $result ); + // } + + // function test_remove_insecure_properties_removes_properties_when_not_allowed_in_a_context() { + // $theme_json = new WP_Theme_JSON( + // array( + // 'styles' => array( + // 'global' => array( + // 'color' => array( + // 'text' => 'var:preset|color|dark-gray', + // ), + // 'spacing' => array( + // 'padding' => array( + // 'top' => '1px', + // 'right' => '1px', + // 'bottom' => '1px', + // 'left' => '1px', + // ), + // ), + // ), + // 'invalid' => array( + // 'background' => 'green', + // ), + // 'core/group' => array( + // 'spacing' => array( + // 'padding' => array( + // 'top' => '1px', + // 'right' => '1px', + // 'bottom' => '1px', + // 'left' => '1px', + // ), + // ), + // ), + // ), + // ), + // true + // ); + // $theme_json->remove_insecure_properties(); + // $result = $theme_json->get_raw_data(); + // $expected = array( + // 'styles' => array( + // 'global' => array( + // 'color' => array( + // 'text' => 'var:preset|color|dark-gray', + // ), + // ), + // 'core/group' => array( + // 'spacing' => array( + // 'padding' => array( + // 'top' => '1px', + // 'right' => '1px', + // 'bottom' => '1px', + // 'left' => '1px', + // ), + // ), + // ), + // ), + // ); + // $this->assertEqualSetsWithIndex( $expected, $result ); + // } + + // function test_remove_insecure_properties_removes_unsafe_sub_properties() { + // $theme_json = new WP_Theme_JSON( + // array( + // 'styles' => array( + // 'core/group' => array( + // 'spacing' => array( + // 'padding' => array( + // 'top' => '1px', + // 'right' => '1px', + // 'bottom' => 'var(--unsafe-var-y)', + // 'left' => '1px', + // ), + // ), + // ), + // ), + // ), + // true + // ); + // $theme_json->remove_insecure_properties(); + // $result = $theme_json->get_raw_data(); + // $expected = array( + // 'styles' => array( + // 'core/group' => array( + // 'spacing' => array( + // 'padding' => array( + // 'top' => '1px', + // 'right' => '1px', + // 'left' => '1px', + // ), + // ), + // ), + // ), + // ); + // $this->assertEqualSetsWithIndex( $expected, $result ); + // } + + // function test_remove_insecure_properties_removes_non_preset_settings() { + // $theme_json = new WP_Theme_JSON( + // array( + // 'settings' => array( + // 'global' => array( + // 'color' => array( + // 'custom' => true, + // 'palette' => array( + // array( + // 'name' => 'Red', + // 'slug' => 'red', + // 'color' => '#ff0000', + // ), + // array( + // 'name' => 'Green', + // 'slug' => 'green', + // 'color' => '#00ff00', + // ), + // array( + // 'name' => 'Blue', + // 'slug' => 'blue', + // 'color' => '#0000ff', + // ), + // ), + // ), + // 'spacing' => array( + // 'customPadding' => false, + // ), + // ), + // ), + // ), + // true + // ); + // $theme_json->remove_insecure_properties(); + // $result = $theme_json->get_raw_data(); + // $expected = array( + // 'settings' => array( + // 'global' => array( + // 'color' => array( + // 'palette' => array( + // array( + // 'name' => 'Red', + // 'slug' => 'red', + // 'color' => '#ff0000', + // ), + // array( + // 'name' => 'Green', + // 'slug' => 'green', + // 'color' => '#00ff00', + // ), + // array( + // 'name' => 'Blue', + // 'slug' => 'blue', + // 'color' => '#0000ff', + // ), + // ), + // ), + // ), + // ), + // ); + // $this->assertEqualSetsWithIndex( $expected, $result ); + // } + + // function test_remove_insecure_properties_removes_unsafe_preset_settings() { + // $theme_json = new WP_Theme_JSON( + // array( + // 'settings' => array( + // 'global' => array( + // 'color' => array( + // 'palette' => array( + // array( + // 'name' => 'Red/>ok', + // 'slug' => 'red', + // 'color' => '#ff0000', + // ), + // array( + // 'name' => 'Green', + // 'slug' => 'a" attr', + // 'color' => '#00ff00', + // ), + // array( + // 'name' => 'Blue', + // 'slug' => 'blue', + // 'color' => 'var(--custom-v1)', + // ), + // array( + // 'name' => 'Pink', + // 'slug' => 'pink', + // 'color' => '#FFC0CB', + // ), + // ), + // ), + // 'typography' => array( + // 'fontFamilies' => array( + // array( + // 'name' => 'Helvetica Arial/>test', + // 'slug' => 'helvetica-arial', + // 'fontFamily' => 'Helvetica Neue, Helvetica, Arial, sans-serif', + // ), + // array( + // 'name' => 'Geneva', + // 'slug' => 'geneva#asa', + // 'fontFamily' => 'Geneva, Tahoma, Verdana, sans-serif', + // ), + // array( + // 'name' => 'Cambria', + // 'slug' => 'cambria', + // 'fontFamily' => 'Cambria, Georgia, serif', + // ), + // array( + // 'name' => 'Helvetica Arial', + // 'slug' => 'helvetica-arial', + // 'fontFamily' => 'var(--custom-var-1)', + // ), + // ), + // ), + // ), + // ), + // ), + // true + // ); + // $theme_json->remove_insecure_properties(); + // $result = $theme_json->get_raw_data(); + // $expected = array( + // 'settings' => array( + // 'global' => array( + // 'color' => array( + // 'palette' => array( + // array( + // 'name' => 'Pink', + // 'slug' => 'pink', + // 'color' => '#FFC0CB', + // ), + // ), + // ), + // 'typography' => array( + // 'fontFamilies' => array( + // array( + // 'name' => 'Cambria', + // 'slug' => 'cambria', + // 'fontFamily' => 'Cambria, Georgia, serif', + // ), + // ), + // ), + // ), + // ), + // ); + // $this->assertEqualSetsWithIndex( $expected, $result ); + // } } From bafc56bdae79057e7a60f487d2bfff7a984d3a7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Fri, 15 Jan 2021 18:36:43 +0100 Subject: [PATCH 24/65] Simplify merge method --- lib/class-wp-theme-json.php | 35 ++++------------------------ phpunit/class-wp-theme-json-test.php | 8 +++---- 2 files changed, 9 insertions(+), 34 deletions(-) diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index e807eeacb67f7e..c633c155800a98 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -979,37 +979,12 @@ public function get_stylesheet( $type = 'all' ) { * @param WP_Theme_JSON $incoming Data to merge. */ public function merge( $incoming ) { - $incoming_data = $incoming ->get_raw_data(); - $blocks_metadata = self::get_blocks_metadata(); - - foreach ( $blocks_metadata as $block_selector => $metadata ) { - foreach ( array( 'settings', 'styles' ) as $subtree ) { - if ( ! isset( $incoming_data[ $subtree ][ $block_selector ] ) ) { - continue; - } - - if ( ! isset( $this->theme_json[ $subtree ][ $block_selector ] ) ) { - $this->theme_json[ $subtree ][ $block_selector ] = $incoming_data[ $subtree ][ $block_selector ]; - continue; - } - - foreach ( array_keys( self::SCHEMA[ $subtree ] ) as $section ) { - if ( ! isset( $incoming_data[ $subtree ][ $block_selector ][ $section ] ) ) { - continue; - } + $incoming_data = $incoming->get_raw_data(); + $this->theme_json = array_replace_recursive( $this->theme_json, $incoming_data ); - if ( ! isset( $this->theme_json[ $subtree ][ $block_selector ][ $section ] ) ) { - $this->theme_json[ $subtree ][ $block_selector ][ $section ] = $incoming_data[ $subtree ][ $block_selector ][ $section ]; - continue; - } - - $this->theme_json[ $subtree ][ $block_selector ][ $section ] = array_merge( - $this->theme_json[ $subtree ][ $block_selector ][ $section ], - $incoming_data[ $subtree ][ $block_selector ][ $section ] - ); - } - } - } + // We treat presets differently than the rest of the properties. + // In this case, we want the incoming preset leaf to replace + // the existing. } /** diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index b0ab3e8a632d43..00730c63904774 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -256,8 +256,8 @@ public function test_merge_incoming_data() { 'color' => 'red', ), array( - 'slug' => 'blue', - 'color' => 'blue', + 'slug' => 'green', + 'color' => 'green', ), ), ), @@ -585,8 +585,8 @@ function test_remove_insecure_properties_removes_non_preset_settings() { 'customGradient' => true, 'palette' => array( array( - 'slug' => 'color', - 'color' => 'color', + 'slug' => 'blue', + 'color' => 'blue', ), ), 'gradients' => array( From 5fdf7d074f30b286baa4634d9c7ba80c781e56b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Fri, 15 Jan 2021 19:03:23 +0100 Subject: [PATCH 25/65] Fix merge algorithm for leafs that have arrays as values --- lib/class-wp-theme-json.php | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index c633c155800a98..4b32de8ee870ce 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -982,9 +982,37 @@ public function merge( $incoming ) { $incoming_data = $incoming->get_raw_data(); $this->theme_json = array_replace_recursive( $this->theme_json, $incoming_data ); - // We treat presets differently than the rest of the properties. - // In this case, we want the incoming preset leaf to replace - // the existing. + // The array_replace_recursive algorithm merges at the leaf level. + // This means that when a leaf value is actually an array, + // the incoming array won't replace the existing, + // but the numeric indexes are used for replacement. + // + // These are the cases that have array values at the leaf levels. + $block_metadata = self::get_blocks_metadata(); + foreach( $block_metadata as $block_selector => $meta ) { + // color presets: palette & gradients + if( isset( $incoming_data[ 'settings' ][ $block_selector ]['color']['palette'] ) ) { + $this->theme_json[ 'settings' ][ $block_selector ]['color']['palette'] = $incoming_data[ 'settings' ][ $block_selector ]['color']['palette']; + } + if( isset( $incoming_data[ 'settings' ][ $block_selector ]['color']['gradients'] ) ) { + $this->theme_json[ 'settings' ][ $block_selector ]['color']['gradients'] = $incoming_data[ 'settings' ][ $block_selector ]['color']['gradients']; + } + // spacing: units + if( isset( $incoming_data[ 'settings' ][ $block_selector ]['spacing']['units'] ) ) { + $this->theme_json[ 'settings' ][ $block_selector ]['spacing']['units'] = $incoming_data[ 'settings' ][ $block_selector ]['spacing']['units']; + } + // typography presets: fontSizes & fontFamilies + if( isset( $incoming_data[ 'settings' ][ $block_selector ]['typography']['fontSizes'] ) ) { + $this->theme_json[ 'settings' ][ $block_selector ]['typography']['fontSizes'] = $incoming_data[ 'settings' ][ $block_selector ]['typography']['fontSizes']; + } + if( isset( $incoming_data[ 'settings' ][ $block_selector ]['typography']['fontFamilies'] ) ) { + $this->theme_json[ 'settings' ][ $block_selector ]['typography']['fontFamilies'] = $incoming_data[ 'settings' ][ $block_selector ]['typography']['fontFamilies']; + } + // custom section + if( isset( $incoming_data[ 'settings' ][ $block_selector ]['custom'] ) ) { + $this->theme_json[ 'settings' ][ $block_selector ]['custom'] = $incoming_data[ 'settings' ][ $block_selector ]['custom']; + } + } } /** From e4aca1bfee208ea356f26518f787f283b1e4c60e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Fri, 15 Jan 2021 19:04:25 +0100 Subject: [PATCH 26/65] Uncomment tests --- phpunit/class-wp-theme-json-test.php | 810 +++++++++++++-------------- 1 file changed, 405 insertions(+), 405 deletions(-) diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index 00730c63904774..acbbe531f1bcde 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -179,70 +179,70 @@ function test_get_settings() { $this->assertEqualSetsWithIndex( $expected, $result ); } - // function test_get_stylesheet() { - // // See schema at WP_Theme_JSON::SCHEMA. - // $theme_json = new WP_Theme_JSON( - // array( - // 'settings' => array( - // 'global' => array( - // 'color' => array( - // 'text' => 'value', - // 'palette' => array( - // array( - // 'slug' => 'grey', - // 'color' => 'grey', - // ), - // ), - // ), - // 'typography' => array( - // 'fontFamilies' => array( - // array( - // 'slug' => 'small', - // 'fontFamily' => '14px', - // ), - // array( - // 'slug' => 'big', - // 'fontFamily' => '41px', - // ), - // ), - // ), - // 'misc' => 'value', - // ), - // ), - // 'styles' => array( - // 'global' => array( - // 'color' => array( - // 'link' => '#111', - // 'text' => 'var:preset|color|grey', - // ), - // 'misc' => 'value', - // ), - // 'core/group' => array( - // 'spacing' => array( - // 'padding' => array( - // 'top' => '12px', - // 'bottom' => '24px', - // ), - // ), - // ), - // ), - // 'misc' => 'value', - // ) - // ); - - // $this->assertEquals( - // ':root{--wp--preset--color--grey: grey;--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}:root{--wp--style--color--link: #111;color: var(--wp--preset--color--grey);}.has-grey-color{color: grey;}.has-grey-background-color{background-color: grey;}.wp-block-group{padding-top: 12px;padding-bottom: 24px;}', - // $theme_json->get_stylesheet() - // ); - // $this->assertEquals( - // ':root{--wp--style--color--link: #111;color: var(--wp--preset--color--grey);}.has-grey-color{color: grey;}.has-grey-background-color{background-color: grey;}.wp-block-group{padding-top: 12px;padding-bottom: 24px;}', - // $theme_json->get_stylesheet( 'block_styles' ) - // ); - // $this->assertEquals( - // ':root{--wp--preset--color--grey: grey;--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}', - // $theme_json->get_stylesheet( 'css_variables' ) - // ); - // } + function test_get_stylesheet() { + // See schema at WP_Theme_JSON::SCHEMA. + $theme_json = new WP_Theme_JSON( + array( + 'settings' => array( + 'global' => array( + 'color' => array( + 'text' => 'value', + 'palette' => array( + array( + 'slug' => 'grey', + 'color' => 'grey', + ), + ), + ), + 'typography' => array( + 'fontFamilies' => array( + array( + 'slug' => 'small', + 'fontFamily' => '14px', + ), + array( + 'slug' => 'big', + 'fontFamily' => '41px', + ), + ), + ), + 'misc' => 'value', + ), + ), + 'styles' => array( + 'global' => array( + 'color' => array( + 'link' => '#111', + 'text' => 'var:preset|color|grey', + ), + 'misc' => 'value', + ), + 'core/group' => array( + 'spacing' => array( + 'padding' => array( + 'top' => '12px', + 'bottom' => '24px', + ), + ), + ), + ), + 'misc' => 'value', + ) + ); + + $this->assertEquals( + ':root{--wp--preset--color--grey: grey;--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}:root{--wp--style--color--link: #111;color: var(--wp--preset--color--grey);}.has-grey-color{color: grey;}.has-grey-background-color{background-color: grey;}.wp-block-group{padding-top: 12px;padding-bottom: 24px;}', + $theme_json->get_stylesheet() + ); + $this->assertEquals( + ':root{--wp--style--color--link: #111;color: var(--wp--preset--color--grey);}.has-grey-color{color: grey;}.has-grey-background-color{background-color: grey;}.wp-block-group{padding-top: 12px;padding-bottom: 24px;}', + $theme_json->get_stylesheet( 'block_styles' ) + ); + $this->assertEquals( + ':root{--wp--preset--color--grey: grey;--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}', + $theme_json->get_stylesheet( 'css_variables' ) + ); + } public function test_merge_incoming_data() { $initial = array( @@ -661,345 +661,345 @@ function test_remove_insecure_properties_removes_non_preset_settings() { $this->assertEqualSetsWithIndex( $expected, $result ); } - // function test_remove_insecure_properties_removes_invalid_contexts() { - // $theme_json = new WP_Theme_JSON( - // array( - // 'styles' => array( - // 'global' => array( - // 'color' => array( - // 'background' => 'green', - // 'text' => 'var:preset|color|dark-gray', - // ), - // ), - // '.my-class' => array( - // 'color' => array( - // 'background' => 'green', - // 'text' => 'var:preset|color|dark-gray', - // ), - // ), - // ), - // ), - // true - // ); - // $theme_json->remove_insecure_properties(); - // $result = $theme_json->get_raw_data(); - // $expected = array( - // 'styles' => array( - // 'global' => array( - // 'color' => array( - // 'background' => 'green', - // 'text' => 'var:preset|color|dark-gray', - // ), - // ), - // ), - // ); - // $this->assertEqualSetsWithIndex( $expected, $result ); - // } - - // function test_remove_insecure_properties_removes_invalid_properties() { - // $theme_json = new WP_Theme_JSON( - // array( - // 'styles' => array( - // 'global' => array( - // 'color' => array( - // 'gradient' => 'linear-gradient(55deg,rgba(6,147,227,1) 0%,rgb(84,177,218) 54%,rgb(155,81,224) 100%)', - // 'text' => 'var:preset|color|dark-gray', - // ), - // ), - // 'invalid' => array( - // 'background' => 'green', - // ), - // ), - // ), - // true - // ); - // $theme_json->remove_insecure_properties(); - // $result = $theme_json->get_raw_data(); - // $expected = array( - // 'styles' => array( - // 'global' => array( - // 'color' => array( - // 'gradient' => 'linear-gradient(55deg,rgba(6,147,227,1) 0%,rgb(84,177,218) 54%,rgb(155,81,224) 100%)', - // 'text' => 'var:preset|color|dark-gray', - // ), - // ), - // ), - // ); - // $this->assertEqualSetsWithIndex( $expected, $result ); - // } - - // function test_remove_insecure_properties_removes_unsafe_properties() { - // $theme_json = new WP_Theme_JSON( - // array( - // 'styles' => array( - // 'global' => array( - // 'color' => array( - // 'gradient' => 'url(\'data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxMCcgaGVpZ2h0PScxMCc+PHNjcmlwdD5hbGVydCgnb2snKTwvc2NyaXB0PjxsaW5lYXJHcmFkaWVudCBpZD0nZ3JhZGllbnQnPjxzdG9wIG9mZnNldD0nMTAlJyBzdG9wLWNvbG9yPScjRjAwJy8+PHN0b3Agb2Zmc2V0PSc5MCUnIHN0b3AtY29sb3I9JyNmY2MnLz4gPC9saW5lYXJHcmFkaWVudD48cmVjdCBmaWxsPSd1cmwoI2dyYWRpZW50KScgeD0nMCcgeT0nMCcgd2lkdGg9JzEwMCUnIGhlaWdodD0nMTAwJScvPjwvc3ZnPg==\')', - // 'text' => 'var:preset|color|dark-gray', - // ), - // ), - // 'invalid' => array( - // 'background' => 'green', - // ), - // ), - // ), - // true - // ); - // $theme_json->remove_insecure_properties(); - // $result = $theme_json->get_raw_data(); - // $expected = array( - // 'styles' => array( - // 'global' => array( - // 'color' => array( - // 'text' => 'var:preset|color|dark-gray', - // ), - // ), - // ), - // ); - // $this->assertEqualSetsWithIndex( $expected, $result ); - // } - - // function test_remove_insecure_properties_removes_properties_when_not_allowed_in_a_context() { - // $theme_json = new WP_Theme_JSON( - // array( - // 'styles' => array( - // 'global' => array( - // 'color' => array( - // 'text' => 'var:preset|color|dark-gray', - // ), - // 'spacing' => array( - // 'padding' => array( - // 'top' => '1px', - // 'right' => '1px', - // 'bottom' => '1px', - // 'left' => '1px', - // ), - // ), - // ), - // 'invalid' => array( - // 'background' => 'green', - // ), - // 'core/group' => array( - // 'spacing' => array( - // 'padding' => array( - // 'top' => '1px', - // 'right' => '1px', - // 'bottom' => '1px', - // 'left' => '1px', - // ), - // ), - // ), - // ), - // ), - // true - // ); - // $theme_json->remove_insecure_properties(); - // $result = $theme_json->get_raw_data(); - // $expected = array( - // 'styles' => array( - // 'global' => array( - // 'color' => array( - // 'text' => 'var:preset|color|dark-gray', - // ), - // ), - // 'core/group' => array( - // 'spacing' => array( - // 'padding' => array( - // 'top' => '1px', - // 'right' => '1px', - // 'bottom' => '1px', - // 'left' => '1px', - // ), - // ), - // ), - // ), - // ); - // $this->assertEqualSetsWithIndex( $expected, $result ); - // } - - // function test_remove_insecure_properties_removes_unsafe_sub_properties() { - // $theme_json = new WP_Theme_JSON( - // array( - // 'styles' => array( - // 'core/group' => array( - // 'spacing' => array( - // 'padding' => array( - // 'top' => '1px', - // 'right' => '1px', - // 'bottom' => 'var(--unsafe-var-y)', - // 'left' => '1px', - // ), - // ), - // ), - // ), - // ), - // true - // ); - // $theme_json->remove_insecure_properties(); - // $result = $theme_json->get_raw_data(); - // $expected = array( - // 'styles' => array( - // 'core/group' => array( - // 'spacing' => array( - // 'padding' => array( - // 'top' => '1px', - // 'right' => '1px', - // 'left' => '1px', - // ), - // ), - // ), - // ), - // ); - // $this->assertEqualSetsWithIndex( $expected, $result ); - // } - - // function test_remove_insecure_properties_removes_non_preset_settings() { - // $theme_json = new WP_Theme_JSON( - // array( - // 'settings' => array( - // 'global' => array( - // 'color' => array( - // 'custom' => true, - // 'palette' => array( - // array( - // 'name' => 'Red', - // 'slug' => 'red', - // 'color' => '#ff0000', - // ), - // array( - // 'name' => 'Green', - // 'slug' => 'green', - // 'color' => '#00ff00', - // ), - // array( - // 'name' => 'Blue', - // 'slug' => 'blue', - // 'color' => '#0000ff', - // ), - // ), - // ), - // 'spacing' => array( - // 'customPadding' => false, - // ), - // ), - // ), - // ), - // true - // ); - // $theme_json->remove_insecure_properties(); - // $result = $theme_json->get_raw_data(); - // $expected = array( - // 'settings' => array( - // 'global' => array( - // 'color' => array( - // 'palette' => array( - // array( - // 'name' => 'Red', - // 'slug' => 'red', - // 'color' => '#ff0000', - // ), - // array( - // 'name' => 'Green', - // 'slug' => 'green', - // 'color' => '#00ff00', - // ), - // array( - // 'name' => 'Blue', - // 'slug' => 'blue', - // 'color' => '#0000ff', - // ), - // ), - // ), - // ), - // ), - // ); - // $this->assertEqualSetsWithIndex( $expected, $result ); - // } - - // function test_remove_insecure_properties_removes_unsafe_preset_settings() { - // $theme_json = new WP_Theme_JSON( - // array( - // 'settings' => array( - // 'global' => array( - // 'color' => array( - // 'palette' => array( - // array( - // 'name' => 'Red/>ok', - // 'slug' => 'red', - // 'color' => '#ff0000', - // ), - // array( - // 'name' => 'Green', - // 'slug' => 'a" attr', - // 'color' => '#00ff00', - // ), - // array( - // 'name' => 'Blue', - // 'slug' => 'blue', - // 'color' => 'var(--custom-v1)', - // ), - // array( - // 'name' => 'Pink', - // 'slug' => 'pink', - // 'color' => '#FFC0CB', - // ), - // ), - // ), - // 'typography' => array( - // 'fontFamilies' => array( - // array( - // 'name' => 'Helvetica Arial/>test', - // 'slug' => 'helvetica-arial', - // 'fontFamily' => 'Helvetica Neue, Helvetica, Arial, sans-serif', - // ), - // array( - // 'name' => 'Geneva', - // 'slug' => 'geneva#asa', - // 'fontFamily' => 'Geneva, Tahoma, Verdana, sans-serif', - // ), - // array( - // 'name' => 'Cambria', - // 'slug' => 'cambria', - // 'fontFamily' => 'Cambria, Georgia, serif', - // ), - // array( - // 'name' => 'Helvetica Arial', - // 'slug' => 'helvetica-arial', - // 'fontFamily' => 'var(--custom-var-1)', - // ), - // ), - // ), - // ), - // ), - // ), - // true - // ); - // $theme_json->remove_insecure_properties(); - // $result = $theme_json->get_raw_data(); - // $expected = array( - // 'settings' => array( - // 'global' => array( - // 'color' => array( - // 'palette' => array( - // array( - // 'name' => 'Pink', - // 'slug' => 'pink', - // 'color' => '#FFC0CB', - // ), - // ), - // ), - // 'typography' => array( - // 'fontFamilies' => array( - // array( - // 'name' => 'Cambria', - // 'slug' => 'cambria', - // 'fontFamily' => 'Cambria, Georgia, serif', - // ), - // ), - // ), - // ), - // ), - // ); - // $this->assertEqualSetsWithIndex( $expected, $result ); - // } + function test_remove_insecure_properties_removes_invalid_contexts() { + $theme_json = new WP_Theme_JSON( + array( + 'styles' => array( + 'global' => array( + 'color' => array( + 'background' => 'green', + 'text' => 'var:preset|color|dark-gray', + ), + ), + '.my-class' => array( + 'color' => array( + 'background' => 'green', + 'text' => 'var:preset|color|dark-gray', + ), + ), + ), + ), + true + ); + $theme_json->remove_insecure_properties(); + $result = $theme_json->get_raw_data(); + $expected = array( + 'styles' => array( + 'global' => array( + 'color' => array( + 'background' => 'green', + 'text' => 'var:preset|color|dark-gray', + ), + ), + ), + ); + $this->assertEqualSetsWithIndex( $expected, $result ); + } + + function test_remove_insecure_properties_removes_invalid_properties() { + $theme_json = new WP_Theme_JSON( + array( + 'styles' => array( + 'global' => array( + 'color' => array( + 'gradient' => 'linear-gradient(55deg,rgba(6,147,227,1) 0%,rgb(84,177,218) 54%,rgb(155,81,224) 100%)', + 'text' => 'var:preset|color|dark-gray', + ), + ), + 'invalid' => array( + 'background' => 'green', + ), + ), + ), + true + ); + $theme_json->remove_insecure_properties(); + $result = $theme_json->get_raw_data(); + $expected = array( + 'styles' => array( + 'global' => array( + 'color' => array( + 'gradient' => 'linear-gradient(55deg,rgba(6,147,227,1) 0%,rgb(84,177,218) 54%,rgb(155,81,224) 100%)', + 'text' => 'var:preset|color|dark-gray', + ), + ), + ), + ); + $this->assertEqualSetsWithIndex( $expected, $result ); + } + + function test_remove_insecure_properties_removes_unsafe_properties() { + $theme_json = new WP_Theme_JSON( + array( + 'styles' => array( + 'global' => array( + 'color' => array( + 'gradient' => 'url(\'data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxMCcgaGVpZ2h0PScxMCc+PHNjcmlwdD5hbGVydCgnb2snKTwvc2NyaXB0PjxsaW5lYXJHcmFkaWVudCBpZD0nZ3JhZGllbnQnPjxzdG9wIG9mZnNldD0nMTAlJyBzdG9wLWNvbG9yPScjRjAwJy8+PHN0b3Agb2Zmc2V0PSc5MCUnIHN0b3AtY29sb3I9JyNmY2MnLz4gPC9saW5lYXJHcmFkaWVudD48cmVjdCBmaWxsPSd1cmwoI2dyYWRpZW50KScgeD0nMCcgeT0nMCcgd2lkdGg9JzEwMCUnIGhlaWdodD0nMTAwJScvPjwvc3ZnPg==\')', + 'text' => 'var:preset|color|dark-gray', + ), + ), + 'invalid' => array( + 'background' => 'green', + ), + ), + ), + true + ); + $theme_json->remove_insecure_properties(); + $result = $theme_json->get_raw_data(); + $expected = array( + 'styles' => array( + 'global' => array( + 'color' => array( + 'text' => 'var:preset|color|dark-gray', + ), + ), + ), + ); + $this->assertEqualSetsWithIndex( $expected, $result ); + } + + function test_remove_insecure_properties_removes_properties_when_not_allowed_in_a_context() { + $theme_json = new WP_Theme_JSON( + array( + 'styles' => array( + 'global' => array( + 'color' => array( + 'text' => 'var:preset|color|dark-gray', + ), + 'spacing' => array( + 'padding' => array( + 'top' => '1px', + 'right' => '1px', + 'bottom' => '1px', + 'left' => '1px', + ), + ), + ), + 'invalid' => array( + 'background' => 'green', + ), + 'core/group' => array( + 'spacing' => array( + 'padding' => array( + 'top' => '1px', + 'right' => '1px', + 'bottom' => '1px', + 'left' => '1px', + ), + ), + ), + ), + ), + true + ); + $theme_json->remove_insecure_properties(); + $result = $theme_json->get_raw_data(); + $expected = array( + 'styles' => array( + 'global' => array( + 'color' => array( + 'text' => 'var:preset|color|dark-gray', + ), + ), + 'core/group' => array( + 'spacing' => array( + 'padding' => array( + 'top' => '1px', + 'right' => '1px', + 'bottom' => '1px', + 'left' => '1px', + ), + ), + ), + ), + ); + $this->assertEqualSetsWithIndex( $expected, $result ); + } + + function test_remove_insecure_properties_removes_unsafe_sub_properties() { + $theme_json = new WP_Theme_JSON( + array( + 'styles' => array( + 'core/group' => array( + 'spacing' => array( + 'padding' => array( + 'top' => '1px', + 'right' => '1px', + 'bottom' => 'var(--unsafe-var-y)', + 'left' => '1px', + ), + ), + ), + ), + ), + true + ); + $theme_json->remove_insecure_properties(); + $result = $theme_json->get_raw_data(); + $expected = array( + 'styles' => array( + 'core/group' => array( + 'spacing' => array( + 'padding' => array( + 'top' => '1px', + 'right' => '1px', + 'left' => '1px', + ), + ), + ), + ), + ); + $this->assertEqualSetsWithIndex( $expected, $result ); + } + + function test_remove_insecure_properties_removes_non_preset_settings() { + $theme_json = new WP_Theme_JSON( + array( + 'settings' => array( + 'global' => array( + 'color' => array( + 'custom' => true, + 'palette' => array( + array( + 'name' => 'Red', + 'slug' => 'red', + 'color' => '#ff0000', + ), + array( + 'name' => 'Green', + 'slug' => 'green', + 'color' => '#00ff00', + ), + array( + 'name' => 'Blue', + 'slug' => 'blue', + 'color' => '#0000ff', + ), + ), + ), + 'spacing' => array( + 'customPadding' => false, + ), + ), + ), + ), + true + ); + $theme_json->remove_insecure_properties(); + $result = $theme_json->get_raw_data(); + $expected = array( + 'settings' => array( + 'global' => array( + 'color' => array( + 'palette' => array( + array( + 'name' => 'Red', + 'slug' => 'red', + 'color' => '#ff0000', + ), + array( + 'name' => 'Green', + 'slug' => 'green', + 'color' => '#00ff00', + ), + array( + 'name' => 'Blue', + 'slug' => 'blue', + 'color' => '#0000ff', + ), + ), + ), + ), + ), + ); + $this->assertEqualSetsWithIndex( $expected, $result ); + } + + function test_remove_insecure_properties_removes_unsafe_preset_settings() { + $theme_json = new WP_Theme_JSON( + array( + 'settings' => array( + 'global' => array( + 'color' => array( + 'palette' => array( + array( + 'name' => 'Red/>ok', + 'slug' => 'red', + 'color' => '#ff0000', + ), + array( + 'name' => 'Green', + 'slug' => 'a" attr', + 'color' => '#00ff00', + ), + array( + 'name' => 'Blue', + 'slug' => 'blue', + 'color' => 'var(--custom-v1)', + ), + array( + 'name' => 'Pink', + 'slug' => 'pink', + 'color' => '#FFC0CB', + ), + ), + ), + 'typography' => array( + 'fontFamilies' => array( + array( + 'name' => 'Helvetica Arial/>test', + 'slug' => 'helvetica-arial', + 'fontFamily' => 'Helvetica Neue, Helvetica, Arial, sans-serif', + ), + array( + 'name' => 'Geneva', + 'slug' => 'geneva#asa', + 'fontFamily' => 'Geneva, Tahoma, Verdana, sans-serif', + ), + array( + 'name' => 'Cambria', + 'slug' => 'cambria', + 'fontFamily' => 'Cambria, Georgia, serif', + ), + array( + 'name' => 'Helvetica Arial', + 'slug' => 'helvetica-arial', + 'fontFamily' => 'var(--custom-var-1)', + ), + ), + ), + ), + ), + ), + true + ); + $theme_json->remove_insecure_properties(); + $result = $theme_json->get_raw_data(); + $expected = array( + 'settings' => array( + 'global' => array( + 'color' => array( + 'palette' => array( + array( + 'name' => 'Pink', + 'slug' => 'pink', + 'color' => '#FFC0CB', + ), + ), + ), + 'typography' => array( + 'fontFamilies' => array( + array( + 'name' => 'Cambria', + 'slug' => 'cambria', + 'fontFamily' => 'Cambria, Georgia, serif', + ), + ), + ), + ), + ), + ); + $this->assertEqualSetsWithIndex( $expected, $result ); + } } From 50d7c0a3641ca882cd7efcb59f40cae56df66cec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Mon, 18 Jan 2021 18:04:05 +0100 Subject: [PATCH 27/65] Fix get_stylesheet( css_variables ) --- lib/class-wp-theme-json.php | 31 +- phpunit/class-wp-theme-json-test.php | 698 +++++++++++++-------------- 2 files changed, 366 insertions(+), 363 deletions(-) diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index 4b32de8ee870ce..7743f191e8b218 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -181,6 +181,7 @@ class WP_Theme_JSON { */ const PRESETS_METADATA = array( array( + 'path_settings' => array( 'color', 'palette' ), 'path' => array( 'settings', 'color', 'palette' ), 'value_key' => 'color', 'css_var_infix' => 'color', @@ -196,6 +197,7 @@ class WP_Theme_JSON { ), ), array( + 'path_settings' => array( 'color', 'gradients' ), 'path' => array( 'settings', 'color', 'gradients' ), 'value_key' => 'gradient', 'css_var_infix' => 'gradient', @@ -207,6 +209,7 @@ class WP_Theme_JSON { ), ), array( + 'path_settings' => array( 'typography', 'fontSizes' ), 'path' => array( 'settings', 'typography', 'fontSizes' ), 'value_key' => 'size', 'css_var_infix' => 'font-size', @@ -218,7 +221,7 @@ class WP_Theme_JSON { ), ), array( - 'path' => array( 'settings', 'typography', 'fontFamilies' ), + 'path_settings' => array( 'typography', 'fontFamilies' ), 'value_key' => 'fontFamily', 'css_var_infix' => 'font-family', 'classes' => array(), @@ -742,7 +745,7 @@ private static function compute_preset_classes( &$stylesheet, $context, $selecto } /** - * Given a context, it extracts the CSS Custom Properties + * Given the block settings, it extracts the CSS Custom Properties * for the presets and adds them to the $declarations array * following the format: * @@ -756,11 +759,11 @@ private static function compute_preset_classes( &$stylesheet, $context, $selecto * Note that this modifies the $declarations in place. * * @param array $declarations Holds the existing declarations. - * @param array $context Input context to process. + * @param array $settings Settings to process. */ - private static function compute_preset_vars( &$declarations, $context ) { + private static function compute_preset_vars( &$declarations, $settings ) { foreach ( self::PRESETS_METADATA as $preset ) { - $values = gutenberg_experimental_get( $context, $preset['path'], array() ); + $values = gutenberg_experimental_get( $settings, $preset['path_settings'], array() ); foreach ( $values as $value ) { $declarations[] = array( 'name' => '--wp--preset--' . $preset['css_var_infix'] . '--' . $value['slug'], @@ -771,7 +774,7 @@ private static function compute_preset_vars( &$declarations, $context ) { } /** - * Given a context, it extracts the CSS Custom Properties + * Given an array of settings, it extracts the CSS Custom Properties * for the custom values and adds them to the $declarations * array following the format: * @@ -785,10 +788,10 @@ private static function compute_preset_vars( &$declarations, $context ) { * Note that this modifies the $declarations in place. * * @param array $declarations Holds the existing declarations. - * @param array $context Input context to process. + * @param array $settings Settings to process. */ - private static function compute_theme_vars( &$declarations, $context ) { - $custom_values = gutenberg_experimental_get( $context, array( 'settings', 'custom' ) ); + private static function compute_theme_vars( &$declarations, $settings ) { + $custom_values = gutenberg_experimental_get( $context, array( 'custom' ) ); $css_vars = self::flatten_tree( $custom_values ); foreach ( $css_vars as $key => $value ) { $declarations[] = array( @@ -856,15 +859,15 @@ function ( $carry, $element ) { private function get_css_variables() { $stylesheet = ''; $metadata = $this->get_blocks_metadata(); - foreach ( $this->theme_json as $context_name => $context ) { - if ( empty( $metadata[ $context_name ]['selector'] ) ) { + foreach ( $this->theme_json['settings'] as $block_selector => $settings ) { + if ( empty( $metadata[ $block_selector ]['selector'] ) ) { continue; } - $selector = $metadata[ $context_name ]['selector']; + $selector = $metadata[ $block_selector ]['selector']; $declarations = array(); - self::compute_preset_vars( $declarations, $context ); - self::compute_theme_vars( $declarations, $context ); + self::compute_preset_vars( $declarations, $settings ); + self::compute_theme_vars( $declarations, $settings ); // Attach the ruleset for style and custom properties. $stylesheet .= self::to_ruleset( $selector, $declarations ); diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index acbbe531f1bcde..cef3cbbb00913c 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -230,14 +230,14 @@ function test_get_stylesheet() { ) ); - $this->assertEquals( - ':root{--wp--preset--color--grey: grey;--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}:root{--wp--style--color--link: #111;color: var(--wp--preset--color--grey);}.has-grey-color{color: grey;}.has-grey-background-color{background-color: grey;}.wp-block-group{padding-top: 12px;padding-bottom: 24px;}', - $theme_json->get_stylesheet() - ); - $this->assertEquals( - ':root{--wp--style--color--link: #111;color: var(--wp--preset--color--grey);}.has-grey-color{color: grey;}.has-grey-background-color{background-color: grey;}.wp-block-group{padding-top: 12px;padding-bottom: 24px;}', - $theme_json->get_stylesheet( 'block_styles' ) - ); + // $this->assertEquals( + // ':root{--wp--preset--color--grey: grey;--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}:root{--wp--style--color--link: #111;color: var(--wp--preset--color--grey);}.has-grey-color{color: grey;}.has-grey-background-color{background-color: grey;}.wp-block-group{padding-top: 12px;padding-bottom: 24px;}', + // $theme_json->get_stylesheet() + // ); + // $this->assertEquals( + // ':root{--wp--style--color--link: #111;color: var(--wp--preset--color--grey);}.has-grey-color{color: grey;}.has-grey-background-color{background-color: grey;}.wp-block-group{padding-top: 12px;padding-bottom: 24px;}', + // $theme_json->get_stylesheet( 'block_styles' ) + // ); $this->assertEquals( ':root{--wp--preset--color--grey: grey;--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}', $theme_json->get_stylesheet( 'css_variables' ) @@ -661,345 +661,345 @@ function test_remove_insecure_properties_removes_non_preset_settings() { $this->assertEqualSetsWithIndex( $expected, $result ); } - function test_remove_insecure_properties_removes_invalid_contexts() { - $theme_json = new WP_Theme_JSON( - array( - 'styles' => array( - 'global' => array( - 'color' => array( - 'background' => 'green', - 'text' => 'var:preset|color|dark-gray', - ), - ), - '.my-class' => array( - 'color' => array( - 'background' => 'green', - 'text' => 'var:preset|color|dark-gray', - ), - ), - ), - ), - true - ); - $theme_json->remove_insecure_properties(); - $result = $theme_json->get_raw_data(); - $expected = array( - 'styles' => array( - 'global' => array( - 'color' => array( - 'background' => 'green', - 'text' => 'var:preset|color|dark-gray', - ), - ), - ), - ); - $this->assertEqualSetsWithIndex( $expected, $result ); - } - - function test_remove_insecure_properties_removes_invalid_properties() { - $theme_json = new WP_Theme_JSON( - array( - 'styles' => array( - 'global' => array( - 'color' => array( - 'gradient' => 'linear-gradient(55deg,rgba(6,147,227,1) 0%,rgb(84,177,218) 54%,rgb(155,81,224) 100%)', - 'text' => 'var:preset|color|dark-gray', - ), - ), - 'invalid' => array( - 'background' => 'green', - ), - ), - ), - true - ); - $theme_json->remove_insecure_properties(); - $result = $theme_json->get_raw_data(); - $expected = array( - 'styles' => array( - 'global' => array( - 'color' => array( - 'gradient' => 'linear-gradient(55deg,rgba(6,147,227,1) 0%,rgb(84,177,218) 54%,rgb(155,81,224) 100%)', - 'text' => 'var:preset|color|dark-gray', - ), - ), - ), - ); - $this->assertEqualSetsWithIndex( $expected, $result ); - } - - function test_remove_insecure_properties_removes_unsafe_properties() { - $theme_json = new WP_Theme_JSON( - array( - 'styles' => array( - 'global' => array( - 'color' => array( - 'gradient' => 'url(\'data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxMCcgaGVpZ2h0PScxMCc+PHNjcmlwdD5hbGVydCgnb2snKTwvc2NyaXB0PjxsaW5lYXJHcmFkaWVudCBpZD0nZ3JhZGllbnQnPjxzdG9wIG9mZnNldD0nMTAlJyBzdG9wLWNvbG9yPScjRjAwJy8+PHN0b3Agb2Zmc2V0PSc5MCUnIHN0b3AtY29sb3I9JyNmY2MnLz4gPC9saW5lYXJHcmFkaWVudD48cmVjdCBmaWxsPSd1cmwoI2dyYWRpZW50KScgeD0nMCcgeT0nMCcgd2lkdGg9JzEwMCUnIGhlaWdodD0nMTAwJScvPjwvc3ZnPg==\')', - 'text' => 'var:preset|color|dark-gray', - ), - ), - 'invalid' => array( - 'background' => 'green', - ), - ), - ), - true - ); - $theme_json->remove_insecure_properties(); - $result = $theme_json->get_raw_data(); - $expected = array( - 'styles' => array( - 'global' => array( - 'color' => array( - 'text' => 'var:preset|color|dark-gray', - ), - ), - ), - ); - $this->assertEqualSetsWithIndex( $expected, $result ); - } - - function test_remove_insecure_properties_removes_properties_when_not_allowed_in_a_context() { - $theme_json = new WP_Theme_JSON( - array( - 'styles' => array( - 'global' => array( - 'color' => array( - 'text' => 'var:preset|color|dark-gray', - ), - 'spacing' => array( - 'padding' => array( - 'top' => '1px', - 'right' => '1px', - 'bottom' => '1px', - 'left' => '1px', - ), - ), - ), - 'invalid' => array( - 'background' => 'green', - ), - 'core/group' => array( - 'spacing' => array( - 'padding' => array( - 'top' => '1px', - 'right' => '1px', - 'bottom' => '1px', - 'left' => '1px', - ), - ), - ), - ), - ), - true - ); - $theme_json->remove_insecure_properties(); - $result = $theme_json->get_raw_data(); - $expected = array( - 'styles' => array( - 'global' => array( - 'color' => array( - 'text' => 'var:preset|color|dark-gray', - ), - ), - 'core/group' => array( - 'spacing' => array( - 'padding' => array( - 'top' => '1px', - 'right' => '1px', - 'bottom' => '1px', - 'left' => '1px', - ), - ), - ), - ), - ); - $this->assertEqualSetsWithIndex( $expected, $result ); - } - - function test_remove_insecure_properties_removes_unsafe_sub_properties() { - $theme_json = new WP_Theme_JSON( - array( - 'styles' => array( - 'core/group' => array( - 'spacing' => array( - 'padding' => array( - 'top' => '1px', - 'right' => '1px', - 'bottom' => 'var(--unsafe-var-y)', - 'left' => '1px', - ), - ), - ), - ), - ), - true - ); - $theme_json->remove_insecure_properties(); - $result = $theme_json->get_raw_data(); - $expected = array( - 'styles' => array( - 'core/group' => array( - 'spacing' => array( - 'padding' => array( - 'top' => '1px', - 'right' => '1px', - 'left' => '1px', - ), - ), - ), - ), - ); - $this->assertEqualSetsWithIndex( $expected, $result ); - } - - function test_remove_insecure_properties_removes_non_preset_settings() { - $theme_json = new WP_Theme_JSON( - array( - 'settings' => array( - 'global' => array( - 'color' => array( - 'custom' => true, - 'palette' => array( - array( - 'name' => 'Red', - 'slug' => 'red', - 'color' => '#ff0000', - ), - array( - 'name' => 'Green', - 'slug' => 'green', - 'color' => '#00ff00', - ), - array( - 'name' => 'Blue', - 'slug' => 'blue', - 'color' => '#0000ff', - ), - ), - ), - 'spacing' => array( - 'customPadding' => false, - ), - ), - ), - ), - true - ); - $theme_json->remove_insecure_properties(); - $result = $theme_json->get_raw_data(); - $expected = array( - 'settings' => array( - 'global' => array( - 'color' => array( - 'palette' => array( - array( - 'name' => 'Red', - 'slug' => 'red', - 'color' => '#ff0000', - ), - array( - 'name' => 'Green', - 'slug' => 'green', - 'color' => '#00ff00', - ), - array( - 'name' => 'Blue', - 'slug' => 'blue', - 'color' => '#0000ff', - ), - ), - ), - ), - ), - ); - $this->assertEqualSetsWithIndex( $expected, $result ); - } - - function test_remove_insecure_properties_removes_unsafe_preset_settings() { - $theme_json = new WP_Theme_JSON( - array( - 'settings' => array( - 'global' => array( - 'color' => array( - 'palette' => array( - array( - 'name' => 'Red/>ok', - 'slug' => 'red', - 'color' => '#ff0000', - ), - array( - 'name' => 'Green', - 'slug' => 'a" attr', - 'color' => '#00ff00', - ), - array( - 'name' => 'Blue', - 'slug' => 'blue', - 'color' => 'var(--custom-v1)', - ), - array( - 'name' => 'Pink', - 'slug' => 'pink', - 'color' => '#FFC0CB', - ), - ), - ), - 'typography' => array( - 'fontFamilies' => array( - array( - 'name' => 'Helvetica Arial/>test', - 'slug' => 'helvetica-arial', - 'fontFamily' => 'Helvetica Neue, Helvetica, Arial, sans-serif', - ), - array( - 'name' => 'Geneva', - 'slug' => 'geneva#asa', - 'fontFamily' => 'Geneva, Tahoma, Verdana, sans-serif', - ), - array( - 'name' => 'Cambria', - 'slug' => 'cambria', - 'fontFamily' => 'Cambria, Georgia, serif', - ), - array( - 'name' => 'Helvetica Arial', - 'slug' => 'helvetica-arial', - 'fontFamily' => 'var(--custom-var-1)', - ), - ), - ), - ), - ), - ), - true - ); - $theme_json->remove_insecure_properties(); - $result = $theme_json->get_raw_data(); - $expected = array( - 'settings' => array( - 'global' => array( - 'color' => array( - 'palette' => array( - array( - 'name' => 'Pink', - 'slug' => 'pink', - 'color' => '#FFC0CB', - ), - ), - ), - 'typography' => array( - 'fontFamilies' => array( - array( - 'name' => 'Cambria', - 'slug' => 'cambria', - 'fontFamily' => 'Cambria, Georgia, serif', - ), - ), - ), - ), - ), - ); - $this->assertEqualSetsWithIndex( $expected, $result ); - } + // function test_remove_insecure_properties_removes_invalid_contexts() { + // $theme_json = new WP_Theme_JSON( + // array( + // 'styles' => array( + // 'global' => array( + // 'color' => array( + // 'background' => 'green', + // 'text' => 'var:preset|color|dark-gray', + // ), + // ), + // '.my-class' => array( + // 'color' => array( + // 'background' => 'green', + // 'text' => 'var:preset|color|dark-gray', + // ), + // ), + // ), + // ), + // true + // ); + // $theme_json->remove_insecure_properties(); + // $result = $theme_json->get_raw_data(); + // $expected = array( + // 'styles' => array( + // 'global' => array( + // 'color' => array( + // 'background' => 'green', + // 'text' => 'var:preset|color|dark-gray', + // ), + // ), + // ), + // ); + // $this->assertEqualSetsWithIndex( $expected, $result ); + // } + + // function test_remove_insecure_properties_removes_invalid_properties() { + // $theme_json = new WP_Theme_JSON( + // array( + // 'styles' => array( + // 'global' => array( + // 'color' => array( + // 'gradient' => 'linear-gradient(55deg,rgba(6,147,227,1) 0%,rgb(84,177,218) 54%,rgb(155,81,224) 100%)', + // 'text' => 'var:preset|color|dark-gray', + // ), + // ), + // 'invalid' => array( + // 'background' => 'green', + // ), + // ), + // ), + // true + // ); + // $theme_json->remove_insecure_properties(); + // $result = $theme_json->get_raw_data(); + // $expected = array( + // 'styles' => array( + // 'global' => array( + // 'color' => array( + // 'gradient' => 'linear-gradient(55deg,rgba(6,147,227,1) 0%,rgb(84,177,218) 54%,rgb(155,81,224) 100%)', + // 'text' => 'var:preset|color|dark-gray', + // ), + // ), + // ), + // ); + // $this->assertEqualSetsWithIndex( $expected, $result ); + // } + + // function test_remove_insecure_properties_removes_unsafe_properties() { + // $theme_json = new WP_Theme_JSON( + // array( + // 'styles' => array( + // 'global' => array( + // 'color' => array( + // 'gradient' => 'url(\'data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxMCcgaGVpZ2h0PScxMCc+PHNjcmlwdD5hbGVydCgnb2snKTwvc2NyaXB0PjxsaW5lYXJHcmFkaWVudCBpZD0nZ3JhZGllbnQnPjxzdG9wIG9mZnNldD0nMTAlJyBzdG9wLWNvbG9yPScjRjAwJy8+PHN0b3Agb2Zmc2V0PSc5MCUnIHN0b3AtY29sb3I9JyNmY2MnLz4gPC9saW5lYXJHcmFkaWVudD48cmVjdCBmaWxsPSd1cmwoI2dyYWRpZW50KScgeD0nMCcgeT0nMCcgd2lkdGg9JzEwMCUnIGhlaWdodD0nMTAwJScvPjwvc3ZnPg==\')', + // 'text' => 'var:preset|color|dark-gray', + // ), + // ), + // 'invalid' => array( + // 'background' => 'green', + // ), + // ), + // ), + // true + // ); + // $theme_json->remove_insecure_properties(); + // $result = $theme_json->get_raw_data(); + // $expected = array( + // 'styles' => array( + // 'global' => array( + // 'color' => array( + // 'text' => 'var:preset|color|dark-gray', + // ), + // ), + // ), + // ); + // $this->assertEqualSetsWithIndex( $expected, $result ); + // } + + // function test_remove_insecure_properties_removes_properties_when_not_allowed_in_a_context() { + // $theme_json = new WP_Theme_JSON( + // array( + // 'styles' => array( + // 'global' => array( + // 'color' => array( + // 'text' => 'var:preset|color|dark-gray', + // ), + // 'spacing' => array( + // 'padding' => array( + // 'top' => '1px', + // 'right' => '1px', + // 'bottom' => '1px', + // 'left' => '1px', + // ), + // ), + // ), + // 'invalid' => array( + // 'background' => 'green', + // ), + // 'core/group' => array( + // 'spacing' => array( + // 'padding' => array( + // 'top' => '1px', + // 'right' => '1px', + // 'bottom' => '1px', + // 'left' => '1px', + // ), + // ), + // ), + // ), + // ), + // true + // ); + // $theme_json->remove_insecure_properties(); + // $result = $theme_json->get_raw_data(); + // $expected = array( + // 'styles' => array( + // 'global' => array( + // 'color' => array( + // 'text' => 'var:preset|color|dark-gray', + // ), + // ), + // 'core/group' => array( + // 'spacing' => array( + // 'padding' => array( + // 'top' => '1px', + // 'right' => '1px', + // 'bottom' => '1px', + // 'left' => '1px', + // ), + // ), + // ), + // ), + // ); + // $this->assertEqualSetsWithIndex( $expected, $result ); + // } + + // function test_remove_insecure_properties_removes_unsafe_sub_properties() { + // $theme_json = new WP_Theme_JSON( + // array( + // 'styles' => array( + // 'core/group' => array( + // 'spacing' => array( + // 'padding' => array( + // 'top' => '1px', + // 'right' => '1px', + // 'bottom' => 'var(--unsafe-var-y)', + // 'left' => '1px', + // ), + // ), + // ), + // ), + // ), + // true + // ); + // $theme_json->remove_insecure_properties(); + // $result = $theme_json->get_raw_data(); + // $expected = array( + // 'styles' => array( + // 'core/group' => array( + // 'spacing' => array( + // 'padding' => array( + // 'top' => '1px', + // 'right' => '1px', + // 'left' => '1px', + // ), + // ), + // ), + // ), + // ); + // $this->assertEqualSetsWithIndex( $expected, $result ); + // } + + // function test_remove_insecure_properties_removes_non_preset_settings() { + // $theme_json = new WP_Theme_JSON( + // array( + // 'settings' => array( + // 'global' => array( + // 'color' => array( + // 'custom' => true, + // 'palette' => array( + // array( + // 'name' => 'Red', + // 'slug' => 'red', + // 'color' => '#ff0000', + // ), + // array( + // 'name' => 'Green', + // 'slug' => 'green', + // 'color' => '#00ff00', + // ), + // array( + // 'name' => 'Blue', + // 'slug' => 'blue', + // 'color' => '#0000ff', + // ), + // ), + // ), + // 'spacing' => array( + // 'customPadding' => false, + // ), + // ), + // ), + // ), + // true + // ); + // $theme_json->remove_insecure_properties(); + // $result = $theme_json->get_raw_data(); + // $expected = array( + // 'settings' => array( + // 'global' => array( + // 'color' => array( + // 'palette' => array( + // array( + // 'name' => 'Red', + // 'slug' => 'red', + // 'color' => '#ff0000', + // ), + // array( + // 'name' => 'Green', + // 'slug' => 'green', + // 'color' => '#00ff00', + // ), + // array( + // 'name' => 'Blue', + // 'slug' => 'blue', + // 'color' => '#0000ff', + // ), + // ), + // ), + // ), + // ), + // ); + // $this->assertEqualSetsWithIndex( $expected, $result ); + // } + + // function test_remove_insecure_properties_removes_unsafe_preset_settings() { + // $theme_json = new WP_Theme_JSON( + // array( + // 'settings' => array( + // 'global' => array( + // 'color' => array( + // 'palette' => array( + // array( + // 'name' => 'Red/>ok', + // 'slug' => 'red', + // 'color' => '#ff0000', + // ), + // array( + // 'name' => 'Green', + // 'slug' => 'a" attr', + // 'color' => '#00ff00', + // ), + // array( + // 'name' => 'Blue', + // 'slug' => 'blue', + // 'color' => 'var(--custom-v1)', + // ), + // array( + // 'name' => 'Pink', + // 'slug' => 'pink', + // 'color' => '#FFC0CB', + // ), + // ), + // ), + // 'typography' => array( + // 'fontFamilies' => array( + // array( + // 'name' => 'Helvetica Arial/>test', + // 'slug' => 'helvetica-arial', + // 'fontFamily' => 'Helvetica Neue, Helvetica, Arial, sans-serif', + // ), + // array( + // 'name' => 'Geneva', + // 'slug' => 'geneva#asa', + // 'fontFamily' => 'Geneva, Tahoma, Verdana, sans-serif', + // ), + // array( + // 'name' => 'Cambria', + // 'slug' => 'cambria', + // 'fontFamily' => 'Cambria, Georgia, serif', + // ), + // array( + // 'name' => 'Helvetica Arial', + // 'slug' => 'helvetica-arial', + // 'fontFamily' => 'var(--custom-var-1)', + // ), + // ), + // ), + // ), + // ), + // ), + // true + // ); + // $theme_json->remove_insecure_properties(); + // $result = $theme_json->get_raw_data(); + // $expected = array( + // 'settings' => array( + // 'global' => array( + // 'color' => array( + // 'palette' => array( + // array( + // 'name' => 'Pink', + // 'slug' => 'pink', + // 'color' => '#FFC0CB', + // ), + // ), + // ), + // 'typography' => array( + // 'fontFamilies' => array( + // array( + // 'name' => 'Cambria', + // 'slug' => 'cambria', + // 'fontFamily' => 'Cambria, Georgia, serif', + // ), + // ), + // ), + // ), + // ), + // ); + // $this->assertEqualSetsWithIndex( $expected, $result ); + // } } From 312044715716775af08bd02997adca787118969e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Mon, 18 Jan 2021 18:12:26 +0100 Subject: [PATCH 28/65] Fix get_stylesheet( block_styles ) --- lib/class-wp-theme-json.php | 48 +++++++++++++++------------- phpunit/class-wp-theme-json-test.php | 8 ++--- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index 7743f191e8b218..43894896320532 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -654,7 +654,7 @@ private static function has_properties( $metadata ) { } /** - * Given a context, it extracts the style properties + * Given a styles array, it extracts the style properties * and adds them to the $declarations array following the format: * * ```php @@ -666,17 +666,18 @@ private static function has_properties( $metadata ) { * * Note that this modifies the $declarations in place. * - * @param array $declarations Holds the existing declarations. - * @param array $context Input context to process. - * @param array $context_supports Supports information for this context. + * @param array $declarations Holds the existing declarations. + * @param array $styles Styles to process. + * @param array $supports Supports information for this context. */ - private static function compute_style_properties( &$declarations, $context, $context_supports ) { - if ( empty( $context['styles'] ) ) { + private static function compute_style_properties( &$declarations, $styles, $supports ) { + if ( empty( $styles ) ) { return; } + $properties = array(); foreach ( self::PROPERTIES_METADATA as $name => $metadata ) { - if ( ! in_array( $name, $context_supports, true ) ) { + if ( ! in_array( $name, $supports, true ) ) { continue; } @@ -698,7 +699,7 @@ private static function compute_style_properties( &$declarations, $context, $con } foreach ( $properties as $prop ) { - $value = self::get_property_value( $context['styles'], $prop['value'] ); + $value = self::get_property_value( $styles, $prop['value'] ); if ( ! empty( $value ) ) { $kebab_cased_name = self::to_kebab_case( $prop['name'] ); $declarations[] = array( @@ -710,16 +711,16 @@ private static function compute_style_properties( &$declarations, $context, $con } /** - * Given a context, it extracts its presets + * Given a settings array, it extracts its presets * and adds them to the given input $stylesheet. * * Note this function modifies $stylesheet in place. * * @param string $stylesheet Input stylesheet to add the presets to. - * @param array $context Context to process. + * @param array $settings Settings to process. * @param string $selector Selector wrapping the classes. */ - private static function compute_preset_classes( &$stylesheet, $context, $selector ) { + private static function compute_preset_classes( &$stylesheet, $settings, $selector ) { if ( self::GLOBAL_SELECTOR === $selector ) { // Classes at the global level do not need any CSS prefixed, // and we don't want to increase its specificity. @@ -727,7 +728,7 @@ private static function compute_preset_classes( &$stylesheet, $context, $selecto } foreach ( self::PRESETS_METADATA as $preset ) { - $values = gutenberg_experimental_get( $context, $preset['path'], array() ); + $values = gutenberg_experimental_get( $settings, $preset['path_settings'], array() ); foreach ( $values as $value ) { foreach ( $preset['classes'] as $class ) { $stylesheet .= self::to_ruleset( @@ -915,20 +916,21 @@ private function get_css_variables() { private function get_block_styles() { $stylesheet = ''; $metadata = $this->get_blocks_metadata(); - foreach ( $this->theme_json as $context_name => $context ) { - if ( empty( $metadata[ $context_name ]['selector'] ) || empty( $metadata[ $context_name ]['supports'] ) ) { + foreach ( $this->theme_json['styles'] as $block_selector => $styles ) { + if ( empty( $metadata[ $block_selector ]['selector'] ) || empty( $metadata[ $block_selector ]['supports'] ) ) { continue; } - $selector = $metadata[ $context_name ]['selector']; - $supports = $metadata[ $context_name ]['supports']; + + $selector = $metadata[ $block_selector ]['selector']; + $supports = $metadata[ $block_selector ]['supports']; $declarations = array(); - self::compute_style_properties( $declarations, $context, $supports ); + self::compute_style_properties( $declarations, $styles, $supports ); $stylesheet .= self::to_ruleset( $selector, $declarations ); // Attach the rulesets for the classes. - self::compute_preset_classes( $stylesheet, $context, $selector ); + self::compute_preset_classes( $stylesheet, $this->theme_json['settings'][ $block_selector ], $selector ); } return $stylesheet; @@ -1023,10 +1025,10 @@ public function merge( $incoming ) { */ public function remove_insecure_properties() { $blocks_metadata = self::get_blocks_metadata(); - foreach ( $this->theme_json as $context_name => &$context ) { + foreach ( $this->theme_json as $block_selector => &$context ) { // Escape the context key. - if ( empty( $blocks_metadata[ $context_name ] ) ) { - unset( $this->theme_json[ $context_name ] ); + if ( empty( $blocks_metadata[ $block_selector ] ) ) { + unset( $this->theme_json[ $block_selector ] ); continue; } @@ -1035,7 +1037,7 @@ public function remove_insecure_properties() { // Style escaping. if ( ! empty( $context['styles'] ) ) { - $supports = $blocks_metadata[ $context_name ]['supports']; + $supports = $blocks_metadata[ $block_selector ]['supports']; $declarations = array(); self::compute_style_properties( $declarations, $context, $supports ); foreach ( $declarations as $declaration ) { @@ -1113,7 +1115,7 @@ public function remove_insecure_properties() { } if ( null === $escaped_settings && null === $escaped_styles ) { - unset( $this->theme_json[ $context_name ] ); + unset( $this->theme_json[ $block_selector ] ); } elseif ( null !== $escaped_settings && null !== $escaped_styles ) { $context = array( 'styles' => $escaped_styles, diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index cef3cbbb00913c..295a98990a7bec 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -234,10 +234,10 @@ function test_get_stylesheet() { // ':root{--wp--preset--color--grey: grey;--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}:root{--wp--style--color--link: #111;color: var(--wp--preset--color--grey);}.has-grey-color{color: grey;}.has-grey-background-color{background-color: grey;}.wp-block-group{padding-top: 12px;padding-bottom: 24px;}', // $theme_json->get_stylesheet() // ); - // $this->assertEquals( - // ':root{--wp--style--color--link: #111;color: var(--wp--preset--color--grey);}.has-grey-color{color: grey;}.has-grey-background-color{background-color: grey;}.wp-block-group{padding-top: 12px;padding-bottom: 24px;}', - // $theme_json->get_stylesheet( 'block_styles' ) - // ); + $this->assertEquals( + ':root{--wp--style--color--link: #111;color: var(--wp--preset--color--grey);}.has-grey-color{color: grey;}.has-grey-background-color{background-color: grey;}.wp-block-group{padding-top: 12px;padding-bottom: 24px;}', + $theme_json->get_stylesheet( 'block_styles' ) + ); $this->assertEquals( ':root{--wp--preset--color--grey: grey;--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}', $theme_json->get_stylesheet( 'css_variables' ) From 79d400d67f6299a94a1c0a8abaa6b5d914e6e798 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Mon, 18 Jan 2021 18:12:52 +0100 Subject: [PATCH 29/65] Fix get_stylesheet --- phpunit/class-wp-theme-json-test.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index 295a98990a7bec..15c1e5637f4577 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -230,10 +230,10 @@ function test_get_stylesheet() { ) ); - // $this->assertEquals( - // ':root{--wp--preset--color--grey: grey;--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}:root{--wp--style--color--link: #111;color: var(--wp--preset--color--grey);}.has-grey-color{color: grey;}.has-grey-background-color{background-color: grey;}.wp-block-group{padding-top: 12px;padding-bottom: 24px;}', - // $theme_json->get_stylesheet() - // ); + $this->assertEquals( + ':root{--wp--preset--color--grey: grey;--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}:root{--wp--style--color--link: #111;color: var(--wp--preset--color--grey);}.has-grey-color{color: grey;}.has-grey-background-color{background-color: grey;}.wp-block-group{padding-top: 12px;padding-bottom: 24px;}', + $theme_json->get_stylesheet() + ); $this->assertEquals( ':root{--wp--style--color--link: #111;color: var(--wp--preset--color--grey);}.has-grey-color{color: grey;}.has-grey-background-color{background-color: grey;}.wp-block-group{padding-top: 12px;padding-bottom: 24px;}', $theme_json->get_stylesheet( 'block_styles' ) From fa14cb5ce4951bf57112376a2656a3b906040bae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Mon, 18 Jan 2021 18:30:57 +0100 Subject: [PATCH 30/65] No need to remove contexts as it was already done by the constructor --- lib/class-wp-theme-json.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index 43894896320532..09213cb147b2e1 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -1026,12 +1026,6 @@ public function merge( $incoming ) { public function remove_insecure_properties() { $blocks_metadata = self::get_blocks_metadata(); foreach ( $this->theme_json as $block_selector => &$context ) { - // Escape the context key. - if ( empty( $blocks_metadata[ $block_selector ] ) ) { - unset( $this->theme_json[ $block_selector ] ); - continue; - } - $escaped_settings = null; $escaped_styles = null; From 12c6fb932414fc3cc51aa643b250dbf20e3c0ba8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Mon, 18 Jan 2021 18:37:52 +0100 Subject: [PATCH 31/65] Create a escape_styles function --- lib/class-wp-theme-json.php | 4 ++ phpunit/class-wp-theme-json-test.php | 70 ++++++++++++++-------------- 2 files changed, 40 insertions(+), 34 deletions(-) diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index 09213cb147b2e1..c31246b9fa96cd 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -1020,6 +1020,10 @@ public function merge( $incoming ) { } } + public function escape_styles() { + // Do nothing. + } + /** * Removes insecure data from theme.json. */ diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index 15c1e5637f4577..704634fe918510 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -661,40 +661,42 @@ function test_remove_insecure_properties_removes_non_preset_settings() { $this->assertEqualSetsWithIndex( $expected, $result ); } - // function test_remove_insecure_properties_removes_invalid_contexts() { - // $theme_json = new WP_Theme_JSON( - // array( - // 'styles' => array( - // 'global' => array( - // 'color' => array( - // 'background' => 'green', - // 'text' => 'var:preset|color|dark-gray', - // ), - // ), - // '.my-class' => array( - // 'color' => array( - // 'background' => 'green', - // 'text' => 'var:preset|color|dark-gray', - // ), - // ), - // ), - // ), - // true - // ); - // $theme_json->remove_insecure_properties(); - // $result = $theme_json->get_raw_data(); - // $expected = array( - // 'styles' => array( - // 'global' => array( - // 'color' => array( - // 'background' => 'green', - // 'text' => 'var:preset|color|dark-gray', - // ), - // ), - // ), - // ); - // $this->assertEqualSetsWithIndex( $expected, $result ); - // } + // This is done in the constructor already. + // No need to test it or do anything code-wise. + function test_remove_insecure_properties_removes_invalid_contexts() { + $theme_json = new WP_Theme_JSON( + array( + 'styles' => array( + 'global' => array( + 'color' => array( + 'background' => 'green', + 'text' => 'var:preset|color|dark-gray', + ), + ), + '.my-class' => array( + 'color' => array( + 'background' => 'green', + 'text' => 'var:preset|color|dark-gray', + ), + ), + ), + ), + true + ); + $theme_json->escape_styles(); + $result = $theme_json->get_raw_data(); + $expected = array( + 'styles' => array( + 'global' => array( + 'color' => array( + 'background' => 'green', + 'text' => 'var:preset|color|dark-gray', + ), + ), + ), + ); + $this->assertEqualSetsWithIndex( $expected, $result ); + } // function test_remove_insecure_properties_removes_invalid_properties() { // $theme_json = new WP_Theme_JSON( From 2dcdc15b1d5cb9624398fcbfc02db7cb095fe244 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Mon, 18 Jan 2021 18:38:45 +0100 Subject: [PATCH 32/65] Another tests that can be removed --- phpunit/class-wp-theme-json-test.php | 62 ++++++++++++++-------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index 704634fe918510..ed968562fd4372 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -698,37 +698,37 @@ function test_remove_insecure_properties_removes_invalid_contexts() { $this->assertEqualSetsWithIndex( $expected, $result ); } - // function test_remove_insecure_properties_removes_invalid_properties() { - // $theme_json = new WP_Theme_JSON( - // array( - // 'styles' => array( - // 'global' => array( - // 'color' => array( - // 'gradient' => 'linear-gradient(55deg,rgba(6,147,227,1) 0%,rgb(84,177,218) 54%,rgb(155,81,224) 100%)', - // 'text' => 'var:preset|color|dark-gray', - // ), - // ), - // 'invalid' => array( - // 'background' => 'green', - // ), - // ), - // ), - // true - // ); - // $theme_json->remove_insecure_properties(); - // $result = $theme_json->get_raw_data(); - // $expected = array( - // 'styles' => array( - // 'global' => array( - // 'color' => array( - // 'gradient' => 'linear-gradient(55deg,rgba(6,147,227,1) 0%,rgb(84,177,218) 54%,rgb(155,81,224) 100%)', - // 'text' => 'var:preset|color|dark-gray', - // ), - // ), - // ), - // ); - // $this->assertEqualSetsWithIndex( $expected, $result ); - // } + function test_remove_insecure_properties_removes_invalid_properties() { + $theme_json = new WP_Theme_JSON( + array( + 'styles' => array( + 'global' => array( + 'color' => array( + 'gradient' => 'linear-gradient(55deg,rgba(6,147,227,1) 0%,rgb(84,177,218) 54%,rgb(155,81,224) 100%)', + 'text' => 'var:preset|color|dark-gray', + ), + ), + 'invalid' => array( + 'background' => 'green', + ), + ), + ), + true + ); + $theme_json->escape_styles(); + $result = $theme_json->get_raw_data(); + $expected = array( + 'styles' => array( + 'global' => array( + 'color' => array( + 'gradient' => 'linear-gradient(55deg,rgba(6,147,227,1) 0%,rgb(84,177,218) 54%,rgb(155,81,224) 100%)', + 'text' => 'var:preset|color|dark-gray', + ), + ), + ), + ); + $this->assertEqualSetsWithIndex( $expected, $result ); + } // function test_remove_insecure_properties_removes_unsafe_properties() { // $theme_json = new WP_Theme_JSON( From 7b1c07ac7f46efa7e5ff2dca6784609419e401ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Mon, 18 Jan 2021 18:39:03 +0100 Subject: [PATCH 33/65] Remove tests that are duplicated --- phpunit/class-wp-theme-json-test.php | 69 ---------------------------- 1 file changed, 69 deletions(-) diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index ed968562fd4372..d5322c75757e3e 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -661,75 +661,6 @@ function test_remove_insecure_properties_removes_non_preset_settings() { $this->assertEqualSetsWithIndex( $expected, $result ); } - // This is done in the constructor already. - // No need to test it or do anything code-wise. - function test_remove_insecure_properties_removes_invalid_contexts() { - $theme_json = new WP_Theme_JSON( - array( - 'styles' => array( - 'global' => array( - 'color' => array( - 'background' => 'green', - 'text' => 'var:preset|color|dark-gray', - ), - ), - '.my-class' => array( - 'color' => array( - 'background' => 'green', - 'text' => 'var:preset|color|dark-gray', - ), - ), - ), - ), - true - ); - $theme_json->escape_styles(); - $result = $theme_json->get_raw_data(); - $expected = array( - 'styles' => array( - 'global' => array( - 'color' => array( - 'background' => 'green', - 'text' => 'var:preset|color|dark-gray', - ), - ), - ), - ); - $this->assertEqualSetsWithIndex( $expected, $result ); - } - - function test_remove_insecure_properties_removes_invalid_properties() { - $theme_json = new WP_Theme_JSON( - array( - 'styles' => array( - 'global' => array( - 'color' => array( - 'gradient' => 'linear-gradient(55deg,rgba(6,147,227,1) 0%,rgb(84,177,218) 54%,rgb(155,81,224) 100%)', - 'text' => 'var:preset|color|dark-gray', - ), - ), - 'invalid' => array( - 'background' => 'green', - ), - ), - ), - true - ); - $theme_json->escape_styles(); - $result = $theme_json->get_raw_data(); - $expected = array( - 'styles' => array( - 'global' => array( - 'color' => array( - 'gradient' => 'linear-gradient(55deg,rgba(6,147,227,1) 0%,rgb(84,177,218) 54%,rgb(155,81,224) 100%)', - 'text' => 'var:preset|color|dark-gray', - ), - ), - ), - ); - $this->assertEqualSetsWithIndex( $expected, $result ); - } - // function test_remove_insecure_properties_removes_unsafe_properties() { // $theme_json = new WP_Theme_JSON( // array( From 8eb12b670f23b7eb979f59fa9c743f2ed04f8ed6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Mon, 18 Jan 2021 18:49:48 +0100 Subject: [PATCH 34/65] Create new schema validation test --- lib/class-wp-theme-json.php | 4 -- phpunit/class-wp-theme-json-test.php | 91 ++++++++++------------------ 2 files changed, 33 insertions(+), 62 deletions(-) diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index c31246b9fa96cd..09213cb147b2e1 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -1020,10 +1020,6 @@ public function merge( $incoming ) { } } - public function escape_styles() { - // Do nothing. - } - /** * Removes insecure data from theme.json. */ diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index d5322c75757e3e..dc4ebf530cff2f 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -144,6 +144,39 @@ function test_schema_validation_subtree_is_removed_if_empty() { $this->assertEqualSetsWithIndex( $expected, $result ); } + function test_schema_validation_subtree_is_removed_if_style_not_supported_by_block() { + $theme_json = new WP_Theme_JSON( + array( + 'styles' => array( + 'global' => array( + 'color' => array( + 'text' => 'var:preset|color|dark-gray', + ), + 'spacing' => array( + 'padding' => array( + 'top' => '1px', + 'right' => '1px', + 'bottom' => '1px', + 'left' => '1px', + ), + ), + ), + ), + ) + ); + $actual = $theme_json->get_raw_data(); + $expected = array( + 'styles' => array( + 'global' => array( + 'color' => array( + 'text' => 'var:preset|color|dark-gray', + ), + ) + ), + ); + $this->assertEqualSetsWithIndex( $expected, $actual ); + } + function test_get_settings() { // See schema at WP_Theme_JSON::SCHEMA. $theme_json = new WP_Theme_JSON( @@ -692,64 +725,6 @@ function test_remove_insecure_properties_removes_non_preset_settings() { // $this->assertEqualSetsWithIndex( $expected, $result ); // } - // function test_remove_insecure_properties_removes_properties_when_not_allowed_in_a_context() { - // $theme_json = new WP_Theme_JSON( - // array( - // 'styles' => array( - // 'global' => array( - // 'color' => array( - // 'text' => 'var:preset|color|dark-gray', - // ), - // 'spacing' => array( - // 'padding' => array( - // 'top' => '1px', - // 'right' => '1px', - // 'bottom' => '1px', - // 'left' => '1px', - // ), - // ), - // ), - // 'invalid' => array( - // 'background' => 'green', - // ), - // 'core/group' => array( - // 'spacing' => array( - // 'padding' => array( - // 'top' => '1px', - // 'right' => '1px', - // 'bottom' => '1px', - // 'left' => '1px', - // ), - // ), - // ), - // ), - // ), - // true - // ); - // $theme_json->remove_insecure_properties(); - // $result = $theme_json->get_raw_data(); - // $expected = array( - // 'styles' => array( - // 'global' => array( - // 'color' => array( - // 'text' => 'var:preset|color|dark-gray', - // ), - // ), - // 'core/group' => array( - // 'spacing' => array( - // 'padding' => array( - // 'top' => '1px', - // 'right' => '1px', - // 'bottom' => '1px', - // 'left' => '1px', - // ), - // ), - // ), - // ), - // ); - // $this->assertEqualSetsWithIndex( $expected, $result ); - // } - // function test_remove_insecure_properties_removes_unsafe_sub_properties() { // $theme_json = new WP_Theme_JSON( // array( From 02adbee6bf3c82407d0966c91fc7e75cac6d6ca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Thu, 21 Jan 2021 11:43:44 +0100 Subject: [PATCH 35/65] Remove style properties that are not supported by the block --- lib/class-wp-theme-json.php | 53 ++++++++++++++++++++-------- phpunit/class-wp-theme-json-test.php | 23 ++++++------ 2 files changed, 49 insertions(+), 27 deletions(-) diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index 09213cb147b2e1..5571808b6a4e93 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -320,24 +320,49 @@ public function __construct( $theme_json = array() ) { } } - // Future optimization: at this point, we could iterate over the block selectors present - // in either styles or settings instead of iterating over all registered. foreach( $block_metadata as $block_selector => $metadata ) { - foreach( [ 'styles', 'settings' ] as $key => $subtree ) { - if ( isset( $this->theme_json[ $subtree ][ $block_selector] ) ) { - // Remove the block selector subtree if it's not an array. - if ( ! is_array( $this->theme_json[ $subtree ][ $block_selector] ) ) { - unset( $this->theme_json[ $subtree ][ $block_selector] ); - continue; + if ( isset( $this->theme_json['styles'][ $block_selector] ) ) { + // Remove the block selector subtree if it's not an array. + if ( ! is_array( $this->theme_json['styles'][ $block_selector] ) ) { + unset( $this->theme_json['styles'][ $block_selector] ); + continue; + } + + // Remove the properties the block doesn't support. + // This is a subset of the full styles schema. + $styles_schema = self::SCHEMA['styles']; + foreach( self::PROPERTIES_METADATA as $prop_name => $prop_meta ) { + if( ! in_array( $prop_name, $metadata['supports'] ) ) { + unset( $styles_schema[ $prop_meta['value'][0] ][ $prop_meta['value'][1] ] ); } + } + self::remove_keys_not_in_schema( + $this->theme_json['styles'][ $block_selector ], + $styles_schema + ); + + // Remove the block selector subtree if it is empty after having processed it. + if ( empty( $this->theme_json['styles'][ $block_selector ] ) ) { + unset( $this->theme_json['styles'][ $block_selector ] ); + } + } + + if ( isset( $this->theme_json['settings'][ $block_selector] ) ) { + // Remove the block selector subtree if it's not an array. + if ( ! is_array( $this->theme_json['settings'][ $block_selector] ) ) { + unset( $this->theme_json['settings'][ $block_selector] ); + continue; + } - // Remove the properties within the styles & settings subtrees if they aren't present in the schema. - self::remove_keys_not_in_schema( $this->theme_json[ $subtree ][ $block_selector ], self::SCHEMA[ $subtree ] ); + // Remove the properties that aren't present in the schema. + self::remove_keys_not_in_schema( + $this->theme_json[ 'settings' ][ $block_selector ], + self::SCHEMA['settings'] + ); - // Remove the block selector subtree if it is empty after having processed it. - if ( empty( $this->theme_json[ $subtree ][ $block_selector ] ) ) { - unset( $this->theme_json[ $subtree ][ $block_selector ] ); - } + // Remove the block selector subtree if it is empty after having processed it. + if ( empty( $this->theme_json['settings'][ $block_selector ] ) ) { + unset( $this->theme_json['settings'][ $block_selector ] ); } } } diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index dc4ebf530cff2f..1517b235167faf 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -18,7 +18,7 @@ function test_schema_validation_subtree_is_removed_if_key_invalid() { 'custom' => 'false', ), ), - 'global' => array( + 'core/group' => array( 'invalid/key' => array( 'custom' => false, 'background' => 'red', @@ -41,7 +41,7 @@ function test_schema_validation_subtree_is_removed_if_key_invalid() { $expected = array( 'styles' => array( - 'global' => array( + 'core/group' => array( 'color' => array( 'background' => 'red', ), @@ -69,15 +69,14 @@ function test_schema_validation_subtree_is_removed_if_not_array() { 'core/group' => array( 'invalid/not/array' => false, 'color' => array( - 'invalid/not/array' => true, + 'link' => 'pink', ), 'typography' => array( 'invalid/key' => false, - 'lineHeight' => '2', ), 'spacing' => array( 'padding' => array( - 'invalid/not/array' => '10px' + 'invalid/key' => '10px', ), ), ), @@ -89,8 +88,8 @@ function test_schema_validation_subtree_is_removed_if_not_array() { $expected = array( 'styles' => array( 'core/group' => array( - 'typography' => array( - 'lineHeight' => '2', + 'color' => array( + 'link' => 'pink', ), ), ), @@ -160,7 +159,7 @@ function test_schema_validation_subtree_is_removed_if_style_not_supported_by_blo 'left' => '1px', ), ), - ), + ) ), ) ); @@ -324,7 +323,6 @@ public function test_merge_incoming_data() { 'fontSize' => '12', ), 'color' => array( - 'link' => 'pink', 'background' => 'brown', ), ), @@ -353,7 +351,7 @@ public function test_merge_incoming_data() { $add_styles = array( 'styles' => array( - 'core/paragraph' => array( + 'core/group' => array( 'spacing' => array( 'padding' => array( 'top' => '12px' @@ -365,7 +363,7 @@ public function test_merge_incoming_data() { $add_key_in_styles = array( 'styles' => array( - 'core/paragraph' => array( + 'core/group' => array( 'spacing' => array( 'padding' => array( 'bottom' => '12px', @@ -661,7 +659,7 @@ function test_remove_insecure_properties_removes_non_preset_settings() { 'fontSize' => '12', ), ), - 'core/paragraph' => array( + 'core/group' => array( 'spacing' => array( 'padding' => array( 'top' => '12px', @@ -674,7 +672,6 @@ function test_remove_insecure_properties_removes_non_preset_settings() { 'fontSize' => '12', ), 'color' => array( - 'link' => 'pink', 'background' => 'brown', ), ), From af15f17f2052b47fbffaa2322c3e7371a667dbc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Thu, 21 Jan 2021 12:16:01 +0100 Subject: [PATCH 36/65] Remove unsafe styles --- lib/class-wp-theme-json.php | 58 ++++++++++----------------- phpunit/class-wp-theme-json-test.php | 60 ++++++++++++++-------------- 2 files changed, 50 insertions(+), 68 deletions(-) diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index 5571808b6a4e93..9e75957c3791e4 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -1050,38 +1050,28 @@ public function merge( $incoming ) { */ public function remove_insecure_properties() { $blocks_metadata = self::get_blocks_metadata(); - foreach ( $this->theme_json as $block_selector => &$context ) { - $escaped_settings = null; - $escaped_styles = null; + foreach ( $blocks_metadata as $block_selector => $metadata ) { + $escaped_settings = array(); + $escaped_styles = array(); // Style escaping. - if ( ! empty( $context['styles'] ) ) { - $supports = $blocks_metadata[ $block_selector ]['supports']; + if ( isset( $this->theme_json['styles'][ $block_selector ] ) ) { $declarations = array(); - self::compute_style_properties( $declarations, $context, $supports ); + self::compute_style_properties( $declarations, $this->theme_json['styles'][ $block_selector ], $metadata['supports'] ); foreach ( $declarations as $declaration ) { $style_to_validate = $declaration['name'] . ': ' . $declaration['value']; if ( esc_html( safecss_filter_attr( $style_to_validate ) ) === $style_to_validate ) { - if ( null === $escaped_styles ) { - $escaped_styles = array(); - } $property = self::to_property( $declaration['name'] ); $path = self::PROPERTIES_METADATA[ $property ]['value']; if ( self::has_properties( self::PROPERTIES_METADATA[ $property ] ) ) { $declaration_divided = explode( '-', $declaration['name'] ); $path[] = $declaration_divided[1]; - gutenberg_experimental_set( - $escaped_styles, - $path, - gutenberg_experimental_get( $context['styles'], $path ) - ); - } else { - gutenberg_experimental_set( - $escaped_styles, - $path, - gutenberg_experimental_get( $context['styles'], $path ) - ); } + gutenberg_experimental_set( + $escaped_styles, + $path, + gutenberg_experimental_get( $this->theme_json['styles'][ $block_selector ], $path ) + ); } } } @@ -1121,33 +1111,25 @@ public function remove_insecure_properties() { } } if ( count( $escaped_preset ) > 0 ) { - if ( null === $escaped_settings ) { - $escaped_settings = array(); - } gutenberg_experimental_set( $escaped_settings, $preset_metadata['path'], $escaped_preset ); } } } - if ( null !== $escaped_settings ) { + if ( empty( $escaped_settings ) ) { $escaped_settings = $escaped_settings['settings']; } } - if ( null === $escaped_settings && null === $escaped_styles ) { - unset( $this->theme_json[ $block_selector ] ); - } elseif ( null !== $escaped_settings && null !== $escaped_styles ) { - $context = array( - 'styles' => $escaped_styles, - 'settings' => $escaped_settings, - ); - } elseif ( null === $escaped_settings ) { - $context = array( - 'styles' => $escaped_styles, - ); + if ( empty( $escaped_settings ) ) { + unset( $this->theme_json['settings'][ $block_selector ] ); } else { - $context = array( - 'settings' => $escaped_settings, - ); + $this->theme_json['settings'][ $block_selector ] = $escaped_settings; + } + + if ( empty( $escaped_styles ) ) { + unset( $this->theme_json['styles'][ $block_selector ] ); + } else { + $this->theme_json['styles'][ $block_selector ] = $escaped_styles; } } } diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index 1517b235167faf..ee4d5bcedac198 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -691,36 +691,36 @@ function test_remove_insecure_properties_removes_non_preset_settings() { $this->assertEqualSetsWithIndex( $expected, $result ); } - // function test_remove_insecure_properties_removes_unsafe_properties() { - // $theme_json = new WP_Theme_JSON( - // array( - // 'styles' => array( - // 'global' => array( - // 'color' => array( - // 'gradient' => 'url(\'data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxMCcgaGVpZ2h0PScxMCc+PHNjcmlwdD5hbGVydCgnb2snKTwvc2NyaXB0PjxsaW5lYXJHcmFkaWVudCBpZD0nZ3JhZGllbnQnPjxzdG9wIG9mZnNldD0nMTAlJyBzdG9wLWNvbG9yPScjRjAwJy8+PHN0b3Agb2Zmc2V0PSc5MCUnIHN0b3AtY29sb3I9JyNmY2MnLz4gPC9saW5lYXJHcmFkaWVudD48cmVjdCBmaWxsPSd1cmwoI2dyYWRpZW50KScgeD0nMCcgeT0nMCcgd2lkdGg9JzEwMCUnIGhlaWdodD0nMTAwJScvPjwvc3ZnPg==\')', - // 'text' => 'var:preset|color|dark-gray', - // ), - // ), - // 'invalid' => array( - // 'background' => 'green', - // ), - // ), - // ), - // true - // ); - // $theme_json->remove_insecure_properties(); - // $result = $theme_json->get_raw_data(); - // $expected = array( - // 'styles' => array( - // 'global' => array( - // 'color' => array( - // 'text' => 'var:preset|color|dark-gray', - // ), - // ), - // ), - // ); - // $this->assertEqualSetsWithIndex( $expected, $result ); - // } + function test_remove_insecure_properties_removes_unsafe_styles() { + $theme_json = new WP_Theme_JSON( + array( + 'styles' => array( + 'core/group' => array( + 'color' => array( + 'gradient' => 'url(\'data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxMCcgaGVpZ2h0PScxMCc+PHNjcmlwdD5hbGVydCgnb2snKTwvc2NyaXB0PjxsaW5lYXJHcmFkaWVudCBpZD0nZ3JhZGllbnQnPjxzdG9wIG9mZnNldD0nMTAlJyBzdG9wLWNvbG9yPScjRjAwJy8+PHN0b3Agb2Zmc2V0PSc5MCUnIHN0b3AtY29sb3I9JyNmY2MnLz4gPC9saW5lYXJHcmFkaWVudD48cmVjdCBmaWxsPSd1cmwoI2dyYWRpZW50KScgeD0nMCcgeT0nMCcgd2lkdGg9JzEwMCUnIGhlaWdodD0nMTAwJScvPjwvc3ZnPg==\')', + 'text' => 'var:preset|color|dark-gray' + ), + ), + 'invalid/key' => array( + 'background' => 'green', + ), + ), + ), + true + ); + $theme_json->remove_insecure_properties(); + $result = $theme_json->get_raw_data(); + $expected = array( + 'styles' => array( + 'core/group' => array( + 'color' => array( + 'text' => 'var:preset|color|dark-gray' + ), + ), + ), + ); + $this->assertEqualSetsWithIndex( $expected, $result ); + } // function test_remove_insecure_properties_removes_unsafe_sub_properties() { // $theme_json = new WP_Theme_JSON( From 99d237ba4135c9059f6c82873ba03df05363cf46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Thu, 21 Jan 2021 12:16:50 +0100 Subject: [PATCH 37/65] Remove unsafe styles sub-properties --- phpunit/class-wp-theme-json-test.php | 70 ++++++++++++++-------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index ee4d5bcedac198..27f390fd452229 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -722,41 +722,41 @@ function test_remove_insecure_properties_removes_unsafe_styles() { $this->assertEqualSetsWithIndex( $expected, $result ); } - // function test_remove_insecure_properties_removes_unsafe_sub_properties() { - // $theme_json = new WP_Theme_JSON( - // array( - // 'styles' => array( - // 'core/group' => array( - // 'spacing' => array( - // 'padding' => array( - // 'top' => '1px', - // 'right' => '1px', - // 'bottom' => 'var(--unsafe-var-y)', - // 'left' => '1px', - // ), - // ), - // ), - // ), - // ), - // true - // ); - // $theme_json->remove_insecure_properties(); - // $result = $theme_json->get_raw_data(); - // $expected = array( - // 'styles' => array( - // 'core/group' => array( - // 'spacing' => array( - // 'padding' => array( - // 'top' => '1px', - // 'right' => '1px', - // 'left' => '1px', - // ), - // ), - // ), - // ), - // ); - // $this->assertEqualSetsWithIndex( $expected, $result ); - // } + function test_remove_insecure_properties_removes_unsafe_styles_sub_properties() { + $theme_json = new WP_Theme_JSON( + array( + 'styles' => array( + 'core/group' => array( + 'spacing' => array( + 'padding' => array( + 'top' => '1px', + 'right' => '1px', + 'bottom' => 'var(--unsafe-var-y)', + 'left' => '1px', + ), + ), + ), + ), + ), + true + ); + $theme_json->remove_insecure_properties(); + $result = $theme_json->get_raw_data(); + $expected = array( + 'styles' => array( + 'core/group' => array( + 'spacing' => array( + 'padding' => array( + 'top' => '1px', + 'right' => '1px', + 'left' => '1px', + ), + ), + ), + ), + ); + $this->assertEqualSetsWithIndex( $expected, $result ); + } // function test_remove_insecure_properties_removes_non_preset_settings() { // $theme_json = new WP_Theme_JSON( From 5162f3e6a202ccec71bbe155365ae918b3ee085b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Thu, 21 Jan 2021 18:03:15 +0100 Subject: [PATCH 38/65] Fix settings --- lib/class-wp-theme-json.php | 16 +-- phpunit/class-wp-theme-json-test.php | 172 +++++++++++++-------------- 2 files changed, 95 insertions(+), 93 deletions(-) diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index 9e75957c3791e4..1400d98df0ac63 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -1078,9 +1078,13 @@ public function remove_insecure_properties() { // Settings escaping. // For now the ony allowed settings are presets. - if ( ! empty( $context['settings'] ) ) { + if ( isset( $this->theme_json['settings'][ $block_selector ] ) ) { foreach ( self::PRESETS_METADATA as $preset_metadata ) { - $current_preset = gutenberg_experimental_get( $context, $preset_metadata['path'], null ); + $current_preset = gutenberg_experimental_get( + $this->theme_json['settings'][ $block_selector], + $preset_metadata['path_settings'], + null + ); if ( null !== $current_preset ) { $escaped_preset = array(); foreach ( $current_preset as $single_preset ) { @@ -1101,6 +1105,7 @@ public function remove_insecure_properties() { } } } else { + // font family $property = $preset_metadata['css_var_infix']; $style_to_validate = $property . ': ' . $value; $single_preset_is_valid = esc_html( safecss_filter_attr( $style_to_validate ) ) === $style_to_validate; @@ -1110,14 +1115,11 @@ public function remove_insecure_properties() { } } } - if ( count( $escaped_preset ) > 0 ) { - gutenberg_experimental_set( $escaped_settings, $preset_metadata['path'], $escaped_preset ); + if ( ! empty( $escaped_preset ) ) { + gutenberg_experimental_set( $escaped_settings, $preset_metadata['path_settings'], $escaped_preset ); } } } - if ( empty( $escaped_settings ) ) { - $escaped_settings = $escaped_settings['settings']; - } } if ( empty( $escaped_settings ) ) { diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index 27f390fd452229..8ed24dd7f1392b 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -821,90 +821,90 @@ function test_remove_insecure_properties_removes_unsafe_styles_sub_properties() // $this->assertEqualSetsWithIndex( $expected, $result ); // } - // function test_remove_insecure_properties_removes_unsafe_preset_settings() { - // $theme_json = new WP_Theme_JSON( - // array( - // 'settings' => array( - // 'global' => array( - // 'color' => array( - // 'palette' => array( - // array( - // 'name' => 'Red/>ok', - // 'slug' => 'red', - // 'color' => '#ff0000', - // ), - // array( - // 'name' => 'Green', - // 'slug' => 'a" attr', - // 'color' => '#00ff00', - // ), - // array( - // 'name' => 'Blue', - // 'slug' => 'blue', - // 'color' => 'var(--custom-v1)', - // ), - // array( - // 'name' => 'Pink', - // 'slug' => 'pink', - // 'color' => '#FFC0CB', - // ), - // ), - // ), - // 'typography' => array( - // 'fontFamilies' => array( - // array( - // 'name' => 'Helvetica Arial/>test', - // 'slug' => 'helvetica-arial', - // 'fontFamily' => 'Helvetica Neue, Helvetica, Arial, sans-serif', - // ), - // array( - // 'name' => 'Geneva', - // 'slug' => 'geneva#asa', - // 'fontFamily' => 'Geneva, Tahoma, Verdana, sans-serif', - // ), - // array( - // 'name' => 'Cambria', - // 'slug' => 'cambria', - // 'fontFamily' => 'Cambria, Georgia, serif', - // ), - // array( - // 'name' => 'Helvetica Arial', - // 'slug' => 'helvetica-arial', - // 'fontFamily' => 'var(--custom-var-1)', - // ), - // ), - // ), - // ), - // ), - // ), - // true - // ); - // $theme_json->remove_insecure_properties(); - // $result = $theme_json->get_raw_data(); - // $expected = array( - // 'settings' => array( - // 'global' => array( - // 'color' => array( - // 'palette' => array( - // array( - // 'name' => 'Pink', - // 'slug' => 'pink', - // 'color' => '#FFC0CB', - // ), - // ), - // ), - // 'typography' => array( - // 'fontFamilies' => array( - // array( - // 'name' => 'Cambria', - // 'slug' => 'cambria', - // 'fontFamily' => 'Cambria, Georgia, serif', - // ), - // ), - // ), - // ), - // ), - // ); - // $this->assertEqualSetsWithIndex( $expected, $result ); - // } + function test_remove_insecure_properties_removes_unsafe_preset_settings() { + $theme_json = new WP_Theme_JSON( + array( + 'settings' => array( + 'global' => array( + 'color' => array( + 'palette' => array( + array( + 'name' => 'Red/>ok', + 'slug' => 'red', + 'color' => '#ff0000', + ), + array( + 'name' => 'Green', + 'slug' => 'a" attr', + 'color' => '#00ff00', + ), + array( + 'name' => 'Blue', + 'slug' => 'blue', + 'color' => 'var(--custom-v1)', + ), + array( + 'name' => 'Pink', + 'slug' => 'pink', + 'color' => '#FFC0CB', + ), + ), + ), + 'typography' => array( + 'fontFamilies' => array( + array( + 'name' => 'Helvetica Arial/>test', + 'slug' => 'helvetica-arial', + 'fontFamily' => 'Helvetica Neue, Helvetica, Arial, sans-serif', + ), + array( + 'name' => 'Geneva', + 'slug' => 'geneva#asa', + 'fontFamily' => 'Geneva, Tahoma, Verdana, sans-serif', + ), + array( + 'name' => 'Cambria', + 'slug' => 'cambria', + 'fontFamily' => 'Cambria, Georgia, serif', + ), + array( + 'name' => 'Helvetica Arial', + 'slug' => 'helvetica-arial', + 'fontFamily' => 'var(--custom-var-1)', + ), + ), + ), + ), + ), + ), + true + ); + $theme_json->remove_insecure_properties(); + $result = $theme_json->get_raw_data(); + $expected = array( + 'settings' => array( + 'global' => array( + 'color' => array( + 'palette' => array( + array( + 'name' => 'Pink', + 'slug' => 'pink', + 'color' => '#FFC0CB', + ), + ), + ), + 'typography' => array( + 'fontFamilies' => array( + array( + 'name' => 'Cambria', + 'slug' => 'cambria', + 'fontFamily' => 'Cambria, Georgia, serif', + ), + ), + ), + ), + ), + ); + $this->assertEqualSetsWithIndex( $expected, $result ); + } } From 63655ae191372879130f5a6bc9ec1bc1cb3c9bd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Thu, 21 Jan 2021 18:04:16 +0100 Subject: [PATCH 39/65] Uncomment passing test --- phpunit/class-wp-theme-json-test.php | 124 +++++++++++++-------------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index 8ed24dd7f1392b..c7a4a65e0c00cb 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -758,68 +758,68 @@ function test_remove_insecure_properties_removes_unsafe_styles_sub_properties() $this->assertEqualSetsWithIndex( $expected, $result ); } - // function test_remove_insecure_properties_removes_non_preset_settings() { - // $theme_json = new WP_Theme_JSON( - // array( - // 'settings' => array( - // 'global' => array( - // 'color' => array( - // 'custom' => true, - // 'palette' => array( - // array( - // 'name' => 'Red', - // 'slug' => 'red', - // 'color' => '#ff0000', - // ), - // array( - // 'name' => 'Green', - // 'slug' => 'green', - // 'color' => '#00ff00', - // ), - // array( - // 'name' => 'Blue', - // 'slug' => 'blue', - // 'color' => '#0000ff', - // ), - // ), - // ), - // 'spacing' => array( - // 'customPadding' => false, - // ), - // ), - // ), - // ), - // true - // ); - // $theme_json->remove_insecure_properties(); - // $result = $theme_json->get_raw_data(); - // $expected = array( - // 'settings' => array( - // 'global' => array( - // 'color' => array( - // 'palette' => array( - // array( - // 'name' => 'Red', - // 'slug' => 'red', - // 'color' => '#ff0000', - // ), - // array( - // 'name' => 'Green', - // 'slug' => 'green', - // 'color' => '#00ff00', - // ), - // array( - // 'name' => 'Blue', - // 'slug' => 'blue', - // 'color' => '#0000ff', - // ), - // ), - // ), - // ), - // ), - // ); - // $this->assertEqualSetsWithIndex( $expected, $result ); - // } + function test_remove_insecure_properties_removes_non_preset_settings() { + $theme_json = new WP_Theme_JSON( + array( + 'settings' => array( + 'global' => array( + 'color' => array( + 'custom' => true, + 'palette' => array( + array( + 'name' => 'Red', + 'slug' => 'red', + 'color' => '#ff0000', + ), + array( + 'name' => 'Green', + 'slug' => 'green', + 'color' => '#00ff00', + ), + array( + 'name' => 'Blue', + 'slug' => 'blue', + 'color' => '#0000ff', + ), + ), + ), + 'spacing' => array( + 'customPadding' => false, + ), + ), + ), + ), + true + ); + $theme_json->remove_insecure_properties(); + $result = $theme_json->get_raw_data(); + $expected = array( + 'settings' => array( + 'global' => array( + 'color' => array( + 'palette' => array( + array( + 'name' => 'Red', + 'slug' => 'red', + 'color' => '#ff0000', + ), + array( + 'name' => 'Green', + 'slug' => 'green', + 'color' => '#00ff00', + ), + array( + 'name' => 'Blue', + 'slug' => 'blue', + 'color' => '#0000ff', + ), + ), + ), + ), + ), + ); + $this->assertEqualSetsWithIndex( $expected, $result ); + } function test_remove_insecure_properties_removes_unsafe_preset_settings() { $theme_json = new WP_Theme_JSON( From f27105baf680e5989a7c404ec1c4648f51637bae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Thu, 21 Jan 2021 18:06:21 +0100 Subject: [PATCH 40/65] Consolidate back keys --- lib/class-wp-theme-json.php | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index 1400d98df0ac63..4c95845f698487 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -181,8 +181,7 @@ class WP_Theme_JSON { */ const PRESETS_METADATA = array( array( - 'path_settings' => array( 'color', 'palette' ), - 'path' => array( 'settings', 'color', 'palette' ), + 'path' => array( 'color', 'palette' ), 'value_key' => 'color', 'css_var_infix' => 'color', 'classes' => array( @@ -197,8 +196,7 @@ class WP_Theme_JSON { ), ), array( - 'path_settings' => array( 'color', 'gradients' ), - 'path' => array( 'settings', 'color', 'gradients' ), + 'path' => array( 'color', 'gradients' ), 'value_key' => 'gradient', 'css_var_infix' => 'gradient', 'classes' => array( @@ -209,8 +207,7 @@ class WP_Theme_JSON { ), ), array( - 'path_settings' => array( 'typography', 'fontSizes' ), - 'path' => array( 'settings', 'typography', 'fontSizes' ), + 'path' => array( 'typography', 'fontSizes' ), 'value_key' => 'size', 'css_var_infix' => 'font-size', 'classes' => array( @@ -221,7 +218,7 @@ class WP_Theme_JSON { ), ), array( - 'path_settings' => array( 'typography', 'fontFamilies' ), + 'path' => array( 'typography', 'fontFamilies' ), 'value_key' => 'fontFamily', 'css_var_infix' => 'font-family', 'classes' => array(), @@ -753,7 +750,7 @@ private static function compute_preset_classes( &$stylesheet, $settings, $select } foreach ( self::PRESETS_METADATA as $preset ) { - $values = gutenberg_experimental_get( $settings, $preset['path_settings'], array() ); + $values = gutenberg_experimental_get( $settings, $preset['path'], array() ); foreach ( $values as $value ) { foreach ( $preset['classes'] as $class ) { $stylesheet .= self::to_ruleset( @@ -789,7 +786,7 @@ private static function compute_preset_classes( &$stylesheet, $settings, $select */ private static function compute_preset_vars( &$declarations, $settings ) { foreach ( self::PRESETS_METADATA as $preset ) { - $values = gutenberg_experimental_get( $settings, $preset['path_settings'], array() ); + $values = gutenberg_experimental_get( $settings, $preset['path'], array() ); foreach ( $values as $value ) { $declarations[] = array( 'name' => '--wp--preset--' . $preset['css_var_infix'] . '--' . $value['slug'], @@ -1082,7 +1079,7 @@ public function remove_insecure_properties() { foreach ( self::PRESETS_METADATA as $preset_metadata ) { $current_preset = gutenberg_experimental_get( $this->theme_json['settings'][ $block_selector], - $preset_metadata['path_settings'], + $preset_metadata['path'], null ); if ( null !== $current_preset ) { @@ -1116,7 +1113,7 @@ public function remove_insecure_properties() { } } if ( ! empty( $escaped_preset ) ) { - gutenberg_experimental_set( $escaped_settings, $preset_metadata['path_settings'], $escaped_preset ); + gutenberg_experimental_set( $escaped_settings, $preset_metadata['path'], $escaped_preset ); } } } From ddeb87a316696832f4c626c49c72e70b081b2070 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Thu, 21 Jan 2021 18:16:45 +0100 Subject: [PATCH 41/65] Rename context to block --- lib/class-wp-theme-json.php | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index 4c95845f698487..7bbfb278b982bc 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -28,21 +28,21 @@ class WP_Theme_JSON { private static $blocks_metadata = null; /** - * The name of the global context. + * The name of the global block. * * @var string */ const GLOBAL_NAME = 'global'; /** - * The CSS selector for the global context. + * The CSS selector for the global block. * * @var string */ const GLOBAL_SELECTOR = ':root'; /** - * The supported properties of the global context. + * The supported properties of the global block. * * @var array */ @@ -61,12 +61,12 @@ class WP_Theme_JSON { ); /** - * Data schema of each context within a theme.json. + * Data schema of each block within a theme.json. * * Example: * * { - * 'context-one': { + * 'block-one': { * 'styles': { * 'color': { * 'background': 'color' @@ -78,7 +78,7 @@ class WP_Theme_JSON { * } * } * }, - * 'context-two': { + * 'block-two': { * 'styles': { * 'color': { * 'link': 'color' @@ -164,7 +164,7 @@ class WP_Theme_JSON { * * This contains the necessary metadata to process them: * - * - path => where to find the preset in a theme.json context + * - path => where to find the preset in a theme.json block * * - value_key => the key that represents the value * @@ -690,7 +690,7 @@ private static function has_properties( $metadata ) { * * @param array $declarations Holds the existing declarations. * @param array $styles Styles to process. - * @param array $supports Supports information for this context. + * @param array $supports Supports information for this block. */ private static function compute_style_properties( &$declarations, $styles, $supports ) { if ( empty( $styles ) ) { @@ -864,15 +864,15 @@ function ( $carry, $element ) { } /** - * Converts each context into a list of rulesets + * Converts each styles section into a list of rulesets * to be appended to the stylesheet. * These rulesets contain all the css variables (custom variables and preset variables). * * See glossary at https://developer.mozilla.org/en-US/docs/Web/CSS/Syntax * - * For each context this creates a new ruleset such as: + * For each section this creates a new ruleset such as: * - * context-selector { + * block-selector { * --wp--preset--category--slug: value; * --wp--custom--variable: value; * } @@ -899,14 +899,14 @@ private function get_css_variables() { } /** - * Converts each context into a list of rulesets + * Converts each style section into a list of rulesets * containing the block styles to be appended to the stylesheet. * * See glossary at https://developer.mozilla.org/en-US/docs/Web/CSS/Syntax * - * For each context this creates a new ruleset such as: + * For each section this creates a new ruleset such as: * - * context-selector { + * block-selector { * style-property-one: value; * } * @@ -959,7 +959,7 @@ private function get_block_styles() { } /** - * Returns the existing settings for each context. + * Returns the existing settings for each block. * * Example: * @@ -976,7 +976,7 @@ private function get_block_styles() { * } * } * - * @return array Settings per context. + * @return array Settings per block. */ public function get_settings() { return $this->theme_json['settings']; From d14d14d6119877c7588e70518711fcdc609fccd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Thu, 21 Jan 2021 18:18:58 +0100 Subject: [PATCH 42/65] Test for custom css vars as well --- lib/class-wp-theme-json.php | 2 +- phpunit/class-wp-theme-json-test.php | 26 +++++++++++++++++--------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index 7bbfb278b982bc..2577517a9a8380 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -889,7 +889,7 @@ private function get_css_variables() { $selector = $metadata[ $block_selector ]['selector']; $declarations = array(); - self::compute_preset_vars( $declarations, $settings ); + // self::compute_preset_vars( $declarations, $settings ); self::compute_theme_vars( $declarations, $settings ); // Attach the ruleset for style and custom properties. diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index c7a4a65e0c00cb..493790758e4f6f 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -256,22 +256,30 @@ function test_get_stylesheet() { 'bottom' => '24px', ), ), + 'custom' => array( + "base-font" => 16, + "line-height" => array( + "small" => 1.2, + "medium" => 1.4, + "large" => 1.8 + ), + ), ), ), 'misc' => 'value', ) ); + // $this->assertEquals( + // ':root{--wp--preset--color--grey: grey;--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px; --wp--custom--base-font: 16; --wp--custom--line-height--small: 1.2; --wp--custom--line-height--medium: 1.4; --wp--custom--line-height--large: 1.8;}:root{--wp--style--color--link: #111;color: var(--wp--preset--color--grey);}.has-grey-color{color: grey;}.has-grey-background-color{background-color: grey;}.wp-block-group{padding-top: 12px;padding-bottom: 24px;}', + // $theme_json->get_stylesheet() + // ); + // $this->assertEquals( + // ':root{--wp--style--color--link: #111;color: var(--wp--preset--color--grey);}.has-grey-color{color: grey;}.has-grey-background-color{background-color: grey;}.wp-block-group{padding-top: 12px;padding-bottom: 24px;}', + // $theme_json->get_stylesheet( 'block_styles' ) + // ); $this->assertEquals( - ':root{--wp--preset--color--grey: grey;--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}:root{--wp--style--color--link: #111;color: var(--wp--preset--color--grey);}.has-grey-color{color: grey;}.has-grey-background-color{background-color: grey;}.wp-block-group{padding-top: 12px;padding-bottom: 24px;}', - $theme_json->get_stylesheet() - ); - $this->assertEquals( - ':root{--wp--style--color--link: #111;color: var(--wp--preset--color--grey);}.has-grey-color{color: grey;}.has-grey-background-color{background-color: grey;}.wp-block-group{padding-top: 12px;padding-bottom: 24px;}', - $theme_json->get_stylesheet( 'block_styles' ) - ); - $this->assertEquals( - ':root{--wp--preset--color--grey: grey;--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}', + ':root{ --wp--custom--base-font: 16; --wp--custom--line-height--small: 1.2; --wp--custom--line-height--medium: 1.4; --wp--custom--line-height--large: 1.8;}', $theme_json->get_stylesheet( 'css_variables' ) ); } From 8b3acf73d18c0e9914bfed96af6029980816d06a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Thu, 21 Jan 2021 18:36:24 +0100 Subject: [PATCH 43/65] Fix custom --- lib/class-wp-theme-json.php | 4 ++-- phpunit/class-wp-theme-json-test.php | 36 +++++++++++++++------------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index 2577517a9a8380..56ba03d3fd82d2 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -814,7 +814,7 @@ private static function compute_preset_vars( &$declarations, $settings ) { * @param array $settings Settings to process. */ private static function compute_theme_vars( &$declarations, $settings ) { - $custom_values = gutenberg_experimental_get( $context, array( 'custom' ) ); + $custom_values = gutenberg_experimental_get( $settings, array( 'custom' ) ); $css_vars = self::flatten_tree( $custom_values ); foreach ( $css_vars as $key => $value ) { $declarations[] = array( @@ -889,7 +889,7 @@ private function get_css_variables() { $selector = $metadata[ $block_selector ]['selector']; $declarations = array(); - // self::compute_preset_vars( $declarations, $settings ); + self::compute_preset_vars( $declarations, $settings ); self::compute_theme_vars( $declarations, $settings ); // Attach the ruleset for style and custom properties. diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index 493790758e4f6f..f680fc41ea65af 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -240,6 +240,16 @@ function test_get_stylesheet() { ), 'misc' => 'value', ), + 'core/group' => array( + 'custom' => array( + 'base-font' => 16, + 'line-height' => array( + 'small' => 1.2, + 'medium' => 1.4, + 'large' => 1.8 + ), + ), + ), ), 'styles' => array( 'global' => array( @@ -256,30 +266,22 @@ function test_get_stylesheet() { 'bottom' => '24px', ), ), - 'custom' => array( - "base-font" => 16, - "line-height" => array( - "small" => 1.2, - "medium" => 1.4, - "large" => 1.8 - ), - ), ), ), 'misc' => 'value', ) ); - // $this->assertEquals( - // ':root{--wp--preset--color--grey: grey;--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px; --wp--custom--base-font: 16; --wp--custom--line-height--small: 1.2; --wp--custom--line-height--medium: 1.4; --wp--custom--line-height--large: 1.8;}:root{--wp--style--color--link: #111;color: var(--wp--preset--color--grey);}.has-grey-color{color: grey;}.has-grey-background-color{background-color: grey;}.wp-block-group{padding-top: 12px;padding-bottom: 24px;}', - // $theme_json->get_stylesheet() - // ); - // $this->assertEquals( - // ':root{--wp--style--color--link: #111;color: var(--wp--preset--color--grey);}.has-grey-color{color: grey;}.has-grey-background-color{background-color: grey;}.wp-block-group{padding-top: 12px;padding-bottom: 24px;}', - // $theme_json->get_stylesheet( 'block_styles' ) - // ); $this->assertEquals( - ':root{ --wp--custom--base-font: 16; --wp--custom--line-height--small: 1.2; --wp--custom--line-height--medium: 1.4; --wp--custom--line-height--large: 1.8;}', + ':root{--wp--preset--color--grey: grey;--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}.wp-block-group{--wp--custom--base-font: 16;--wp--custom--line-height--small: 1.2;--wp--custom--line-height--medium: 1.4;--wp--custom--line-height--large: 1.8;}:root{--wp--style--color--link: #111;color: var(--wp--preset--color--grey);}.has-grey-color{color: grey;}.has-grey-background-color{background-color: grey;}.wp-block-group{padding-top: 12px;padding-bottom: 24px;}', + $theme_json->get_stylesheet() + ); + $this->assertEquals( + ':root{--wp--style--color--link: #111;color: var(--wp--preset--color--grey);}.has-grey-color{color: grey;}.has-grey-background-color{background-color: grey;}.wp-block-group{padding-top: 12px;padding-bottom: 24px;}', + $theme_json->get_stylesheet( 'block_styles' ) + ); + $this->assertEquals( + ':root{--wp--preset--color--grey: grey;--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}.wp-block-group{--wp--custom--base-font: 16;--wp--custom--line-height--small: 1.2;--wp--custom--line-height--medium: 1.4;--wp--custom--line-height--large: 1.8;}', $theme_json->get_stylesheet( 'css_variables' ) ); } From 716c912bb527ed680e8929d4059919ba34669b19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Thu, 21 Jan 2021 18:47:10 +0100 Subject: [PATCH 44/65] Update comments --- lib/class-wp-theme-json.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index 56ba03d3fd82d2..02962283c28b30 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -164,7 +164,7 @@ class WP_Theme_JSON { * * This contains the necessary metadata to process them: * - * - path => where to find the preset in a theme.json block + * - path => where to find the preset within the settings section * * - value_key => the key that represents the value * @@ -306,12 +306,12 @@ public function __construct( $theme_json = array() ) { $block_metadata = $this->get_blocks_metadata(); foreach( [ 'settings', 'styles' ] as $key => $subtree ) { - // Remove settings & styles if they aren't arrays. + // Remove settings & styles subtrees if they aren't arrays. if ( isset( $this->theme_json[ $subtree ] ) && ! is_array( $this->theme_json[ $subtree ] ) ) { unset( $this->theme_json[ $subtree ] ); } - // Remove block selectors within settings & styles if that aren't registered. + // Remove block selectors subtrees declared within settings & styles if that aren't registered. if ( isset( $this->theme_json[ $subtree ] ) ) { $this->theme_json[ $subtree ] = array_intersect_key( $this->theme_json[ $subtree ], $block_metadata ); } @@ -399,10 +399,12 @@ private static function to_property( $property ) { * Returns a mapping on metadata properties to avoid having to constantly * transforms properties between camel case and kebab. * - * @return array Containing three mappings - * "to_kebab_case" mapping properties in camel case to + * @return array Containing two mappings: + * + * - "to_kebab_case" mapping properties in camel case to * properties in kebab case e.g: "paddingTop" to "padding-top". - * "to_property" mapping properties in kebab case to + * + * - "to_property" mapping properties in kebab case to * the main properties in camel case e.g: "padding-top" to "padding". */ private static function get_case_mappings() { @@ -705,6 +707,7 @@ private static function compute_style_properties( &$declarations, $styles, $supp // Some properties can be shorthand properties, meaning that // they contain multiple values instead of a single one. + // An example of this is the padding property, see self::SCHEMA. if ( self::has_properties( $metadata ) ) { foreach ( $metadata['properties'] as $property ) { $properties[] = array( @@ -1010,7 +1013,7 @@ public function merge( $incoming ) { $this->theme_json = array_replace_recursive( $this->theme_json, $incoming_data ); // The array_replace_recursive algorithm merges at the leaf level. - // This means that when a leaf value is actually an array, + // This means that when a leaf value is an array, // the incoming array won't replace the existing, // but the numeric indexes are used for replacement. // @@ -1102,7 +1105,6 @@ public function remove_insecure_properties() { } } } else { - // font family $property = $preset_metadata['css_var_infix']; $style_to_validate = $property . ': ' . $value; $single_preset_is_valid = esc_html( safecss_filter_attr( $style_to_validate ) ) === $style_to_validate; From 0d41973399fa54243616542f655ae19b89909924 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Fri, 22 Jan 2021 18:27:19 +0100 Subject: [PATCH 45/65] Adapt translation logic to new shape --- lib/class-wp-theme-json-resolver.php | 13 ++++--- lib/experimental-i18n-theme.json | 56 ++++++++++++++-------------- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/lib/class-wp-theme-json-resolver.php b/lib/class-wp-theme-json-resolver.php index 721aa77b046297..c47bd49c09e7ff 100644 --- a/lib/class-wp-theme-json-resolver.php +++ b/lib/class-wp-theme-json-resolver.php @@ -110,7 +110,6 @@ private static function get_presets_to_translate() { if ( null === $theme_json_i18n ) { $file_structure = self::get_from_file( __DIR__ . '/experimental-i18n-theme.json' ); $theme_json_i18n = self::theme_json_i18_file_structure_to_preset_paths( $file_structure ); - } return $theme_json_i18n; } @@ -124,28 +123,32 @@ private static function get_presets_to_translate() { */ private static function translate_presets( &$theme_json_structure, $domain = 'default' ) { $preset_to_translate = self::get_presets_to_translate(); - foreach ( $theme_json_structure as &$context_value ) { - if ( empty( $context_value ) ) { + foreach ( $theme_json_structure['settings'] as &$settings ) { + if ( empty( $settings ) ) { continue; } + foreach ( $preset_to_translate as $preset ) { $path = $preset['path']; $translatable_keys = $preset['translatable_keys']; - $array_to_translate = gutenberg_experimental_get( $context_value, $path, null ); + $array_to_translate = gutenberg_experimental_get( $settings, $path, null ); if ( null === $array_to_translate ) { continue; } + foreach ( $array_to_translate as &$item_to_translate ) { foreach ( $translatable_keys as $translatable_key ) { if ( empty( $item_to_translate[ $translatable_key ] ) ) { continue; } + // phpcs:ignore WordPress.WP.I18n.LowLevelTranslationFunction,WordPress.WP.I18n.NonSingularStringLiteralText,WordPress.WP.I18n.NonSingularStringLiteralDomain $item_to_translate[ $translatable_key ] = translate( $item_to_translate[ $translatable_key ], $domain ); // phpcs:enable } } - gutenberg_experimental_set( $context_value, $path, $array_to_translate ); + + gutenberg_experimental_set( $settings, $path, $array_to_translate ); } } } diff --git a/lib/experimental-i18n-theme.json b/lib/experimental-i18n-theme.json index 4731a59df0e976..6d5db8d2f21284 100644 --- a/lib/experimental-i18n-theme.json +++ b/lib/experimental-i18n-theme.json @@ -1,32 +1,30 @@ { - "settings": { - "typography": { - "fontSizes": [ - "name" - ], - "fontStyles": [ - "name" - ], - "fontWeights": [ - "name" - ], - "fontFamilies": [ - "name" - ], - "textTransforms": [ - "name" - ], - "textDecorations": [ - "name" - ] - }, - "color": { - "palette": [ - "name" - ], - "gradients": [ - "name" - ] - } + "typography": { + "fontSizes": [ + "name" + ], + "fontStyles": [ + "name" + ], + "fontWeights": [ + "name" + ], + "fontFamilies": [ + "name" + ], + "textTransforms": [ + "name" + ], + "textDecorations": [ + "name" + ] + }, + "color": { + "palette": [ + "name" + ], + "gradients": [ + "name" + ] } } From 138092f43cabb271be093f4e75e717d281c778e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Fri, 22 Jan 2021 18:29:17 +0100 Subject: [PATCH 46/65] Adapt preset defaults to new shape --- lib/class-wp-theme-json-resolver.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/class-wp-theme-json-resolver.php b/lib/class-wp-theme-json-resolver.php index c47bd49c09e7ff..74a2df40dcbe91 100644 --- a/lib/class-wp-theme-json-resolver.php +++ b/lib/class-wp-theme-json-resolver.php @@ -181,8 +181,8 @@ private static function get_core_origin() { 'vivid-cyan-blue' => __( 'Vivid cyan blue', 'gutenberg' ), 'vivid-purple' => __( 'Vivid purple', 'gutenberg' ), ); - if ( ! empty( $config['global']['settings']['color']['palette'] ) ) { - foreach ( $config['global']['settings']['color']['palette'] as &$color ) { + if ( ! empty( $config['settings']['global']['color']['palette'] ) ) { + foreach ( $config['settings']['global']['color']['palette'] as &$color ) { $color['name'] = $default_colors_i18n[ $color['slug'] ]; } } @@ -201,8 +201,8 @@ private static function get_core_origin() { 'electric-grass' => __( 'Electric grass', 'gutenberg' ), 'midnight' => __( 'Midnight', 'gutenberg' ), ); - if ( ! empty( $config['global']['settings']['color']['gradients'] ) ) { - foreach ( $config['global']['settings']['color']['gradients'] as &$gradient ) { + if ( ! empty( $config['settings']['global']['color']['gradients'] ) ) { + foreach ( $config['settings']['global']['color']['gradients'] as &$gradient ) { $gradient['name'] = $default_gradients_i18n[ $gradient['slug'] ]; } } @@ -214,8 +214,8 @@ private static function get_core_origin() { 'large' => __( 'Large', 'gutenberg' ), 'huge' => __( 'Huge', 'gutenberg' ), ); - if ( ! empty( $config['global']['settings']['typography']['fontSizes'] ) ) { - foreach ( $config['global']['settings']['typography']['fontSizes'] as &$font_size ) { + if ( ! empty( $config['settings']['global']['typography']['fontSizes'] ) ) { + foreach ( $config['settings']['global']['typography']['fontSizes'] as &$font_size ) { $font_size['name'] = $default_font_sizes_i18n[ $font_size['slug'] ]; } } From d863d6cdc2bd568185dc5259bcf0891fc09eea59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Fri, 22 Jan 2021 18:34:47 +0100 Subject: [PATCH 47/65] Adapt preset defaults to new shape --- lib/global-styles.php | 64 +++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/lib/global-styles.php b/lib/global-styles.php index 5aab9277715e46..0f717938ae0789 100644 --- a/lib/global-styles.php +++ b/lib/global-styles.php @@ -23,59 +23,59 @@ function gutenberg_experimental_global_styles_has_theme_json_support() { */ function gutenberg_experimental_global_styles_get_theme_support_settings( $settings ) { $theme_settings = array(); - $theme_settings['global'] = array(); - $theme_settings['global']['settings'] = array(); + $theme_settings['settings'] = array(); + $theme_settings['settings']['global'] = array(); // Deprecated theme supports. if ( isset( $settings['disableCustomColors'] ) ) { - if ( ! isset( $theme_settings['global']['settings']['color'] ) ) { - $theme_settings['global']['settings']['color'] = array(); + if ( ! isset( $theme_settings['settings']['global']['color'] ) ) { + $theme_settings['settings']['global']['color'] = array(); } - $theme_settings['global']['settings']['color']['custom'] = ! $settings['disableCustomColors']; + $theme_settings['settings']['global']['color']['custom'] = ! $settings['disableCustomColors']; } if ( isset( $settings['disableCustomGradients'] ) ) { - if ( ! isset( $theme_settings['global']['settings']['color'] ) ) { - $theme_settings['global']['settings']['color'] = array(); + if ( ! isset( $theme_settings['settings']['global']['color'] ) ) { + $theme_settings['settings']['global']['color'] = array(); } - $theme_settings['global']['settings']['color']['customGradient'] = ! $settings['disableCustomGradients']; + $theme_settings['settings']['global']['color']['customGradient'] = ! $settings['disableCustomGradients']; } if ( isset( $settings['disableCustomFontSizes'] ) ) { - if ( ! isset( $theme_settings['global']['settings']['typography'] ) ) { - $theme_settings['global']['settings']['typography'] = array(); + if ( ! isset( $theme_settings['settings']['global']['typography'] ) ) { + $theme_settings['settings']['global']['typography'] = array(); } - $theme_settings['global']['settings']['typography']['customFontSize'] = ! $settings['disableCustomFontSizes']; + $theme_settings['settings']['global']['typography']['customFontSize'] = ! $settings['disableCustomFontSizes']; } if ( isset( $settings['enableCustomLineHeight'] ) ) { - if ( ! isset( $theme_settings['global']['settings']['typography'] ) ) { - $theme_settings['global']['settings']['typography'] = array(); + if ( ! isset( $theme_settings['settings']['global']['typography'] ) ) { + $theme_settings['settings']['global']['typography'] = array(); } - $theme_settings['global']['settings']['typography']['customLineHeight'] = $settings['enableCustomLineHeight']; + $theme_settings['settings']['global']['typography']['customLineHeight'] = $settings['enableCustomLineHeight']; } if ( isset( $settings['enableCustomUnits'] ) ) { - if ( ! isset( $theme_settings['global']['settings']['spacing'] ) ) { - $theme_settings['global']['settings']['spacing'] = array(); + if ( ! isset( $theme_settings['settings']['global']['spacing'] ) ) { + $theme_settings['settings']['global']['spacing'] = array(); } - $theme_settings['global']['settings']['spacing']['units'] = ( true === $settings['enableCustomUnits'] ) ? + $theme_settings['settings']['global']['spacing']['units'] = ( true === $settings['enableCustomUnits'] ) ? array( 'px', 'em', 'rem', 'vh', 'vw' ) : $settings['enableCustomUnits']; } if ( isset( $settings['colors'] ) ) { - if ( ! isset( $theme_settings['global']['settings']['color'] ) ) { - $theme_settings['global']['settings']['color'] = array(); + if ( ! isset( $theme_settings['settings']['global']['color'] ) ) { + $theme_settings['settings']['global']['color'] = array(); } - $theme_settings['global']['settings']['color']['palette'] = $settings['colors']; + $theme_settings['settings']['global']['color']['palette'] = $settings['colors']; } if ( isset( $settings['gradients'] ) ) { - if ( ! isset( $theme_settings['global']['settings']['color'] ) ) { - $theme_settings['global']['settings']['color'] = array(); + if ( ! isset( $theme_settings['settings']['global']['color'] ) ) { + $theme_settings['settings']['global']['color'] = array(); } - $theme_settings['global']['settings']['color']['gradients'] = $settings['gradients']; + $theme_settings['settings']['global']['color']['gradients'] = $settings['gradients']; } if ( isset( $settings['fontSizes'] ) ) { @@ -86,25 +86,25 @@ function gutenberg_experimental_global_styles_get_theme_support_settings( $setti $font_size['size'] = $font_size['size'] . 'px'; } } - if ( ! isset( $theme_settings['global']['settings']['typography'] ) ) { - $theme_settings['global']['settings']['typography'] = array(); + if ( ! isset( $theme_settings['settings']['global']['typography'] ) ) { + $theme_settings['settings']['global']['typography'] = array(); } - $theme_settings['global']['settings']['typography']['fontSizes'] = $font_sizes; + $theme_settings['settings']['global']['typography']['fontSizes'] = $font_sizes; } // Things that didn't land in core yet, so didn't have a setting assigned. if ( current( (array) get_theme_support( 'custom-spacing' ) ) ) { - if ( ! isset( $theme_settings['global']['settings']['spacing'] ) ) { - $theme_settings['global']['settings']['spacing'] = array(); + if ( ! isset( $theme_settings['settings']['global']['spacing'] ) ) { + $theme_settings['settings']['global']['spacing'] = array(); } - $theme_settings['global']['settings']['spacing']['customPadding'] = true; + $theme_settings['settings']['global']['spacing']['customPadding'] = true; } if ( current( (array) get_theme_support( 'experimental-link-color' ) ) ) { - if ( ! isset( $theme_settings['global']['settings']['color'] ) ) { - $theme_settings['global']['settings']['color'] = array(); + if ( ! isset( $theme_settings['settings']['global']['color'] ) ) { + $theme_settings['settings']['global']['color'] = array(); } - $theme_settings['global']['settings']['color']['link'] = true; + $theme_settings['settings']['global']['color']['link'] = true; } return $theme_settings; From a1cb0e48597e1e16d59f597f8e6d48f5b75c55a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Fri, 22 Jan 2021 18:38:55 +0100 Subject: [PATCH 48/65] Protect against theme.json with different shape or empty settings --- lib/class-wp-theme-json-resolver.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/class-wp-theme-json-resolver.php b/lib/class-wp-theme-json-resolver.php index 74a2df40dcbe91..35bc447b0843d0 100644 --- a/lib/class-wp-theme-json-resolver.php +++ b/lib/class-wp-theme-json-resolver.php @@ -122,6 +122,10 @@ private static function get_presets_to_translate() { * Default 'default'. */ private static function translate_presets( &$theme_json_structure, $domain = 'default' ) { + if ( ! isset( $theme_json_structure['settings'] ) ) { + return; + } + $preset_to_translate = self::get_presets_to_translate(); foreach ( $theme_json_structure['settings'] as &$settings ) { if ( empty( $settings ) ) { From 2f395f43ac27d7e10021aa2c1229c9b28347a512 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Fri, 22 Jan 2021 18:46:56 +0100 Subject: [PATCH 49/65] Protect against different theme.json shapes --- lib/class-wp-theme-json.php | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index 02962283c28b30..f31d4d97089ce4 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -884,6 +884,10 @@ function ( $carry, $element ) { */ private function get_css_variables() { $stylesheet = ''; + if ( ! isset( $this->theme_json['settings'] ) ) { + return $stylesheet; + } + $metadata = $this->get_blocks_metadata(); foreach ( $this->theme_json['settings'] as $block_selector => $settings ) { if ( empty( $metadata[ $block_selector ]['selector'] ) ) { @@ -940,7 +944,11 @@ private function get_css_variables() { */ private function get_block_styles() { $stylesheet = ''; - $metadata = $this->get_blocks_metadata(); + if ( ! isset( $this->theme_json['styles'] ) ) { + return $stylesheet; + } + + $metadata = $this->get_blocks_metadata(); foreach ( $this->theme_json['styles'] as $block_selector => $styles ) { if ( empty( $metadata[ $block_selector ]['selector'] ) || empty( $metadata[ $block_selector ]['supports'] ) ) { continue; @@ -982,7 +990,11 @@ private function get_block_styles() { * @return array Settings per block. */ public function get_settings() { - return $this->theme_json['settings']; + if ( ! isset( $this->theme_json['settings'] ) ) { + return array(); + } else { + return $this->theme_json['settings']; + } } /** @@ -1009,7 +1021,7 @@ public function get_stylesheet( $type = 'all' ) { * @param WP_Theme_JSON $incoming Data to merge. */ public function merge( $incoming ) { - $incoming_data = $incoming->get_raw_data(); + $incoming_data = $incoming->get_raw_data(); $this->theme_json = array_replace_recursive( $this->theme_json, $incoming_data ); // The array_replace_recursive algorithm merges at the leaf level. From 00d5db1a0e66323dd0fff9042101ce521f025839 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Fri, 22 Jan 2021 18:54:48 +0100 Subject: [PATCH 50/65] Fix block styles --- lib/class-wp-theme-json.php | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index f31d4d97089ce4..20c47d6c5b265d 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -944,26 +944,38 @@ private function get_css_variables() { */ private function get_block_styles() { $stylesheet = ''; - if ( ! isset( $this->theme_json['styles'] ) ) { + if ( ! isset( $this->theme_json['styles'] ) && ! isset( $this->theme_json['settings'] ) ) { return $stylesheet; } $metadata = $this->get_blocks_metadata(); - foreach ( $this->theme_json['styles'] as $block_selector => $styles ) { - if ( empty( $metadata[ $block_selector ]['selector'] ) || empty( $metadata[ $block_selector ]['supports'] ) ) { + foreach ( $metadata as $block_selector => $metadata ) { + if ( empty( $metadata['selector'] ) || empty( $metadata['supports'] ) ) { continue; } - $selector = $metadata[ $block_selector ]['selector']; - $supports = $metadata[ $block_selector ]['supports']; + $selector = $metadata['selector']; + $supports = $metadata['supports']; $declarations = array(); - self::compute_style_properties( $declarations, $styles, $supports ); + if ( isset( $this->theme_json['styles'][ $block_selector ] ) ) { + self::compute_style_properties( + $declarations, + $this->theme_json['styles'][ $block_selector ], + $supports + ); + } $stylesheet .= self::to_ruleset( $selector, $declarations ); // Attach the rulesets for the classes. - self::compute_preset_classes( $stylesheet, $this->theme_json['settings'][ $block_selector ], $selector ); + if ( isset( $this->theme_json['settings'][ $block_selector ] ) ) { + self::compute_preset_classes( + $stylesheet, + $this->theme_json['settings'][ $block_selector ], + $selector + ); + } } return $stylesheet; From d3195a6cde18a4394e096521ab14fd7ab0e188b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Mon, 25 Jan 2021 12:53:35 +0100 Subject: [PATCH 51/65] add task/todo --- .../edit-site/src/components/editor/global-styles-provider.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/edit-site/src/components/editor/global-styles-provider.js b/packages/edit-site/src/components/editor/global-styles-provider.js index c24a08964e6de3..1d199f09631aa2 100644 --- a/packages/edit-site/src/components/editor/global-styles-provider.js +++ b/packages/edit-site/src/components/editor/global-styles-provider.js @@ -142,6 +142,9 @@ export default function GlobalStylesProvider( { children, baseStyles } ) { if ( ! newUserStyles.isGlobalStylesUserThemeJSON ) { newUserStyles = EMPTY_CONTENT; } + // TODO: we probably want to check here that the shape is what we want + // This is, settings & styles are top-level keys, or perhaps a version. + // As to avoid merging trees that are different. const newMergedStyles = mergeWith( {}, baseStyles, From 523d62d7febe3acbbe2012bef3d278f6fcb0b4b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Mon, 25 Jan 2021 13:02:40 +0100 Subject: [PATCH 52/65] Update getSetting / setSetting --- .../src/components/editor/global-styles-provider.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/edit-site/src/components/editor/global-styles-provider.js b/packages/edit-site/src/components/editor/global-styles-provider.js index 1d199f09631aa2..4c3aa1dcf5ac80 100644 --- a/packages/edit-site/src/components/editor/global-styles-provider.js +++ b/packages/edit-site/src/components/editor/global-styles-provider.js @@ -162,13 +162,13 @@ export default function GlobalStylesProvider( { children, baseStyles } ) { () => ( { contexts, getSetting: ( context, path ) => - get( userStyles?.[ context ]?.settings, path ), + get( userStyles?.settings?.[ context ], path ), setSetting: ( context, path, newValue ) => { const newContent = { ...userStyles }; - let contextSettings = newContent?.[ context ]?.settings; + let contextSettings = newContent?.settings?.[ context ]; if ( ! contextSettings ) { contextSettings = {}; - set( newContent, [ context, 'settings' ], contextSettings ); + set( newContent, [ 'settings', context ], contextSettings ); } set( contextSettings, path, newValue ); setContent( JSON.stringify( newContent ) ); From d153174727ca7620405306c1bf593c97da2b0376 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Mon, 25 Jan 2021 13:04:32 +0100 Subject: [PATCH 53/65] Update getStyle / setStyle --- .../src/components/editor/global-styles-provider.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/edit-site/src/components/editor/global-styles-provider.js b/packages/edit-site/src/components/editor/global-styles-provider.js index 4c3aa1dcf5ac80..c340d9b9cc1cd4 100644 --- a/packages/edit-site/src/components/editor/global-styles-provider.js +++ b/packages/edit-site/src/components/editor/global-styles-provider.js @@ -174,20 +174,20 @@ export default function GlobalStylesProvider( { children, baseStyles } ) { setContent( JSON.stringify( newContent ) ); }, getStyle: ( context, propertyName, origin = 'merged' ) => { - const styles = 'user' === origin ? userStyles : mergedStyles; + const styleOrigin = 'user' === origin ? userStyles : mergedStyles; const value = get( - styles?.[ context ]?.styles, + styleOrigin?.styles?.[ context ], STYLE_PROPERTY[ propertyName ].value ); return getValueFromVariable( mergedStyles, context, value ); }, setStyle: ( context, propertyName, newValue ) => { const newContent = { ...userStyles }; - let contextStyles = newContent?.[ context ]?.styles; + let contextStyles = newContent?.styles?.[ context ]; if ( ! contextStyles ) { contextStyles = {}; - set( newContent, [ context, 'styles' ], contextStyles ); + set( newContent, [ 'styles', context ], contextStyles ); } set( contextStyles, From 471a19bee4237fe7bad5b486f66709eafccf4830 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Mon, 25 Jan 2021 13:07:49 +0100 Subject: [PATCH 54/65] Update global styles rendered function --- .../src/components/editor/global-styles-provider.js | 3 ++- .../src/components/editor/global-styles-renderer.js | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/edit-site/src/components/editor/global-styles-provider.js b/packages/edit-site/src/components/editor/global-styles-provider.js index c340d9b9cc1cd4..3bc121b20f7cc9 100644 --- a/packages/edit-site/src/components/editor/global-styles-provider.js +++ b/packages/edit-site/src/components/editor/global-styles-provider.js @@ -174,7 +174,8 @@ export default function GlobalStylesProvider( { children, baseStyles } ) { setContent( JSON.stringify( newContent ) ); }, getStyle: ( context, propertyName, origin = 'merged' ) => { - const styleOrigin = 'user' === origin ? userStyles : mergedStyles; + const styleOrigin = + 'user' === origin ? userStyles : mergedStyles; const value = get( styleOrigin?.styles?.[ context ], diff --git a/packages/edit-site/src/components/editor/global-styles-renderer.js b/packages/edit-site/src/components/editor/global-styles-renderer.js index d2f538d9371f10..cb387fd996c85e 100644 --- a/packages/edit-site/src/components/editor/global-styles-renderer.js +++ b/packages/edit-site/src/components/editor/global-styles-renderer.js @@ -146,9 +146,9 @@ export default ( blockData, tree, type = 'all' ) => { ( styles, { selector }, context ) => { if ( type === 'all' || type === 'cssVariables' ) { const variableDeclarations = [ - ...getBlockPresetsDeclarations( tree?.[ context ] ), + ...getBlockPresetsDeclarations( tree?.settings?.[ context ] ), ...flattenTree( - tree?.[ context ]?.settings?.custom, + tree?.settings?.[ context ]?.custom, '--wp--custom--', '--' ), @@ -165,7 +165,7 @@ export default ( blockData, tree, type = 'all' ) => { if ( type === 'all' || type === 'blockStyles' ) { const blockStyleDeclarations = getBlockStylesDeclarations( blockData[ context ].supports, - tree?.[ context ]?.styles + tree?.styles?.[ context ] ); if ( blockStyleDeclarations.length > 0 ) { @@ -178,7 +178,7 @@ export default ( blockData, tree, type = 'all' ) => { const presetClasses = getBlockPresetClasses( selector, - tree?.[ context ] + tree?.settings?.[ context ] ); if ( presetClasses ) { styles.push( presetClasses ); From 2d037ba5e6dddf771dfb42295caaac8e31470d3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Mon, 25 Jan 2021 13:09:56 +0100 Subject: [PATCH 55/65] Update presets processing --- .../src/components/editor/global-styles-renderer.js | 4 +++- packages/edit-site/src/components/editor/utils.js | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/edit-site/src/components/editor/global-styles-renderer.js b/packages/edit-site/src/components/editor/global-styles-renderer.js index cb387fd996c85e..c00ab558af3af6 100644 --- a/packages/edit-site/src/components/editor/global-styles-renderer.js +++ b/packages/edit-site/src/components/editor/global-styles-renderer.js @@ -146,7 +146,9 @@ export default ( blockData, tree, type = 'all' ) => { ( styles, { selector }, context ) => { if ( type === 'all' || type === 'cssVariables' ) { const variableDeclarations = [ - ...getBlockPresetsDeclarations( tree?.settings?.[ context ] ), + ...getBlockPresetsDeclarations( + tree?.settings?.[ context ] + ), ...flattenTree( tree?.settings?.[ context ]?.custom, '--wp--custom--', diff --git a/packages/edit-site/src/components/editor/utils.js b/packages/edit-site/src/components/editor/utils.js index 1bd54dc32d675b..68bf1747cec40c 100644 --- a/packages/edit-site/src/components/editor/utils.js +++ b/packages/edit-site/src/components/editor/utils.js @@ -26,7 +26,7 @@ export const GLOBAL_CONTEXT_SUPPORTS = [ export const PRESET_METADATA = [ { - path: [ 'settings', 'color', 'palette' ], + path: [ 'color', 'palette' ], valueKey: 'color', cssVarInfix: 'color', classes: [ @@ -38,7 +38,7 @@ export const PRESET_METADATA = [ ], }, { - path: [ 'settings', 'color', 'gradients' ], + path: [ 'color', 'gradients' ], valueKey: 'gradient', cssVarInfix: 'gradient', classes: [ @@ -49,13 +49,13 @@ export const PRESET_METADATA = [ ], }, { - path: [ 'settings', 'typography', 'fontSizes' ], + path: [ 'typography', 'fontSizes' ], valueKey: 'size', cssVarInfix: 'font-size', classes: [ { classSuffix: 'font-size', propertyName: 'font-size' } ], }, { - path: [ 'settings', 'typography', 'fontFamilies' ], + path: [ 'typography', 'fontFamilies' ], valueKey: 'fontFamily', cssVarInfix: 'font-family', classes: [], From 9e173730e8b297fe5d36dcfc9c524d53d0d138e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Mon, 25 Jan 2021 17:16:10 +0100 Subject: [PATCH 56/65] Pass only the merged settings --- .../src/components/editor/global-styles-provider.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/edit-site/src/components/editor/global-styles-provider.js b/packages/edit-site/src/components/editor/global-styles-provider.js index 3bc121b20f7cc9..7b55d3b5a25051 100644 --- a/packages/edit-site/src/components/editor/global-styles-provider.js +++ b/packages/edit-site/src/components/editor/global-styles-provider.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { set, get, mapValues, mergeWith } from 'lodash'; +import { set, get, mergeWith } from 'lodash'; /** * WordPress dependencies @@ -232,10 +232,7 @@ export default function GlobalStylesProvider( { children, baseStyles } ) { isGlobalStyles: true, }, ], - __experimentalFeatures: mapValues( - mergedStyles, - ( value ) => value?.settings || {} - ), + __experimentalFeatures: mergedStyles.settings, } ); }, [ contexts, mergedStyles ] ); From a6cba44d5ee08d15fc9827ef00b7f80a46b29679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Mon, 25 Jan 2021 17:19:45 +0100 Subject: [PATCH 57/65] Format for i18n --- lib/experimental-i18n-theme.json | 42 ++++++++++++-------------------- 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/lib/experimental-i18n-theme.json b/lib/experimental-i18n-theme.json index 6d5db8d2f21284..cd8d4f2c76148d 100644 --- a/lib/experimental-i18n-theme.json +++ b/lib/experimental-i18n-theme.json @@ -1,30 +1,18 @@ { - "typography": { - "fontSizes": [ - "name" - ], - "fontStyles": [ - "name" - ], - "fontWeights": [ - "name" - ], - "fontFamilies": [ - "name" - ], - "textTransforms": [ - "name" - ], - "textDecorations": [ - "name" - ] - }, - "color": { - "palette": [ - "name" - ], - "gradients": [ - "name" - ] + "settings": { + "*": { + "typography": { + "fontSizes": [ "name" ], + "fontStyles": [ "name" ], + "fontWeights": [ "name" ], + "fontFamilies": [ "name" ], + "textTransforms": [ "name" ], + "textDecorations": [ "name" ] + }, + "color": { + "palette": [ "name" ], + "gradients": [ "name" ] + } + } } } From 4ea5f337091670d83039b291f3a0ced38ab804a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Mon, 25 Jan 2021 17:27:56 +0100 Subject: [PATCH 58/65] Add comment --- lib/class-wp-theme-json-resolver.php | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/lib/class-wp-theme-json-resolver.php b/lib/class-wp-theme-json-resolver.php index 35bc447b0843d0..5c0f4ef3e157ae 100644 --- a/lib/class-wp-theme-json-resolver.php +++ b/lib/class-wp-theme-json-resolver.php @@ -76,6 +76,32 @@ private static function get_from_file( $file_path ) { * containing the a translatable path from theme.json and an array * of properties that are translatable. * + * For example, given this input: + * + * { + * "settings": { + * "*": { + * "typography": { + * "fontSizes": [ "name" ], + * "fontStyles": [ "name" ] + * } + * } + * } + * } + * + * will return this output: + * + * [ + * 0 => [ + * 'path' => [ 'settings', '*', 'typography', 'fontSizes' ], + * 'translatable_keys' => [ 'name' ] + * ], + * 1 => [ + * 'path' => [ 'settings', '*', 'typography', 'fontStyles' ], + * 'translatable_keys' => [ 'name'] + * ] + * ] + * * @param array $file_structure_partial A part of a theme.json i18n tree. * @param array $current_path An array with a path on the theme.json i18n tree. * From 0078b355c083e6e117d3fd0a727e500470516af3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Mon, 25 Jan 2021 17:32:20 +0100 Subject: [PATCH 59/65] Adapt path to new i18-theme.json shape --- lib/class-wp-theme-json-resolver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/class-wp-theme-json-resolver.php b/lib/class-wp-theme-json-resolver.php index 5c0f4ef3e157ae..ef794281abf94d 100644 --- a/lib/class-wp-theme-json-resolver.php +++ b/lib/class-wp-theme-json-resolver.php @@ -159,7 +159,7 @@ private static function translate_presets( &$theme_json_structure, $domain = 'de } foreach ( $preset_to_translate as $preset ) { - $path = $preset['path']; + $path = array_slice( $preset['path'], 2 ) ; $translatable_keys = $preset['translatable_keys']; $array_to_translate = gutenberg_experimental_get( $settings, $path, null ); if ( null === $array_to_translate ) { From 710953a5992bc6401678a3f841fff34ba27142ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Mon, 25 Jan 2021 17:43:38 +0100 Subject: [PATCH 60/65] Fix rebase issues --- phpunit/class-wp-theme-json-test.php | 113 --------------------------- 1 file changed, 113 deletions(-) diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index f680fc41ea65af..20c66fe33c98e8 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -588,119 +588,6 @@ function test_remove_insecure_properties_removes_unsafe_sub_properties() { $this->assertEqualSetsWithIndex( $expected, $result ); } - function test_remove_insecure_properties_removes_non_preset_settings() { - $theme_json = new WP_Theme_JSON( - array( - 'settings' => array( - 'global' => array( - 'color' => array( - 'custom' => true, - 'palette' => array( - array( - 'name' => 'Red', - 'slug' => 'red', - 'color' => '#ff0000', - ), - array( - 'name' => 'Green', - 'slug' => 'green', - 'color' => '#00ff00', - ), - array( - 'name' => 'Blue', - 'slug' => 'blue', - 'color' => '#0000ff', - ), - ), - ), - ), - ), - ), - ); - - $expected = array( - 'settings' => array( - 'global' => array( - 'color' => array( - 'custom' => true, - 'customGradient' => true, - 'palette' => array( - array( - 'slug' => 'blue', - 'color' => 'blue', - ), - ), - 'gradients' => array( - array( - 'slug' => 'gradient', - 'gradient' => 'gradient', - ), - ), - ), - 'typography' => array( - 'fontSizes' => array( - array( - 'slug' => 'fontSize', - 'size' => 'fontSize', - ), - ), - 'fontFamilies' => array( - array( - 'slug' => 'fontFamily', - 'fontFamily' => 'fontFamily', - ), - ), - ), - ), - 'core/paragraph' => array( - 'color' => array( - 'custom' => false, - ), - ), - 'core/list' => array( - 'color' => array( - 'custom' => false, - ), - ), - ), - 'styles' => array( - 'global' => array( - 'typography' => array( - 'fontSize' => '12', - ), - ), - 'core/group' => array( - 'spacing' => array( - 'padding' => array( - 'top' => '12px', - 'bottom' => '12px', - ), - ), - ), - 'core/list' => array( - 'typography' => array( - 'fontSize' => '12', - ), - 'color' => array( - 'background' => 'brown', - ), - ), - ), - ); - - $theme_json = new WP_Theme_JSON( $initial ); - $theme_json->merge( new WP_Theme_JSON( $add_new_block ) ); - $theme_json->merge( new WP_Theme_JSON( $add_key_in_settings ) ); - $theme_json->merge( new WP_Theme_JSON( $update_key_in_settings ) ); - $theme_json->merge( new WP_Theme_JSON( $add_styles ) ); - $theme_json->merge( new WP_Theme_JSON( $add_key_in_styles ) ); - $theme_json->merge( new WP_Theme_JSON( $add_invalid_context ) ); - $theme_json->merge( new WP_Theme_JSON( $update_presets ) ); - $result = $theme_json->get_raw_data(); - - $this->assertEqualSetsWithIndex( $expected, $result ); - } - function test_remove_insecure_properties_removes_unsafe_styles() { $theme_json = new WP_Theme_JSON( array( From 7097e4330b2b740b3100ae0ccebc8024b7557a85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Mon, 25 Jan 2021 17:45:40 +0100 Subject: [PATCH 61/65] Fix rebase issues --- phpunit/class-wp-theme-json-test.php | 239 +++++++++------------------ 1 file changed, 81 insertions(+), 158 deletions(-) diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index 20c66fe33c98e8..44d21938b4b128 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -393,198 +393,121 @@ public function test_merge_incoming_data() { ), ); - $this->assertEqualSetsWithIndex( $expected, $result ); - } - - function test_remove_insecure_properties_removes_invalid_contexts() { - $theme_json = new WP_Theme_JSON( - array( - 'styles' => array( - 'global' => array( - 'color' => array( - 'background' => 'green', - 'text' => 'var:preset|color|dark-gray', + $update_presets = array( + 'settings' => array( + 'global' => array( + 'color' => array( + 'palette' => array( + array( + 'slug' => 'blue', + 'color' => 'blue', + ), ), - ), - '.my-class' => array( - 'color' => array( - 'background' => 'green', - 'text' => 'var:preset|color|dark-gray', + 'gradients' => array( + array( + 'slug' => 'gradient', + 'gradient' => 'gradient', + ), ), ), - ), - ), - true - ); - $theme_json->remove_insecure_properties(); - $result = $theme_json->get_raw_data(); - $expected = array( - 'styles' => array( - 'global' => array( - 'color' => array( - 'background' => 'green', - 'text' => 'var:preset|color|dark-gray', - ), - ), - ), - ); - $this->assertEqualSetsWithIndex( $expected, $result ); - } - - function test_remove_insecure_properties_removes_invalid_properties() { - $theme_json = new WP_Theme_JSON( - array( - 'styles' => array( - 'global' => array( - 'color' => array( - 'gradient' => 'linear-gradient(55deg,rgba(6,147,227,1) 0%,rgb(84,177,218) 54%,rgb(155,81,224) 100%)', - 'text' => 'var:preset|color|dark-gray', + 'typography' => array( + 'fontSizes' => array( + array( + 'slug' => 'fontSize', + 'size' => 'fontSize', + ), ), - ), - 'invalid' => array( - 'background' => 'green', - ), - ), - ), - true - ); - $theme_json->remove_insecure_properties(); - $result = $theme_json->get_raw_data(); - $expected = array( - 'styles' => array( - 'global' => array( - 'color' => array( - 'gradient' => 'linear-gradient(55deg,rgba(6,147,227,1) 0%,rgb(84,177,218) 54%,rgb(155,81,224) 100%)', - 'text' => 'var:preset|color|dark-gray', - ), - ), - ), - ); - $this->assertEqualSetsWithIndex( $expected, $result ); - } - - function test_remove_insecure_properties_removes_unsafe_properties() { - $theme_json = new WP_Theme_JSON( - array( - 'styles' => array( - 'global' => array( - 'color' => array( - 'gradient' => 'url(\'data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxMCcgaGVpZ2h0PScxMCc+PHNjcmlwdD5hbGVydCgnb2snKTwvc2NyaXB0PjxsaW5lYXJHcmFkaWVudCBpZD0nZ3JhZGllbnQnPjxzdG9wIG9mZnNldD0nMTAlJyBzdG9wLWNvbG9yPScjRjAwJy8+PHN0b3Agb2Zmc2V0PSc5MCUnIHN0b3AtY29sb3I9JyNmY2MnLz4gPC9saW5lYXJHcmFkaWVudD48cmVjdCBmaWxsPSd1cmwoI2dyYWRpZW50KScgeD0nMCcgeT0nMCcgd2lkdGg9JzEwMCUnIGhlaWdodD0nMTAwJScvPjwvc3ZnPg==\')', - 'text' => 'var:preset|color|dark-gray', + 'fontFamilies' => array( + array( + 'slug' => 'fontFamily', + 'fontFamily' => 'fontFamily', + ), ), ), - 'invalid' => array( - 'background' => 'green', - ), - ), - ), - true - ); - $theme_json->remove_insecure_properties(); - $result = $theme_json->get_raw_data(); - $expected = array( - 'styles' => array( - 'global' => array( - 'color' => array( - 'text' => 'var:preset|color|dark-gray', - ), ), ), ); - $this->assertEqualSetsWithIndex( $expected, $result ); - } - function test_remove_insecure_properties_removes_properties_when_not_allowed_in_a_context() { - $theme_json = new WP_Theme_JSON( - array( - 'styles' => array( - 'global' => array( - 'color' => array( - 'text' => 'var:preset|color|dark-gray', + $expected = array( + 'settings' => array( + 'global' => array( + 'color' => array( + 'custom' => true, + 'customGradient' => true, + 'palette' => array( + array( + 'slug' => 'blue', + 'color' => 'blue', + ), ), - 'spacing' => array( - 'padding' => array( - 'top' => '1px', - 'right' => '1px', - 'bottom' => '1px', - 'left' => '1px', + 'gradients' => array( + array( + 'slug' => 'gradient', + 'gradient' => 'gradient', ), ), ), - 'invalid' => array( - 'background' => 'green', - ), - 'core/group' => array( - 'spacing' => array( - 'padding' => array( - 'top' => '1px', - 'right' => '1px', - 'bottom' => '1px', - 'left' => '1px', + 'typography' => array( + 'fontSizes' => array( + array( + 'slug' => 'fontSize', + 'size' => 'fontSize', + ), + ), + 'fontFamilies' => array( + array( + 'slug' => 'fontFamily', + 'fontFamily' => 'fontFamily', ), ), ), ), - ), - true - ); - $theme_json->remove_insecure_properties(); - $result = $theme_json->get_raw_data(); - $expected = array( - 'styles' => array( - 'global' => array( + 'core/paragraph' => array( 'color' => array( - 'text' => 'var:preset|color|dark-gray', + 'custom' => false, ), ), - 'core/group' => array( - 'spacing' => array( - 'padding' => array( - 'top' => '1px', - 'right' => '1px', - 'bottom' => '1px', - 'left' => '1px', - ), + 'core/list' => array( + 'color' => array( + 'custom' => false, ), ), ), - ); - $this->assertEqualSetsWithIndex( $expected, $result ); - } - - function test_remove_insecure_properties_removes_unsafe_sub_properties() { - $theme_json = new WP_Theme_JSON( - array( - 'styles' => array( - 'core/group' => array( - 'spacing' => array( - 'padding' => array( - 'top' => '1px', - 'right' => '1px', - 'bottom' => 'var(--unsafe-var-y)', - 'left' => '1px', - ), - ), + 'styles' => array( + 'global' => array( + 'typography' => array( + 'fontSize' => '12', ), ), - ), - true - ); - $theme_json->remove_insecure_properties(); - $result = $theme_json->get_raw_data(); - $expected = array( - 'styles' => array( 'core/group' => array( 'spacing' => array( 'padding' => array( - 'top' => '1px', - 'right' => '1px', - 'left' => '1px', + 'top' => '12px', + 'bottom' => '12px', ), ), ), + 'core/list' => array( + 'typography' => array( + 'fontSize' => '12', + ), + 'color' => array( + 'background' => 'brown', + ), + ), ), ); + + $theme_json = new WP_Theme_JSON( $initial ); + $theme_json->merge( new WP_Theme_JSON( $add_new_block ) ); + $theme_json->merge( new WP_Theme_JSON( $add_key_in_settings ) ); + $theme_json->merge( new WP_Theme_JSON( $update_key_in_settings ) ); + $theme_json->merge( new WP_Theme_JSON( $add_styles ) ); + $theme_json->merge( new WP_Theme_JSON( $add_key_in_styles ) ); + $theme_json->merge( new WP_Theme_JSON( $add_invalid_context ) ); + $theme_json->merge( new WP_Theme_JSON( $update_presets ) ); + $result = $theme_json->get_raw_data(); + $this->assertEqualSetsWithIndex( $expected, $result ); } From 158491b24ad968437ea408b612bbc09fb07b4692 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Mon, 25 Jan 2021 17:56:28 +0100 Subject: [PATCH 62/65] fix lint issues in class-wp-theme-json-test.php --- phpunit/class-wp-theme-json-test.php | 99 ++++++++++++++-------------- 1 file changed, 50 insertions(+), 49 deletions(-) diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index 44d21938b4b128..10e567923c4e2e 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -12,25 +12,25 @@ function test_schema_validation_subtree_is_removed_if_key_invalid() { $theme_json = new WP_Theme_JSON( array( 'invalid/key' => 'content', - 'styles' => array( + 'styles' => array( 'invalid/key' => array( 'color' => array( 'custom' => 'false', ), ), - 'core/group' => array( + 'core/group' => array( 'invalid/key' => array( 'custom' => false, 'background' => 'red', ), - 'color' => array( + 'color' => array( 'invalid/key' => true, 'background' => 'red', ), - 'spacing' => array( + 'spacing' => array( 'padding' => array( 'invalid/key' => false, - 'top' => '10px', + 'top' => '10px', ), ), ), @@ -42,7 +42,7 @@ function test_schema_validation_subtree_is_removed_if_key_invalid() { $expected = array( 'styles' => array( 'core/group' => array( - 'color' => array( + 'color' => array( 'background' => 'red', ), 'spacing' => array( @@ -51,7 +51,7 @@ function test_schema_validation_subtree_is_removed_if_key_invalid() { ), ), ), - ) + ), ); $this->assertEqualSetsWithIndex( $expected, $result ); @@ -61,20 +61,20 @@ function test_schema_validation_subtree_is_removed_if_not_array() { $theme_json = new WP_Theme_JSON( array( 'settings' => 'invalid/not/array', - 'styles' => array( - 'global' => 'invalid/not/array', + 'styles' => array( + 'global' => 'invalid/not/array', 'core/paragraph' => array( 'invalid/not/array' => false, ), - 'core/group' => array( + 'core/group' => array( 'invalid/not/array' => false, - 'color' => array( + 'color' => array( 'link' => 'pink', ), - 'typography' => array( + 'typography' => array( 'invalid/key' => false, ), - 'spacing' => array( + 'spacing' => array( 'padding' => array( 'invalid/key' => '10px', ), @@ -101,25 +101,25 @@ function test_schema_validation_subtree_is_removed_if_not_array() { function test_schema_validation_subtree_is_removed_if_empty() { $theme_json = new WP_Theme_JSON( array( - 'settings' => array( + 'settings' => array( 'invalid/key' => array( 'color' => array( 'custom' => false, ), ), - 'global' => array( + 'global' => array( 'invalid/key' => false, ), ), - 'styles' => array( + 'styles' => array( 'global' => array( - 'color' => array( + 'color' => array( 'link' => 'blue', ), 'typography' => array( 'invalid/key' => false, ), - 'spacing' => array( + 'spacing' => array( 'padding' => array( 'invalid/key' => '10px', ), @@ -148,7 +148,7 @@ function test_schema_validation_subtree_is_removed_if_style_not_supported_by_blo array( 'styles' => array( 'global' => array( - 'color' => array( + 'color' => array( 'text' => 'var:preset|color|dark-gray', ), 'spacing' => array( @@ -159,10 +159,11 @@ function test_schema_validation_subtree_is_removed_if_style_not_supported_by_blo 'left' => '1px', ), ), - ) + ), ), ) ); + $actual = $theme_json->get_raw_data(); $expected = array( 'styles' => array( @@ -170,7 +171,7 @@ function test_schema_validation_subtree_is_removed_if_style_not_supported_by_blo 'color' => array( 'text' => 'var:preset|color|dark-gray', ), - ) + ), ), ); $this->assertEqualSetsWithIndex( $expected, $actual ); @@ -182,7 +183,7 @@ function test_get_settings() { array( 'settings' => array( 'global' => array( - 'color' => array( + 'color' => array( 'custom' => false, ), 'invalid/key' => 'value', @@ -215,8 +216,8 @@ function test_get_stylesheet() { // See schema at WP_Theme_JSON::SCHEMA. $theme_json = new WP_Theme_JSON( array( - 'settings' => array( - 'global' => array( + 'settings' => array( + 'global' => array( 'color' => array( 'text' => 'value', 'palette' => array( @@ -242,17 +243,17 @@ function test_get_stylesheet() { ), 'core/group' => array( 'custom' => array( - 'base-font' => 16, + 'base-font' => 16, 'line-height' => array( 'small' => 1.2, 'medium' => 1.4, - 'large' => 1.8 + 'large' => 1.8, ), ), ), ), 'styles' => array( - 'global' => array( + 'global' => array( 'color' => array( 'link' => '#111', 'text' => 'var:preset|color|grey', @@ -288,8 +289,8 @@ function test_get_stylesheet() { public function test_merge_incoming_data() { $initial = array( - 'settings' => array( - 'global' => array( + 'settings' => array( + 'global' => array( 'color' => array( 'custom' => false, 'palette' => array( @@ -327,8 +328,8 @@ public function test_merge_incoming_data() { ), ), ), - 'styles' => array( - 'core/list' => array( + 'styles' => array( + 'core/list' => array( 'typography' => array( 'fontSize' => '12', ), @@ -364,8 +365,8 @@ public function test_merge_incoming_data() { 'core/group' => array( 'spacing' => array( 'padding' => array( - 'top' => '12px' - ) + 'top' => '12px', + ), ), ), ), @@ -474,7 +475,7 @@ public function test_merge_incoming_data() { ), ), 'styles' => array( - 'global' => array( + 'global' => array( 'typography' => array( 'fontSize' => '12', ), @@ -482,12 +483,12 @@ public function test_merge_incoming_data() { 'core/group' => array( 'spacing' => array( 'padding' => array( - 'top' => '12px', + 'top' => '12px', 'bottom' => '12px', ), ), ), - 'core/list' => array( + 'core/list' => array( 'typography' => array( 'fontSize' => '12', ), @@ -515,13 +516,13 @@ function test_remove_insecure_properties_removes_unsafe_styles() { $theme_json = new WP_Theme_JSON( array( 'styles' => array( - 'core/group' => array( + 'core/group' => array( 'color' => array( 'gradient' => 'url(\'data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxMCcgaGVpZ2h0PScxMCc+PHNjcmlwdD5hbGVydCgnb2snKTwvc2NyaXB0PjxsaW5lYXJHcmFkaWVudCBpZD0nZ3JhZGllbnQnPjxzdG9wIG9mZnNldD0nMTAlJyBzdG9wLWNvbG9yPScjRjAwJy8+PHN0b3Agb2Zmc2V0PSc5MCUnIHN0b3AtY29sb3I9JyNmY2MnLz4gPC9saW5lYXJHcmFkaWVudD48cmVjdCBmaWxsPSd1cmwoI2dyYWRpZW50KScgeD0nMCcgeT0nMCcgd2lkdGg9JzEwMCUnIGhlaWdodD0nMTAwJScvPjwvc3ZnPg==\')', - 'text' => 'var:preset|color|dark-gray' + 'text' => 'var:preset|color|dark-gray', ), ), - 'invalid/key' => array( + 'invalid/key' => array( 'background' => 'green', ), ), @@ -534,7 +535,7 @@ function test_remove_insecure_properties_removes_unsafe_styles() { 'styles' => array( 'core/group' => array( 'color' => array( - 'text' => 'var:preset|color|dark-gray' + 'text' => 'var:preset|color|dark-gray', ), ), ), @@ -549,10 +550,10 @@ function test_remove_insecure_properties_removes_unsafe_styles_sub_properties() 'core/group' => array( 'spacing' => array( 'padding' => array( - 'top' => '1px', - 'right' => '1px', + 'top' => '1px', + 'right' => '1px', 'bottom' => 'var(--unsafe-var-y)', - 'left' => '1px', + 'left' => '1px', ), ), ), @@ -567,9 +568,9 @@ function test_remove_insecure_properties_removes_unsafe_styles_sub_properties() 'core/group' => array( 'spacing' => array( 'padding' => array( - 'top' => '1px', + 'top' => '1px', 'right' => '1px', - 'left' => '1px', + 'left' => '1px', ), ), ), @@ -583,8 +584,8 @@ function test_remove_insecure_properties_removes_non_preset_settings() { array( 'settings' => array( 'global' => array( - 'color' => array( - 'custom' => true, + 'color' => array( + 'custom' => true, 'palette' => array( array( 'name' => 'Red', @@ -646,7 +647,7 @@ function test_remove_insecure_properties_removes_unsafe_preset_settings() { array( 'settings' => array( 'global' => array( - 'color' => array( + 'color' => array( 'palette' => array( array( 'name' => 'Red/>ok', @@ -704,7 +705,7 @@ function test_remove_insecure_properties_removes_unsafe_preset_settings() { $expected = array( 'settings' => array( 'global' => array( - 'color' => array( + 'color' => array( 'palette' => array( array( 'name' => 'Pink', From ba940aa59f5fc459ee87f10ea1cfa7bd538d2af9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Mon, 25 Jan 2021 18:04:48 +0100 Subject: [PATCH 63/65] fix lint issues in class-wp-theme-json.php --- lib/class-wp-theme-json.php | 68 ++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index 20c47d6c5b265d..4d117715f0cd11 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -218,7 +218,7 @@ class WP_Theme_JSON { ), ), array( - 'path' => array( 'typography', 'fontFamilies' ), + 'path' => array( 'typography', 'fontFamilies' ), 'value_key' => 'fontFamily', 'css_var_infix' => 'font-family', 'classes' => array(), @@ -305,7 +305,7 @@ public function __construct( $theme_json = array() ) { $this->theme_json = array_intersect_key( $theme_json, self::SCHEMA ); $block_metadata = $this->get_blocks_metadata(); - foreach( [ 'settings', 'styles' ] as $key => $subtree ) { + foreach ( array( 'settings', 'styles' ) as $subtree ) { // Remove settings & styles subtrees if they aren't arrays. if ( isset( $this->theme_json[ $subtree ] ) && ! is_array( $this->theme_json[ $subtree ] ) ) { unset( $this->theme_json[ $subtree ] ); @@ -313,23 +313,23 @@ public function __construct( $theme_json = array() ) { // Remove block selectors subtrees declared within settings & styles if that aren't registered. if ( isset( $this->theme_json[ $subtree ] ) ) { - $this->theme_json[ $subtree ] = array_intersect_key( $this->theme_json[ $subtree ], $block_metadata ); + $this->theme_json[ $subtree ] = array_intersect_key( $this->theme_json[ $subtree ], $block_metadata ); } } - foreach( $block_metadata as $block_selector => $metadata ) { - if ( isset( $this->theme_json['styles'][ $block_selector] ) ) { + foreach ( $block_metadata as $block_selector => $metadata ) { + if ( isset( $this->theme_json['styles'][ $block_selector ] ) ) { // Remove the block selector subtree if it's not an array. - if ( ! is_array( $this->theme_json['styles'][ $block_selector] ) ) { - unset( $this->theme_json['styles'][ $block_selector] ); + if ( ! is_array( $this->theme_json['styles'][ $block_selector ] ) ) { + unset( $this->theme_json['styles'][ $block_selector ] ); continue; } // Remove the properties the block doesn't support. // This is a subset of the full styles schema. $styles_schema = self::SCHEMA['styles']; - foreach( self::PROPERTIES_METADATA as $prop_name => $prop_meta ) { - if( ! in_array( $prop_name, $metadata['supports'] ) ) { + foreach ( self::PROPERTIES_METADATA as $prop_name => $prop_meta ) { + if ( ! in_array( $prop_name, $metadata['supports'], true ) ) { unset( $styles_schema[ $prop_meta['value'][0] ][ $prop_meta['value'][1] ] ); } } @@ -344,16 +344,16 @@ public function __construct( $theme_json = array() ) { } } - if ( isset( $this->theme_json['settings'][ $block_selector] ) ) { + if ( isset( $this->theme_json['settings'][ $block_selector ] ) ) { // Remove the block selector subtree if it's not an array. - if ( ! is_array( $this->theme_json['settings'][ $block_selector] ) ) { - unset( $this->theme_json['settings'][ $block_selector] ); + if ( ! is_array( $this->theme_json['settings'][ $block_selector ] ) ) { + unset( $this->theme_json['settings'][ $block_selector ] ); continue; } // Remove the properties that aren't present in the schema. self::remove_keys_not_in_schema( - $this->theme_json[ 'settings' ][ $block_selector ], + $this->theme_json['settings'][ $block_selector ], self::SCHEMA['settings'] ); @@ -365,7 +365,7 @@ public function __construct( $theme_json = array() ) { } // Remove the settings & styles subtrees if they're empty after having processed them. - foreach( [ 'settings', 'styles' ] as $key => $subtree ) { + foreach ( array( 'settings', 'styles' ) as $subtree ) { if ( empty( $this->theme_json[ $subtree ] ) ) { unset( $this->theme_json[ $subtree ] ); } @@ -558,7 +558,7 @@ private static function get_blocks_metadata() { private static function remove_keys_not_in_schema( &$tree, $schema ) { $tree = array_intersect_key( $tree, $schema ); - foreach( $schema as $key => $data ) { + foreach ( $schema as $key => $data ) { if ( is_array( $schema[ $key ] ) && isset( $tree[ $key ] ) ) { self::remove_keys_not_in_schema( $tree[ $key ], $schema[ $key ] ); @@ -888,7 +888,7 @@ private function get_css_variables() { return $stylesheet; } - $metadata = $this->get_blocks_metadata(); + $metadata = $this->get_blocks_metadata(); foreach ( $this->theme_json['settings'] as $block_selector => $settings ) { if ( empty( $metadata[ $block_selector ]['selector'] ) ) { continue; @@ -1043,28 +1043,28 @@ public function merge( $incoming ) { // // These are the cases that have array values at the leaf levels. $block_metadata = self::get_blocks_metadata(); - foreach( $block_metadata as $block_selector => $meta ) { - // color presets: palette & gradients - if( isset( $incoming_data[ 'settings' ][ $block_selector ]['color']['palette'] ) ) { - $this->theme_json[ 'settings' ][ $block_selector ]['color']['palette'] = $incoming_data[ 'settings' ][ $block_selector ]['color']['palette']; + foreach ( $block_metadata as $block_selector => $meta ) { + // Color presets: palette & gradients. + if ( isset( $incoming_data['settings'][ $block_selector ]['color']['palette'] ) ) { + $this->theme_json['settings'][ $block_selector ]['color']['palette'] = $incoming_data['settings'][ $block_selector ]['color']['palette']; } - if( isset( $incoming_data[ 'settings' ][ $block_selector ]['color']['gradients'] ) ) { - $this->theme_json[ 'settings' ][ $block_selector ]['color']['gradients'] = $incoming_data[ 'settings' ][ $block_selector ]['color']['gradients']; + if ( isset( $incoming_data['settings'][ $block_selector ]['color']['gradients'] ) ) { + $this->theme_json['settings'][ $block_selector ]['color']['gradients'] = $incoming_data['settings'][ $block_selector ]['color']['gradients']; } - // spacing: units - if( isset( $incoming_data[ 'settings' ][ $block_selector ]['spacing']['units'] ) ) { - $this->theme_json[ 'settings' ][ $block_selector ]['spacing']['units'] = $incoming_data[ 'settings' ][ $block_selector ]['spacing']['units']; + // Spacing: units. + if ( isset( $incoming_data['settings'][ $block_selector ]['spacing']['units'] ) ) { + $this->theme_json['settings'][ $block_selector ]['spacing']['units'] = $incoming_data['settings'][ $block_selector ]['spacing']['units']; } - // typography presets: fontSizes & fontFamilies - if( isset( $incoming_data[ 'settings' ][ $block_selector ]['typography']['fontSizes'] ) ) { - $this->theme_json[ 'settings' ][ $block_selector ]['typography']['fontSizes'] = $incoming_data[ 'settings' ][ $block_selector ]['typography']['fontSizes']; + // Typography presets: fontSizes & fontFamilies. + if ( isset( $incoming_data['settings'][ $block_selector ]['typography']['fontSizes'] ) ) { + $this->theme_json['settings'][ $block_selector ]['typography']['fontSizes'] = $incoming_data['settings'][ $block_selector ]['typography']['fontSizes']; } - if( isset( $incoming_data[ 'settings' ][ $block_selector ]['typography']['fontFamilies'] ) ) { - $this->theme_json[ 'settings' ][ $block_selector ]['typography']['fontFamilies'] = $incoming_data[ 'settings' ][ $block_selector ]['typography']['fontFamilies']; + if ( isset( $incoming_data['settings'][ $block_selector ]['typography']['fontFamilies'] ) ) { + $this->theme_json['settings'][ $block_selector ]['typography']['fontFamilies'] = $incoming_data['settings'][ $block_selector ]['typography']['fontFamilies']; } - // custom section - if( isset( $incoming_data[ 'settings' ][ $block_selector ]['custom'] ) ) { - $this->theme_json[ 'settings' ][ $block_selector ]['custom'] = $incoming_data[ 'settings' ][ $block_selector ]['custom']; + // Custom section. + if ( isset( $incoming_data['settings'][ $block_selector ]['custom'] ) ) { + $this->theme_json['settings'][ $block_selector ]['custom'] = $incoming_data['settings'][ $block_selector ]['custom']; } } } @@ -1105,7 +1105,7 @@ public function remove_insecure_properties() { if ( isset( $this->theme_json['settings'][ $block_selector ] ) ) { foreach ( self::PRESETS_METADATA as $preset_metadata ) { $current_preset = gutenberg_experimental_get( - $this->theme_json['settings'][ $block_selector], + $this->theme_json['settings'][ $block_selector ], $preset_metadata['path'], null ); From aaa3edb5a55f1c8f1007477f85dd4a7905460633 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Mon, 25 Jan 2021 18:05:46 +0100 Subject: [PATCH 64/65] fix lint issues in class-wp-theme-json-resolver.php --- lib/class-wp-theme-json-resolver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/class-wp-theme-json-resolver.php b/lib/class-wp-theme-json-resolver.php index ef794281abf94d..36bcb603cccd0c 100644 --- a/lib/class-wp-theme-json-resolver.php +++ b/lib/class-wp-theme-json-resolver.php @@ -159,7 +159,7 @@ private static function translate_presets( &$theme_json_structure, $domain = 'de } foreach ( $preset_to_translate as $preset ) { - $path = array_slice( $preset['path'], 2 ) ; + $path = array_slice( $preset['path'], 2 ); $translatable_keys = $preset['translatable_keys']; $array_to_translate = gutenberg_experimental_get( $settings, $path, null ); if ( null === $array_to_translate ) { From 7f99119add425d0c4276cc49e6d87667f66f6523 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Mon, 25 Jan 2021 18:09:34 +0100 Subject: [PATCH 65/65] Adapt phpunit/class-wp-theme-json-legacy-settings-test.php --- ...lass-wp-theme-json-legacy-settings-test.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/phpunit/class-wp-theme-json-legacy-settings-test.php b/phpunit/class-wp-theme-json-legacy-settings-test.php index addadeceeccb06..5124ee3004ef0e 100644 --- a/phpunit/class-wp-theme-json-legacy-settings-test.php +++ b/phpunit/class-wp-theme-json-legacy-settings-test.php @@ -43,8 +43,8 @@ function get_editor_settings_no_theme_support() { function test_legacy_settings_blank() { $input = array(); $expected = array( - 'global' => array( - 'settings' => array(), + 'settings' => array( + 'global' => array(), ), ); @@ -56,8 +56,8 @@ function test_legacy_settings_blank() { function test_legacy_settings_no_theme_support() { $input = $this->get_editor_settings_no_theme_support(); $expected = array( - 'global' => array( - 'settings' => array( + 'settings' => array( + 'global' => array( 'color' => array( 'custom' => true, 'customGradient' => true, @@ -88,7 +88,7 @@ function test_legacy_settings_custom_units_can_be_disabled() { $actual = gutenberg_experimental_global_styles_get_theme_support_settings( $input ); - $this->assertEqualSetsWithIndex( $expected, $actual['global']['settings']['spacing'] ); + $this->assertEqualSetsWithIndex( $expected, $actual['settings']['global']['spacing'] ); } function test_legacy_settings_custom_units_can_be_enabled() { @@ -101,7 +101,7 @@ function test_legacy_settings_custom_units_can_be_enabled() { $actual = gutenberg_experimental_global_styles_get_theme_support_settings( $input ); - $this->assertEqualSetsWithIndex( $expected, $actual['global']['settings']['spacing'] ); + $this->assertEqualSetsWithIndex( $expected, $actual['settings']['global']['spacing'] ); } function test_legacy_settings_custom_units_can_be_filtered() { @@ -114,7 +114,7 @@ function test_legacy_settings_custom_units_can_be_filtered() { $actual = gutenberg_experimental_global_styles_get_theme_support_settings( $input ); - $this->assertEqualSetsWithIndex( $expected, $actual['global']['settings']['spacing'] ); + $this->assertEqualSetsWithIndex( $expected, $actual['settings']['global']['spacing'] ); } function test_legacy_settings_filled() { @@ -148,8 +148,8 @@ function test_legacy_settings_filled() { ); $expected = array( - 'global' => array( - 'settings' => array( + 'settings' => array( + 'global' => array( 'color' => array( 'custom' => false, 'customGradient' => false,