Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Section Styles: Fix removal of insecure properties for block style variations #7759

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 58 additions & 19 deletions src/wp-includes/class-wp-theme-json.php
Original file line number Diff line number Diff line change
Expand Up @@ -3552,26 +3552,12 @@ public static function remove_insecure_properties( $theme_json, $origin = 'theme

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

// Process a variation's elements and element pseudo selector styles.
if ( isset( $variation_input['elements'] ) ) {
foreach ( $valid_element_names as $element_name ) {
$element_input = $variation_input['elements'][ $element_name ] ?? null;
if ( $element_input ) {
$element_output = static::remove_insecure_styles( $element_input );

if ( isset( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element_name ] ) ) {
foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element_name ] as $pseudo_selector ) {
if ( isset( $element_input[ $pseudo_selector ] ) ) {
$element_output[ $pseudo_selector ] = static::remove_insecure_styles( $element_input[ $pseudo_selector ] );
}
}
}
if ( isset( $variation_input['blocks'] ) ) {
$variation_output['blocks'] = static::remove_insecure_inner_block_styles( $variation_input['blocks'] );
}

if ( ! empty( $element_output ) ) {
_wp_array_set( $variation_output, array( 'elements', $element_name ), $element_output );
}
}
}
if ( isset( $variation_input['elements'] ) ) {
$variation_output['elements'] = static::remove_insecure_element_styles( $variation_input['elements'] );
}

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

/**
* Remove insecure element styles within a variation or block.
*
* @since 6.8.0
*
* @param array $elements The elements to process.
* @return array The sanitized elements styles.
*/
protected static function remove_insecure_element_styles( $elements ) {
$sanitized = array();
$valid_element_names = array_keys( static::ELEMENTS );

foreach ( $valid_element_names as $element_name ) {
$element_input = $elements[ $element_name ] ?? null;
if ( $element_input ) {
$element_output = static::remove_insecure_styles( $element_input );

if ( isset( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element_name ] ) ) {
foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element_name ] as $pseudo_selector ) {
if ( isset( $element_input[ $pseudo_selector ] ) ) {
$element_output[ $pseudo_selector ] = static::remove_insecure_styles( $element_input[ $pseudo_selector ] );
}
}
}

$sanitized[ $element_name ] = $element_output;
}
}
return $sanitized;
}

/**
* Remove insecure styles from inner blocks and their elements.
*
* @since 6.8.0
*
* @param array $blocks The block styles to process.
* @return array Sanitized block type styles.
*/
protected static function remove_insecure_inner_block_styles( $blocks ) {
$sanitized = array();
foreach ( $blocks as $block_type => $block_input ) {
$block_output = static::remove_insecure_styles( $block_input );

if ( isset( $block_input['elements'] ) ) {
$block_output['elements'] = static::remove_insecure_element_styles( $block_input['elements'] );
}

$sanitized[ $block_type ] = $block_output;
}
return $sanitized;
}

/**
* Processes a setting node and returns the same node
* without the insecure settings.
Expand Down
184 changes: 184 additions & 0 deletions tests/phpunit/tests/theme/wpThemeJson.php
Original file line number Diff line number Diff line change
Expand Up @@ -4706,6 +4706,190 @@ public function test_block_style_variations_with_invalid_properties() {
$this->assertSameSetsWithIndex( $expected, $actual );
}

/**
* Test ensures that inner block type styles and their element styles are
* preserved for block style variations when removing insecure properties.
*
* @ticket 62372
*/
public function test_block_style_variations_with_inner_blocks_and_elements() {
wp_set_current_user( static::$administrator_id );
register_block_style(
array( 'core/group' ),
array(
'name' => 'custom-group',
'label' => 'Custom Group',
)
);

$expected = array(
'version' => WP_Theme_JSON::LATEST_SCHEMA,
'styles' => array(
'blocks' => array(
'core/group' => array(
'color' => array(
'background' => 'blue',
),
'variations' => array(
'custom-group' => array(
'color' => array(
'background' => 'purple',
),
'blocks' => array(
'core/paragraph' => array(
'color' => array(
'text' => 'red',
),
'elements' => array(
'link' => array(
'color' => array(
'text' => 'blue',
),
':hover' => array(
'color' => array(
'text' => 'green',
),
),
),
),
),
'core/heading' => array(
'typography' => array(
'fontSize' => '24px',
),
),
),
'elements' => array(
'link' => array(
'color' => array(
'text' => 'yellow',
),
':hover' => array(
'color' => array(
'text' => 'orange',
),
),
),
),
),
),
),
),
),
);

$actual = WP_Theme_JSON::remove_insecure_properties( $expected );

// The sanitization processes blocks in a specific order which might differ to the theme.json input.
$this->assertEqualsCanonicalizing(
$expected,
$actual,
'Block style variations data does not match when inner blocks or element styles present'
);
}

/**
* Test ensures that inner block type styles and their element styles for block
* style variations have all unsafe values removed.
*
* @ticket 62372
*/
public function test_block_style_variations_with_invalid_inner_block_or_element_styles() {
wp_set_current_user( static::$administrator_id );
register_block_style(
array( 'core/group' ),
array(
'name' => 'custom-group',
'label' => 'Custom Group',
)
);

$input = array(
'version' => WP_Theme_JSON::LATEST_SCHEMA,
'styles' => array(
'blocks' => array(
'core/group' => array(
'variations' => array(
'custom-group' => array(
'blocks' => array(
'core/paragraph' => array(
'color' => array(
'text' => 'red',
),
'typography' => array(
'fontSize' => 'alert(1)', // Should be removed.
),
'elements' => array(
'link' => array(
'color' => array(
'text' => 'blue',
),
'css' => 'unsafe-value', // Should be removed.
),
),
'custom' => 'unsafe-value', // Should be removed.
),
),
'elements' => array(
'link' => array(
'color' => array(
'text' => 'yellow',
),
'javascript' => 'alert(1)', // Should be removed.
),
),
),
),
),
),
),
);

$expected = array(
'version' => WP_Theme_JSON::LATEST_SCHEMA,
'styles' => array(
'blocks' => array(
'core/group' => array(
'variations' => array(
'custom-group' => array(
'blocks' => array(
'core/paragraph' => array(
'color' => array(
'text' => 'red',
),
'elements' => array(
'link' => array(
'color' => array(
'text' => 'blue',
),
),
),
),
),
'elements' => array(
'link' => array(
'color' => array(
'text' => 'yellow',
),
),
),
),
),
),
),
),
);

$actual = WP_Theme_JSON::remove_insecure_properties( $input );

// The sanitization processes blocks in a specific order which might differ to the theme.json input.
$this->assertEqualsCanonicalizing(
$expected,
$actual,
'Insecure properties were not removed from block style variation inner block types or elements'
);
}

/**
* Tests generating the spacing presets array based on the spacing scale provided.
*
Expand Down
Loading