From ee2786ad9f9e085f0a26f963159e38b47b134e41 Mon Sep 17 00:00:00 2001
From: Dean Sas <dean.sas@automattic.com>
Date: Fri, 11 Aug 2023 01:49:17 +0100
Subject: [PATCH] Preserve block style variations when securing theme json
 (#53466)

* Preserve block style variations when securing theme json

Valid and safe block style variations were being removed by
`WP_Theme_JSON_Gutenberg::remove_insecure_properties` when securing the
theme.json. When this was a problem varied depending upon site
configuration, but out-of-the-box it was a problem for administrators on
multi-site installs.

This change adds explicit processing of variations in
`remove_insecure_properties` so that they won't get removed.

* Add another variation sanitisation test

This test checks that when removing insecure properties an
unknown/unsupported property is removed from the variation.
---
 lib/class-wp-theme-json-gutenberg.php | 14 +++++
 phpunit/class-wp-theme-json-test.php  | 79 +++++++++++++++++++++++++++
 2 files changed, 93 insertions(+)

diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php
index 7313afeba91bca..70816ff6d5917b 100644
--- a/lib/class-wp-theme-json-gutenberg.php
+++ b/lib/class-wp-theme-json-gutenberg.php
@@ -2906,6 +2906,20 @@ public static function remove_insecure_properties( $theme_json ) {
 			if ( ! empty( $output ) ) {
 				_wp_array_set( $sanitized, $metadata['path'], $output );
 			}
+
+			if ( isset( $metadata['variations'] ) ) {
+				foreach ( $metadata['variations'] as $variation ) {
+					$variation_input = _wp_array_get( $theme_json, $variation['path'], array() );
+					if ( empty( $variation_input ) ) {
+						continue;
+					}
+
+					$variation_output = static::remove_insecure_styles( $variation_input );
+					if ( ! empty( $variation_output ) ) {
+						_wp_array_set( $sanitized, $variation['path'], $variation_output );
+					}
+				}
+			}
 		}
 
 		$setting_nodes = static::get_setting_nodes( $theme_json );
diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php
index bd1d578a1297b6..2acab0fd33356d 100644
--- a/phpunit/class-wp-theme-json-test.php
+++ b/phpunit/class-wp-theme-json-test.php
@@ -1702,6 +1702,85 @@ public function data_get_styles_for_block_with_style_variations() {
 		);
 	}
 
+	public function test_block_style_variations() {
+		wp_set_current_user( static::$administrator_id );
+
+		$expected = array(
+			'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA,
+			'styles'  => array(
+				'blocks' => array(
+					'core/button' => array(
+						'color'      => array(
+							'background' => 'blue',
+						),
+						'variations' => array(
+							'outline' => array(
+								'color' => array(
+									'background' => 'purple',
+								),
+							),
+						),
+					),
+				),
+			),
+		);
+
+		$actual = WP_Theme_JSON_Gutenberg::remove_insecure_properties( $expected );
+
+		$this->assertSameSetsWithIndex( $expected, $actual );
+	}
+
+	public function test_block_style_variations_with_invalid_properties() {
+		wp_set_current_user( static::$administrator_id );
+
+		$partially_invalid_variation = array(
+			'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA,
+			'styles'  => array(
+				'blocks' => array(
+					'core/button' => array(
+						'color'      => array(
+							'background' => 'blue',
+						),
+						'variations' => array(
+							'outline' => array(
+								'color'   => array(
+									'background' => 'purple',
+								),
+								'invalid' => array(
+									'value' => 'should be stripped',
+								),
+							),
+						),
+					),
+				),
+			),
+		);
+
+		$expected = array(
+			'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA,
+			'styles'  => array(
+				'blocks' => array(
+					'core/button' => array(
+						'color'      => array(
+							'background' => 'blue',
+						),
+						'variations' => array(
+							'outline' => array(
+								'color' => array(
+									'background' => 'purple',
+								),
+							),
+						),
+					),
+				),
+			),
+		);
+
+		$actual = WP_Theme_JSON_Gutenberg::remove_insecure_properties( $partially_invalid_variation );
+
+		$this->assertSameSetsWithIndex( $expected, $actual );
+	}
+
 	public function test_update_separator_declarations() {
 		// If only background is defined, test that includes border-color to the style so it is applied on the front end.
 		$theme_json = new WP_Theme_JSON_Gutenberg(