From 33e336a9ae8c627f1e3afdc9575f97e8fbce0de1 Mon Sep 17 00:00:00 2001 From: ramonjd Date: Tue, 9 Aug 2022 11:43:28 +1000 Subject: [PATCH] Allow a single custom properties with which we can test incoming `--wp--*` custom properties --- ...class-wp-style-engine-css-declarations.php | 46 ++++++++++++++++++- ...-wp-style-engine-css-declarations-test.php | 24 +++++++++- 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/packages/style-engine/class-wp-style-engine-css-declarations.php b/packages/style-engine/class-wp-style-engine-css-declarations.php index c223dc74de2c0c..5dfded9ad99efb 100644 --- a/packages/style-engine/class-wp-style-engine-css-declarations.php +++ b/packages/style-engine/class-wp-style-engine-css-declarations.php @@ -38,6 +38,27 @@ public function __construct( $declarations = array() ) { return; } $this->add_declarations( $declarations ); + + // @TODO: This should be removed when and if safecss_filter_attr() in wp-includes/kses.php allows CSS custom properties. + if ( ! has_filter( 'safe_style_css', array( __CLASS__, 'safe_style_css_allow_wp_custom_property_filter' ) ) ) { + add_filter( 'safe_style_css', array( __CLASS__, 'safe_style_css_allow_wp_custom_property_filter' ), 10, 1 ); + } + } + + /** + * Update allowed inline style attributes list. + * We can then use this to run + * + * @TODO: This should be removed when and if safecss_filter_attr() in wp-includes/kses.php allows CSS custom properties. + * + * @param string[] $attrs Array of allowed CSS attributes. + * @return string[] CSS attributes. + */ + public static function safe_style_css_allow_wp_custom_property_filter( $attrs ) { + // A single CSS custom property used in place of incoming `---wp--*` properties. + // The goal is to use it to run `---wp--*: {$value}` through safecss_filter_attr(). + $attrs[] = '--wp--custom-property'; + return $attrs; } /** @@ -113,6 +134,29 @@ public function get_declarations() { return $this->declarations; } + /** + * Filters a CSS property + value pair. + * + * @param string $property The CSS property. + * @param string $value The value to be filtered. + * @param string $spacer The spacer between the colon and the value. Defaults to an empty string. + * + * @return string The filtered declaration as a single string. + */ + protected static function filter_declaration( $property, $value, $spacer = '' ) { + if ( isset( $property ) && isset( $value ) ) { + // Allow CSS custom properties starting with `--wp--`. + // Run a generic CSS string through `safecss_filter_attr`'s value checks. + // @TODO: This should be removed when and if safecss_filter_attr() in wp-includes/kses.php allows CSS custom properties. + if ( 0 === strpos( $property, '--wp--' ) && ! empty( safecss_filter_attr( "--wp--custom-property:{$spacer}{$value}" ) ) ) { + // The property has already been sanitized by $this->sanitize_property(). + return "{$property}:{$spacer}{$value}"; + } + return safecss_filter_attr( "{$property}:{$spacer}{$value}" ); + } + return ''; + } + /** * Filters and compiles the CSS declarations. * @@ -130,7 +174,7 @@ public function get_declarations_string( $should_prettify = false, $indent_count foreach ( $declarations_array as $property => $value ) { $spacer = $should_prettify ? ' ' : ''; - $filtered_declaration = esc_html( safecss_filter_attr( "{$property}:{$spacer}{$value}" ) ); + $filtered_declaration = static::filter_declaration( $property, $value, $spacer ); if ( $filtered_declaration ) { $declarations_output .= "{$indent}{$filtered_declaration};$suffix"; } diff --git a/packages/style-engine/phpunit/class-wp-style-engine-css-declarations-test.php b/packages/style-engine/phpunit/class-wp-style-engine-css-declarations-test.php index 243a6bfd9956a9..d600e4ab3ff7ea 100644 --- a/packages/style-engine/phpunit/class-wp-style-engine-css-declarations-test.php +++ b/packages/style-engine/phpunit/class-wp-style-engine-css-declarations-test.php @@ -149,14 +149,34 @@ public function test_generate_prettified_with_more_indents_css_declarations_stri */ public function test_remove_unsafe_properties_and_values() { $input_declarations = array( - 'color' => '', + 'color' => 'url("https://wordpress.org")', 'margin-right' => '10em', 'potato' => 'uppercase', ); $css_declarations = new WP_Style_Engine_CSS_Declarations( $input_declarations ); $this->assertSame( - 'color:<red/>;margin-right:10em;', + 'margin-right:10em;', + $css_declarations->get_declarations_string() + ); + } + + /** + * Should allow --wp--* CSS custom properties. + */ + public function test_allow_wp_custom_properties() { + $input_declarations = array( + '--wp--love-your-work' => 'url("https://wordpress.org")', + '--large-font-size' => '10em', + '--wp-yeah-nah' => '100%', + '--wp--preset--here-is-a-potato' => '88px', + '--wp--style--/::target-[]' => '2000.75em', + '--wp--style--block-gap' => '2em', + ); + $css_declarations = new WP_Style_Engine_CSS_Declarations( $input_declarations ); + + $this->assertSame( + '--wp--preset--here-is-a-potato:88px;--wp--style--target-nonsense:2000.75em;--wp--style--block-gap:2em;', $css_declarations->get_declarations_string() ); }