diff --git a/projects/plugins/jetpack/changelog/add-css-vars-to-csstidy b/projects/plugins/jetpack/changelog/add-css-vars-to-csstidy new file mode 100644 index 000000000000..25bc845a6619 --- /dev/null +++ b/projects/plugins/jetpack/changelog/add-css-vars-to-csstidy @@ -0,0 +1,5 @@ +Significance: patch +Type: compat +Comment: Modified csstidy to allow css variable properties + + diff --git a/projects/plugins/jetpack/modules/custom-css/csstidy/class.csstidy.php b/projects/plugins/jetpack/modules/custom-css/csstidy/class.csstidy.php index ecb5f72931c5..ecae3063e5aa 100644 --- a/projects/plugins/jetpack/modules/custom-css/csstidy/class.csstidy.php +++ b/projects/plugins/jetpack/modules/custom-css/csstidy/class.csstidy.php @@ -279,6 +279,7 @@ function __construct() { $this->settings['preserve_css'] = false; $this->settings['timestamp'] = false; $this->settings['template'] = ''; // say that propertie exist + $this->settings['preserve_css_variables'] = false; $this->set_cfg('template','default'); // call load_template $this->optimise = new csstidy_optimise($this); @@ -1178,7 +1179,21 @@ function property_is_valid($property) { $property = strtolower($property); if (in_array(trim($property), $GLOBALS['csstidy']['multiple_properties'])) $property = trim($property); $all_properties = & $GLOBALS['csstidy']['all_properties']; - return (isset($all_properties[$property]) && strpos($all_properties[$property], strtoupper($this->get_cfg('css_level'))) !== false ); + return ( ( isset( $all_properties[ $property ] ) && strpos( $all_properties[ $property ], strtoupper( $this->get_cfg( 'css_level' ) ) ) !== false ) + || ( $this->get_cfg( 'preserve_css_variables' ) && $this->property_is_css_variable( $property ) ) ); + } + + /** + * Checks if a property is a css variable + * Valid patterns must start with `--` and use alphanumeric characters optionally separated by `-` or `_`. They must not end with a `-` or `_`. + * + * @param string $property The property name to be checked. + * @return bool; + * @access public + * @version 1.0 + */ + public function property_is_css_variable( $property ) { + return preg_match( '/^--([a-zA-Z0-9]+[\-_]?)+(?set_cfg( 'remove_last_;', false ); $csstidy->set_cfg( 'css_level', 'CSS3.0' ); - // Turn off css shorthands when in block editor context as it breaks block validation. + // Turn off css shorthands, and allow css variables, when in block editor context otherwise block validation is broken. if ( true === isset( $_REQUEST['_gutenberg_nonce'] ) && wp_verify_nonce( $_REQUEST['_gutenberg_nonce'], 'gutenberg_request' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash $csstidy->set_cfg( 'optimise_shorthands', 0 ); + $csstidy->set_cfg( 'preserve_css_variables', true ); } $css = preg_replace( '/\\\\([0-9a-fA-F]{4})/', '\\\\\\\\$1', $css ); diff --git a/projects/plugins/jetpack/phpunit.xml.dist b/projects/plugins/jetpack/phpunit.xml.dist index 10aa1e98f164..3cd084bd3b63 100644 --- a/projects/plugins/jetpack/phpunit.xml.dist +++ b/projects/plugins/jetpack/phpunit.xml.dist @@ -128,6 +128,9 @@ tests/php/modules/seo-tools + + tests/php/modules/csstidy + diff --git a/projects/plugins/jetpack/tests/php/modules/csstidy/test-class.jetpack-csstidy.php b/projects/plugins/jetpack/tests/php/modules/csstidy/test-class.jetpack-csstidy.php new file mode 100644 index 000000000000..8c0321179420 --- /dev/null +++ b/projects/plugins/jetpack/tests/php/modules/csstidy/test-class.jetpack-csstidy.php @@ -0,0 +1,67 @@ +instance = new csstidy(); + $this->instance->set_cfg( 'optimise_shorthands', 0 ); + $this->instance->set_cfg( 'discard_invalid_properties', true ); + } + + /** Provides values for CSS custom property patterns */ + public function custom_property_matches_provider() { + // phpcs:ignore Squiz.PHP.CommentedOutCode.Found -- false positive + // 'test case description' => [ 'input', 'expected output', 'preserve_css_variables' ]. + return array( + 'test_removes_css_var_properties_by_default' => array( 'div {--base-color:red;color:var(--base-color)}', "div {\ncolor:var(--base-color)\n}", false ), + 'test_css_var_properties_preserved' => array( 'div {--base-color_for_1st-child:red;color:var(--base-color)}', "div {\n--base-color_for_1st-child:red;\ncolor:var(--base-color)\n}", true ), + 'test_css_var_properties_with_no_alphanum_chars_removed' => array( 'div {--_:red;color:var(--base-color)}', "div {\ncolor:var(--base-color)\n}", true ), + 'test_css_var_properties_ending_in_hyphen_removed' => array( 'div {--base-color-:red;color:var(--base-color)}', "div {\ncolor:var(--base-color)\n}", true ), + 'test_css_var_properties_ending_in_underscore_removed' => array( 'div {--base-color_:red;color:var(--base-color)}', "div {\ncolor:var(--base-color)\n}", true ), + 'test_unknown_properties_removed' => array( 'div {clowns-nose:red;color:var(--base-color)}', "div {\ncolor:var(--base-color)\n}", true ), + 'test_invalid_css_properties_removed' => array( 'div {--$//2343--3423:red;color:var(--$//2343--3423)}', "div {\ncolor:var(--$//2343--3423)\n}", true ), + 'test_broken_or_dangerous_css_removed' => array( 'div {xss-trap-be-careful:red;}color:var(--base-color)}', '', true ), + ); + } + + /** + * Test that css variable properties are valid/invalid. + * + * @dataProvider custom_property_matches_provider + * + * @param string $input potential CSS custom property. + * @param string $expected_output what we expect css tidy to output. + * @param bool $preserve_css_variables the value of preserve_css_variables in csstidy's config. + */ + public function test_custom_property_patterns( $input, $expected_output, $preserve_css_variables ) { + $this->instance->set_cfg( 'preserve_css_variables', $preserve_css_variables ); + $this->instance->parse( $input ); + $this->assertEquals( + $expected_output, + $this->instance->print->plain() + ); + } +}