Skip to content

Commit d71f29f

Browse files
committed
Global Styles: Improve sanitization of block variation styles.
Fixes an issue where block style variations containing inner block type and element styles would have those inner styles stripped when the user attempting to save Global Styles does not have the `unfiltered_html` capability. Props aaronrobertshaw, mukesh27, andrewserong. Fixes #62372. git-svn-id: https://develop.svn.wordpress.org/trunk@59802 602fd350-edb4-49c9-b593-d223f7449a82
1 parent f71d5f0 commit d71f29f

File tree

2 files changed

+242
-19
lines changed

2 files changed

+242
-19
lines changed

src/wp-includes/class-wp-theme-json.php

Lines changed: 58 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3552,26 +3552,12 @@ public static function remove_insecure_properties( $theme_json, $origin = 'theme
35523552

35533553
$variation_output = static::remove_insecure_styles( $variation_input );
35543554

3555-
// Process a variation's elements and element pseudo selector styles.
3556-
if ( isset( $variation_input['elements'] ) ) {
3557-
foreach ( $valid_element_names as $element_name ) {
3558-
$element_input = $variation_input['elements'][ $element_name ] ?? null;
3559-
if ( $element_input ) {
3560-
$element_output = static::remove_insecure_styles( $element_input );
3561-
3562-
if ( isset( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element_name ] ) ) {
3563-
foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element_name ] as $pseudo_selector ) {
3564-
if ( isset( $element_input[ $pseudo_selector ] ) ) {
3565-
$element_output[ $pseudo_selector ] = static::remove_insecure_styles( $element_input[ $pseudo_selector ] );
3566-
}
3567-
}
3568-
}
3555+
if ( isset( $variation_input['blocks'] ) ) {
3556+
$variation_output['blocks'] = static::remove_insecure_inner_block_styles( $variation_input['blocks'] );
3557+
}
35693558

3570-
if ( ! empty( $element_output ) ) {
3571-
_wp_array_set( $variation_output, array( 'elements', $element_name ), $element_output );
3572-
}
3573-
}
3574-
}
3559+
if ( isset( $variation_input['elements'] ) ) {
3560+
$variation_output['elements'] = static::remove_insecure_element_styles( $variation_input['elements'] );
35753561
}
35763562

35773563
if ( ! empty( $variation_output ) ) {
@@ -3609,6 +3595,59 @@ public static function remove_insecure_properties( $theme_json, $origin = 'theme
36093595
return $theme_json;
36103596
}
36113597

3598+
/**
3599+
* Remove insecure element styles within a variation or block.
3600+
*
3601+
* @since 6.8.0
3602+
*
3603+
* @param array $elements The elements to process.
3604+
* @return array The sanitized elements styles.
3605+
*/
3606+
protected static function remove_insecure_element_styles( $elements ) {
3607+
$sanitized = array();
3608+
$valid_element_names = array_keys( static::ELEMENTS );
3609+
3610+
foreach ( $valid_element_names as $element_name ) {
3611+
$element_input = $elements[ $element_name ] ?? null;
3612+
if ( $element_input ) {
3613+
$element_output = static::remove_insecure_styles( $element_input );
3614+
3615+
if ( isset( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element_name ] ) ) {
3616+
foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element_name ] as $pseudo_selector ) {
3617+
if ( isset( $element_input[ $pseudo_selector ] ) ) {
3618+
$element_output[ $pseudo_selector ] = static::remove_insecure_styles( $element_input[ $pseudo_selector ] );
3619+
}
3620+
}
3621+
}
3622+
3623+
$sanitized[ $element_name ] = $element_output;
3624+
}
3625+
}
3626+
return $sanitized;
3627+
}
3628+
3629+
/**
3630+
* Remove insecure styles from inner blocks and their elements.
3631+
*
3632+
* @since 6.8.0
3633+
*
3634+
* @param array $blocks The block styles to process.
3635+
* @return array Sanitized block type styles.
3636+
*/
3637+
protected static function remove_insecure_inner_block_styles( $blocks ) {
3638+
$sanitized = array();
3639+
foreach ( $blocks as $block_type => $block_input ) {
3640+
$block_output = static::remove_insecure_styles( $block_input );
3641+
3642+
if ( isset( $block_input['elements'] ) ) {
3643+
$block_output['elements'] = static::remove_insecure_element_styles( $block_input['elements'] );
3644+
}
3645+
3646+
$sanitized[ $block_type ] = $block_output;
3647+
}
3648+
return $sanitized;
3649+
}
3650+
36123651
/**
36133652
* Processes a setting node and returns the same node
36143653
* without the insecure settings.

tests/phpunit/tests/theme/wpThemeJson.php

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4706,6 +4706,190 @@ public function test_block_style_variations_with_invalid_properties() {
47064706
$this->assertSameSetsWithIndex( $expected, $actual );
47074707
}
47084708

4709+
/**
4710+
* Test ensures that inner block type styles and their element styles are
4711+
* preserved for block style variations when removing insecure properties.
4712+
*
4713+
* @ticket 62372
4714+
*/
4715+
public function test_block_style_variations_with_inner_blocks_and_elements() {
4716+
wp_set_current_user( static::$administrator_id );
4717+
register_block_style(
4718+
array( 'core/group' ),
4719+
array(
4720+
'name' => 'custom-group',
4721+
'label' => 'Custom Group',
4722+
)
4723+
);
4724+
4725+
$expected = array(
4726+
'version' => WP_Theme_JSON::LATEST_SCHEMA,
4727+
'styles' => array(
4728+
'blocks' => array(
4729+
'core/group' => array(
4730+
'color' => array(
4731+
'background' => 'blue',
4732+
),
4733+
'variations' => array(
4734+
'custom-group' => array(
4735+
'color' => array(
4736+
'background' => 'purple',
4737+
),
4738+
'blocks' => array(
4739+
'core/paragraph' => array(
4740+
'color' => array(
4741+
'text' => 'red',
4742+
),
4743+
'elements' => array(
4744+
'link' => array(
4745+
'color' => array(
4746+
'text' => 'blue',
4747+
),
4748+
':hover' => array(
4749+
'color' => array(
4750+
'text' => 'green',
4751+
),
4752+
),
4753+
),
4754+
),
4755+
),
4756+
'core/heading' => array(
4757+
'typography' => array(
4758+
'fontSize' => '24px',
4759+
),
4760+
),
4761+
),
4762+
'elements' => array(
4763+
'link' => array(
4764+
'color' => array(
4765+
'text' => 'yellow',
4766+
),
4767+
':hover' => array(
4768+
'color' => array(
4769+
'text' => 'orange',
4770+
),
4771+
),
4772+
),
4773+
),
4774+
),
4775+
),
4776+
),
4777+
),
4778+
),
4779+
);
4780+
4781+
$actual = WP_Theme_JSON::remove_insecure_properties( $expected );
4782+
4783+
// The sanitization processes blocks in a specific order which might differ to the theme.json input.
4784+
$this->assertEqualsCanonicalizing(
4785+
$expected,
4786+
$actual,
4787+
'Block style variations data does not match when inner blocks or element styles present'
4788+
);
4789+
}
4790+
4791+
/**
4792+
* Test ensures that inner block type styles and their element styles for block
4793+
* style variations have all unsafe values removed.
4794+
*
4795+
* @ticket 62372
4796+
*/
4797+
public function test_block_style_variations_with_invalid_inner_block_or_element_styles() {
4798+
wp_set_current_user( static::$administrator_id );
4799+
register_block_style(
4800+
array( 'core/group' ),
4801+
array(
4802+
'name' => 'custom-group',
4803+
'label' => 'Custom Group',
4804+
)
4805+
);
4806+
4807+
$input = array(
4808+
'version' => WP_Theme_JSON::LATEST_SCHEMA,
4809+
'styles' => array(
4810+
'blocks' => array(
4811+
'core/group' => array(
4812+
'variations' => array(
4813+
'custom-group' => array(
4814+
'blocks' => array(
4815+
'core/paragraph' => array(
4816+
'color' => array(
4817+
'text' => 'red',
4818+
),
4819+
'typography' => array(
4820+
'fontSize' => 'alert(1)', // Should be removed.
4821+
),
4822+
'elements' => array(
4823+
'link' => array(
4824+
'color' => array(
4825+
'text' => 'blue',
4826+
),
4827+
'css' => 'unsafe-value', // Should be removed.
4828+
),
4829+
),
4830+
'custom' => 'unsafe-value', // Should be removed.
4831+
),
4832+
),
4833+
'elements' => array(
4834+
'link' => array(
4835+
'color' => array(
4836+
'text' => 'yellow',
4837+
),
4838+
'javascript' => 'alert(1)', // Should be removed.
4839+
),
4840+
),
4841+
),
4842+
),
4843+
),
4844+
),
4845+
),
4846+
);
4847+
4848+
$expected = array(
4849+
'version' => WP_Theme_JSON::LATEST_SCHEMA,
4850+
'styles' => array(
4851+
'blocks' => array(
4852+
'core/group' => array(
4853+
'variations' => array(
4854+
'custom-group' => array(
4855+
'blocks' => array(
4856+
'core/paragraph' => array(
4857+
'color' => array(
4858+
'text' => 'red',
4859+
),
4860+
'elements' => array(
4861+
'link' => array(
4862+
'color' => array(
4863+
'text' => 'blue',
4864+
),
4865+
),
4866+
),
4867+
),
4868+
),
4869+
'elements' => array(
4870+
'link' => array(
4871+
'color' => array(
4872+
'text' => 'yellow',
4873+
),
4874+
),
4875+
),
4876+
),
4877+
),
4878+
),
4879+
),
4880+
),
4881+
);
4882+
4883+
$actual = WP_Theme_JSON::remove_insecure_properties( $input );
4884+
4885+
// The sanitization processes blocks in a specific order which might differ to the theme.json input.
4886+
$this->assertEqualsCanonicalizing(
4887+
$expected,
4888+
$actual,
4889+
'Insecure properties were not removed from block style variation inner block types or elements'
4890+
);
4891+
}
4892+
47094893
/**
47104894
* Tests generating the spacing presets array based on the spacing scale provided.
47114895
*

0 commit comments

Comments
 (0)