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()
+ );
+ }
+}