From b0f4e169dfa66c7d0287db433fea5917a8e9a9c9 Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Tue, 13 Dec 2022 16:12:27 +1100 Subject: [PATCH 01/11] Global Styles: Fix block spacing values being stripped for uses without unfiltered_html capability --- src/wp-includes/class-wp-theme-json.php | 32 +++++++++++++++ src/wp-includes/default-filters.php | 4 ++ tests/phpunit/tests/theme/wpThemeJson.php | 47 +++++++++++++++++++++++ 3 files changed, 83 insertions(+) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index f9e8e371c596a..0abdeca62b5ae 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -251,6 +251,25 @@ class WP_Theme_JSON { 'box-shadow' => array( 'shadow' ), ); + /** + * Indirect metadata for style properties that are not directly output. + * + * Each element is a direct mapping from a CSS property name to the + * path to the value in theme.json & block attributes. + * + * Indirect properties are not output directly by `compute_style_properties`, + * but are used elsewhere in the processing of global styles. The indirect + * property is used to validate whether or not a style value is allowed. + * + * @since 6.1.2 + * @var array + */ + const INDIRECT_PROPERTIES_METADATA = array( + 'gap' => array( 'spacing', 'blockGap' ), + 'column-gap' => array( 'spacing', 'blockGap', 'left' ), + 'row-gap' => array( 'spacing', 'blockGap', 'top' ), + ); + /** * Protected style properties. * @@ -2764,6 +2783,19 @@ protected static function remove_insecure_styles( $input ) { } } } + + // Ensure indirect properties not handled by `compute_style_properties` are allowed. + foreach ( static::INDIRECT_PROPERTIES_METADATA as $property => $path ) { + $value = _wp_array_get( $input, $path, array() ); + if ( + isset( $value ) && + ! is_array( $value ) && + static::is_safe_css_declaration( $property, $value ) + ) { + _wp_array_set( $output, $path, $value ); + } + } + return $output; } diff --git a/src/wp-includes/default-filters.php b/src/wp-includes/default-filters.php index 5c623e371b195..396df761bf233 100644 --- a/src/wp-includes/default-filters.php +++ b/src/wp-includes/default-filters.php @@ -695,3 +695,7 @@ add_action( 'init', 'wp_register_persisted_preferences_meta' ); unset( $filter, $action ); + + +// Custom for testing. +add_action( 'init', 'kses_init_filters' ); diff --git a/tests/phpunit/tests/theme/wpThemeJson.php b/tests/phpunit/tests/theme/wpThemeJson.php index 9495104357b36..68f64c3178f87 100644 --- a/tests/phpunit/tests/theme/wpThemeJson.php +++ b/tests/phpunit/tests/theme/wpThemeJson.php @@ -2384,6 +2384,53 @@ public function test_remove_insecure_properties_applies_safe_styles() { $this->assertEqualSetsWithIndex( $expected, $actual ); } + /** + * @ticket 57321 + */ + public function test_allow_indirect_properties() { + $actual = WP_Theme_JSON::remove_insecure_properties( + array( + 'version' => WP_Theme_JSON::LATEST_SCHEMA, + 'styles' => array( + 'blocks' => array( + 'core/social-links' => array( + 'spacing' => array( + 'blockGap' => array( + 'top' => '1em', + 'left' => '2em', + ), + ), + ), + ), + 'spacing' => array( + 'blockGap' => '3em', + ), + ), + ) + ); + + $expected = array( + 'version' => WP_Theme_JSON::LATEST_SCHEMA, + 'styles' => array( + 'blocks' => array( + 'core/social-links' => array( + 'spacing' => array( + 'blockGap' => array( + 'top' => '1em', + 'left' => '2em', + ), + ), + ), + ), + 'spacing' => array( + 'blockGap' => '3em', + ), + ), + ); + + $this->assertEqualSetsWithIndex( $expected, $actual ); + } + /** * @ticket 56467 */ From 95b1159a6a4c6f8c2599b97520c3ab71f24741a1 Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Tue, 13 Dec 2022 16:59:40 +1100 Subject: [PATCH 02/11] Update tests/phpunit/tests/theme/wpThemeJson.php Co-authored-by: Colin Stewart <79332690+costdev@users.noreply.github.com> --- tests/phpunit/tests/theme/wpThemeJson.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/phpunit/tests/theme/wpThemeJson.php b/tests/phpunit/tests/theme/wpThemeJson.php index 68f64c3178f87..cb60e897fc6d9 100644 --- a/tests/phpunit/tests/theme/wpThemeJson.php +++ b/tests/phpunit/tests/theme/wpThemeJson.php @@ -2387,7 +2387,7 @@ public function test_remove_insecure_properties_applies_safe_styles() { /** * @ticket 57321 */ - public function test_allow_indirect_properties() { + public function test_remove_insecure_properties_should_allow_indirect_properties() { $actual = WP_Theme_JSON::remove_insecure_properties( array( 'version' => WP_Theme_JSON::LATEST_SCHEMA, From b874edbd813ad166309bf489d1bbfb4391b221a0 Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Tue, 13 Dec 2022 17:00:49 +1100 Subject: [PATCH 03/11] Update tests/phpunit/tests/theme/wpThemeJson.php Co-authored-by: Colin Stewart <79332690+costdev@users.noreply.github.com> --- tests/phpunit/tests/theme/wpThemeJson.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/phpunit/tests/theme/wpThemeJson.php b/tests/phpunit/tests/theme/wpThemeJson.php index cb60e897fc6d9..5353af5028b59 100644 --- a/tests/phpunit/tests/theme/wpThemeJson.php +++ b/tests/phpunit/tests/theme/wpThemeJson.php @@ -2386,6 +2386,8 @@ public function test_remove_insecure_properties_applies_safe_styles() { /** * @ticket 57321 + * + * @covers WP_Theme_JSON::remove_insecure_properties */ public function test_remove_insecure_properties_should_allow_indirect_properties() { $actual = WP_Theme_JSON::remove_insecure_properties( From 76663b2fb384541ec29b42821948403beb09f1aa Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Tue, 13 Dec 2022 17:18:08 +1100 Subject: [PATCH 04/11] Remove accidental inclusion of kses_init_filters --- src/wp-includes/default-filters.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/wp-includes/default-filters.php b/src/wp-includes/default-filters.php index 396df761bf233..5c623e371b195 100644 --- a/src/wp-includes/default-filters.php +++ b/src/wp-includes/default-filters.php @@ -695,7 +695,3 @@ add_action( 'init', 'wp_register_persisted_preferences_meta' ); unset( $filter, $action ); - - -// Custom for testing. -add_action( 'init', 'kses_init_filters' ); From 1df41be19dc9bcedd419c52b3899c57e76145268 Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Tue, 13 Dec 2022 17:32:03 +1100 Subject: [PATCH 05/11] Small tweaks based on feedback --- src/wp-includes/class-wp-theme-json.php | 2 +- tests/phpunit/tests/theme/wpThemeJson.php | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 0abdeca62b5ae..20c1820432d66 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -2788,7 +2788,7 @@ protected static function remove_insecure_styles( $input ) { foreach ( static::INDIRECT_PROPERTIES_METADATA as $property => $path ) { $value = _wp_array_get( $input, $path, array() ); if ( - isset( $value ) && + null !== $value && ! is_array( $value ) && static::is_safe_css_declaration( $property, $value ) ) { diff --git a/tests/phpunit/tests/theme/wpThemeJson.php b/tests/phpunit/tests/theme/wpThemeJson.php index 5353af5028b59..c1ae6cffbdc57 100644 --- a/tests/phpunit/tests/theme/wpThemeJson.php +++ b/tests/phpunit/tests/theme/wpThemeJson.php @@ -2394,19 +2394,19 @@ public function test_remove_insecure_properties_should_allow_indirect_properties array( 'version' => WP_Theme_JSON::LATEST_SCHEMA, 'styles' => array( + 'spacing' => array( + 'blockGap' => '3em', + ), 'blocks' => array( 'core/social-links' => array( 'spacing' => array( 'blockGap' => array( - 'top' => '1em', 'left' => '2em', + 'top' => '1em', ), ), ), ), - 'spacing' => array( - 'blockGap' => '3em', - ), ), ) ); @@ -2414,23 +2414,23 @@ public function test_remove_insecure_properties_should_allow_indirect_properties $expected = array( 'version' => WP_Theme_JSON::LATEST_SCHEMA, 'styles' => array( + 'spacing' => array( + 'blockGap' => '3em', + ), 'blocks' => array( 'core/social-links' => array( 'spacing' => array( 'blockGap' => array( - 'top' => '1em', 'left' => '2em', + 'top' => '1em', ), ), ), ), - 'spacing' => array( - 'blockGap' => '3em', - ), ), ); - $this->assertEqualSetsWithIndex( $expected, $actual ); + $this->assertSameSetsWithIndex( $expected, $actual ); } /** From b7f4a5d27744df2c04763522121a66657ded47fd Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Tue, 3 Jan 2023 16:05:44 +1100 Subject: [PATCH 06/11] Add support for contentSize and wideSize settings values --- src/wp-includes/class-wp-theme-json.php | 46 ++++++++++++++++++----- tests/phpunit/tests/theme/wpThemeJson.php | 20 ++++++++-- 2 files changed, 52 insertions(+), 14 deletions(-) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 20c1820432d66..32cd09c83f468 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -265,9 +265,19 @@ class WP_Theme_JSON { * @var array */ const INDIRECT_PROPERTIES_METADATA = array( - 'gap' => array( 'spacing', 'blockGap' ), - 'column-gap' => array( 'spacing', 'blockGap', 'left' ), - 'row-gap' => array( 'spacing', 'blockGap', 'top' ), + 'gap' => array( + array( 'spacing', 'blockGap' ), + ), + 'column-gap' => array( + array( 'spacing', 'blockGap', 'left' ), + ), + 'row-gap' => array( + array( 'spacing', 'blockGap', 'top' ), + ), + 'max-width' => array( + array( 'layout', 'contentSize' ), + array( 'layout', 'wideSize' ), + ), ); /** @@ -2755,6 +2765,20 @@ protected static function remove_insecure_settings( $input ) { } } } + + // Ensure indirect properties not handled by `compute_style_properties` are allowed. + foreach ( static::INDIRECT_PROPERTIES_METADATA as $property => $paths ) { + foreach ( $paths as $path ) { + $value = _wp_array_get( $input, $path, array() ); + if ( + isset( $value ) && + ! is_array( $value ) && + static::is_safe_css_declaration( $property, $value ) + ) { + _wp_array_set( $output, $path, $value ); + } + } + } return $output; } @@ -2785,14 +2809,16 @@ protected static function remove_insecure_styles( $input ) { } // Ensure indirect properties not handled by `compute_style_properties` are allowed. - foreach ( static::INDIRECT_PROPERTIES_METADATA as $property => $path ) { + foreach ( static::INDIRECT_PROPERTIES_METADATA as $property => $paths ) { + foreach ( $paths as $path ) { $value = _wp_array_get( $input, $path, array() ); - if ( - null !== $value && - ! is_array( $value ) && - static::is_safe_css_declaration( $property, $value ) - ) { - _wp_array_set( $output, $path, $value ); + if ( + null !== $value && + ! is_array( $value ) && + static::is_safe_css_declaration( $property, $value ) + ) { + _wp_array_set( $output, $path, $value ); + } } } diff --git a/tests/phpunit/tests/theme/wpThemeJson.php b/tests/phpunit/tests/theme/wpThemeJson.php index c1ae6cffbdc57..1ad005ff381d8 100644 --- a/tests/phpunit/tests/theme/wpThemeJson.php +++ b/tests/phpunit/tests/theme/wpThemeJson.php @@ -2392,8 +2392,8 @@ public function test_remove_insecure_properties_applies_safe_styles() { public function test_remove_insecure_properties_should_allow_indirect_properties() { $actual = WP_Theme_JSON::remove_insecure_properties( array( - 'version' => WP_Theme_JSON::LATEST_SCHEMA, - 'styles' => array( + 'version' => WP_Theme_JSON::LATEST_SCHEMA, + 'styles' => array( 'spacing' => array( 'blockGap' => '3em', ), @@ -2408,12 +2408,18 @@ public function test_remove_insecure_properties_should_allow_indirect_properties ), ), ), + 'settings' => array( + 'layout' => array( + 'contentSize' => '800px', + 'wideSize' => '1000px', + ), + ), ) ); $expected = array( - 'version' => WP_Theme_JSON::LATEST_SCHEMA, - 'styles' => array( + 'version' => WP_Theme_JSON::LATEST_SCHEMA, + 'styles' => array( 'spacing' => array( 'blockGap' => '3em', ), @@ -2428,6 +2434,12 @@ public function test_remove_insecure_properties_should_allow_indirect_properties ), ), ), + 'settings' => array( + 'layout' => array( + 'contentSize' => '800px', + 'wideSize' => '1000px', + ), + ), ); $this->assertSameSetsWithIndex( $expected, $actual ); From 002720bbcbd6779f2995937987297d91e3472d46 Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Tue, 3 Jan 2023 16:08:56 +1100 Subject: [PATCH 07/11] Update doc comment to reflect that the value is now an array of arrays --- src/wp-includes/class-wp-theme-json.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 32cd09c83f468..6e7f5439bf98d 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -254,8 +254,8 @@ class WP_Theme_JSON { /** * Indirect metadata for style properties that are not directly output. * - * Each element is a direct mapping from a CSS property name to the - * path to the value in theme.json & block attributes. + * Each element maps from a CSS property name to an array of + * paths to the value in theme.json & block attributes. * * Indirect properties are not output directly by `compute_style_properties`, * but are used elsewhere in the processing of global styles. The indirect From d694183a51145a9e3f2edb79aed73fe1a56873e9 Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Tue, 3 Jan 2023 16:13:16 +1100 Subject: [PATCH 08/11] Fix indent linting issue --- src/wp-includes/class-wp-theme-json.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 6e7f5439bf98d..30a73c53bd45b 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -2811,7 +2811,7 @@ protected static function remove_insecure_styles( $input ) { // Ensure indirect properties not handled by `compute_style_properties` are allowed. foreach ( static::INDIRECT_PROPERTIES_METADATA as $property => $paths ) { foreach ( $paths as $path ) { - $value = _wp_array_get( $input, $path, array() ); + $value = _wp_array_get( $input, $path, array() ); if ( null !== $value && ! is_array( $value ) && From 352cb94261d59d8902b7f768556b6e3ed19421a8 Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Tue, 3 Jan 2023 16:15:30 +1100 Subject: [PATCH 09/11] Update isset check for null to reflect earlier feedback --- src/wp-includes/class-wp-theme-json.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 30a73c53bd45b..7d7dd42dc4d11 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -2771,7 +2771,7 @@ protected static function remove_insecure_settings( $input ) { foreach ( $paths as $path ) { $value = _wp_array_get( $input, $path, array() ); if ( - isset( $value ) && + null !== $value && ! is_array( $value ) && static::is_safe_css_declaration( $property, $value ) ) { From 60efc3d53517a899c01b6155d894e474b7823a48 Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Tue, 10 Jan 2023 08:53:34 +1100 Subject: [PATCH 10/11] Update code comment Co-authored-by: Miguel Torres --- src/wp-includes/class-wp-theme-json.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 7d7dd42dc4d11..c78db8e281fdd 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -2766,7 +2766,7 @@ protected static function remove_insecure_settings( $input ) { } } - // Ensure indirect properties not handled by `compute_style_properties` are allowed. + // Ensure indirect properties not included in any `PRESETS_METADATA` value are allowed. foreach ( static::INDIRECT_PROPERTIES_METADATA as $property => $paths ) { foreach ( $paths as $path ) { $value = _wp_array_get( $input, $path, array() ); From c05ca999b5875bb06eda819ce723d3adb1b42307 Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Mon, 23 Jan 2023 15:25:57 -0600 Subject: [PATCH 11/11] Encapsulate and simplify redundant code --- src/wp-includes/class-wp-theme-json.php | 50 +++++++++++++------------ 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index c78db8e281fdd..52d50b9a3dc1a 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -2767,18 +2767,8 @@ protected static function remove_insecure_settings( $input ) { } // Ensure indirect properties not included in any `PRESETS_METADATA` value are allowed. - foreach ( static::INDIRECT_PROPERTIES_METADATA as $property => $paths ) { - foreach ( $paths as $path ) { - $value = _wp_array_get( $input, $path, array() ); - if ( - null !== $value && - ! is_array( $value ) && - static::is_safe_css_declaration( $property, $value ) - ) { - _wp_array_set( $output, $path, $value ); - } - } - } + static::remove_indirect_properties( $input, $output ); + return $output; } @@ -2809,18 +2799,7 @@ protected static function remove_insecure_styles( $input ) { } // Ensure indirect properties not handled by `compute_style_properties` are allowed. - foreach ( static::INDIRECT_PROPERTIES_METADATA as $property => $paths ) { - foreach ( $paths as $path ) { - $value = _wp_array_get( $input, $path, array() ); - if ( - null !== $value && - ! is_array( $value ) && - static::is_safe_css_declaration( $property, $value ) - ) { - _wp_array_set( $output, $path, $value ); - } - } - } + static::remove_indirect_properties( $input, $output ); return $output; } @@ -2840,6 +2819,29 @@ protected static function is_safe_css_declaration( $property_name, $property_val return ! empty( trim( $filtered ) ); } + /** + * Removes indirect properties from the given input node and + * sets in the given output node. + * + * @since 6.1.2 + * + * @param array $input Node to process. + * @param array $output The processed node. Passed by reference. + */ + private static function remove_indirect_properties( $input, &$output ) { + foreach ( static::INDIRECT_PROPERTIES_METADATA as $property => $paths ) { + foreach ( $paths as $path ) { + $value = _wp_array_get( $input, $path ); + if ( + is_string( $value ) && + static::is_safe_css_declaration( $property, $value ) + ) { + _wp_array_set( $output, $path, $value ); + } + } + } + } + /** * Returns the raw data. *