Skip to content
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
26 changes: 26 additions & 0 deletions src/wp-includes/class-wp-theme-json.php
Original file line number Diff line number Diff line change
Expand Up @@ -1536,6 +1536,32 @@ protected static function sanitize( $input, $valid_block_names, $valid_element_n
$result['viewport'] = self::sanitize_viewport_settings( $input[ $subtree ]['viewport'] );
}

if ( 'settings' === $subtree ) {
// Preset leaves are untyped in VALID_SETTINGS, but consumers read `$preset['slug']` as a string.
$is_valid_preset = static function ( $preset ) {
return is_array( $preset ) && ( ! isset( $preset['slug'] ) || is_scalar( $preset['slug'] ) );
};
foreach ( static::get_setting_nodes( array( 'settings' => $result ) ) as $node ) {
foreach ( static::PRESETS_METADATA as $preset_metadata ) {
$path = array_merge( array_slice( $node['path'], 1 ), $preset_metadata['path'] );
$presets = _wp_array_get( $result, $path, null );
if ( ! is_array( $presets ) ) {
continue;
}
if ( isset( $presets[0] ) ) {
$presets = array_values( array_filter( $presets, $is_valid_preset ) );
} else {
foreach ( static::VALID_ORIGINS as $origin ) {
if ( isset( $presets[ $origin ] ) && is_array( $presets[ $origin ] ) ) {
$presets[ $origin ] = array_values( array_filter( $presets[ $origin ], $is_valid_preset ) );
}
}
}
_wp_array_set( $result, $path, $presets );
}
}
}

if ( empty( $result ) ) {
unset( $output[ $subtree ] );
} else {
Expand Down
114 changes: 106 additions & 8 deletions tests/phpunit/tests/theme/wpThemeJson.php
Original file line number Diff line number Diff line change
Expand Up @@ -5898,6 +5898,7 @@ public static function data_sanitize_with_invalid_style_variation() {

/**
* @ticket 66286
* @ticket 66304
*
* @dataProvider data_get_stylesheet_ignores_values_of_unexpected_types
*
Expand All @@ -5918,22 +5919,57 @@ public function test_get_stylesheet_ignores_values_of_unexpected_types( $theme_j
*/
public static function data_get_stylesheet_ignores_values_of_unexpected_types() {
return array(
'root custom css as an object' => array(
'root custom css as an object' => array(
array( 'styles' => array( 'css' => array( 'color' => 'red' ) ) ),
),
'element custom css as an object' => array(
'element custom css as an object' => array(
array( 'styles' => array( 'elements' => array( 'link' => array( 'css' => array( 'color' => 'red' ) ) ) ) ),
),
'block custom css as a list' => array(
'block custom css as a list' => array(
array( 'styles' => array( 'blocks' => array( 'core/paragraph' => array( 'css' => array( 'color: red;' ) ) ) ) ),
),
'ref as an array' => array(
'ref as an array' => array(
array( 'styles' => array( 'color' => array( 'text' => array( 'ref' => array( 'styles', 'color' ) ) ) ) ),
),
'spacing scale as a string' => array(
'palette as a list of strings' => array(
array( 'settings' => array( 'color' => array( 'palette' => array( '#000', '#fff' ) ) ) ),
),
'palette keyed by origin with a string' => array(
array( 'settings' => array( 'color' => array( 'palette' => array( 'custom' => array( '#000' ) ) ) ) ),
),
'palette mixing a list and an origin' => array(
array(
'settings' => array(
'color' => array(
'palette' => array(
0 => '#000',
'theme' => '#fff',
),
),
),
),
),
'preset slug as an array' => array(
array(
'settings' => array(
'typography' => array(
'fontSizes' => array(
array(
'slug' => array( 'small' ),
'size' => '1rem',
),
),
),
),
),
),
'font families as a list of strings' => array(
array( 'settings' => array( 'typography' => array( 'fontFamilies' => array( 'Inter' ) ) ) ),
),
'spacing scale as a string' => array(
array( 'settings' => array( 'spacing' => array( 'spacingScale' => '1.5' ) ) ),
),
'spacing scale unit as an array' => array(
'spacing scale unit as an array' => array(
array(
'settings' => array(
'spacing' => array(
Expand All @@ -5948,15 +5984,77 @@ public static function data_get_stylesheet_ignores_values_of_unexpected_types()
),
),
),
'shared style variation as a string' => array(
'shared style variation as a string' => array(
array( 'styles' => array( 'variations' => array( 'plain' => 'red' ) ) ),
),
'block types item as an array' => array(
'block types item as an array' => array(
array( 'blockTypes' => array( array( 'core/button' ) ) ),
),
);
}

/**
* @ticket 66304
*/
public function test_sanitize_removes_preset_items_of_unexpected_types() {
$valid_color = array(
'slug' => 'black',
'color' => '#000',
'name' => 'Black',
);
$int_slug = array(
'slug' => 50,
'color' => '#888',
'name' => 'Grey',
);
$invalid = array(
'#fff',
array(
'slug' => array( 'white' ),
'color' => '#fff',
),
);

$theme_json = new WP_Theme_JSON(
array(
'version' => WP_Theme_JSON::LATEST_SCHEMA,
'settings' => array(
'color' => array( 'palette' => array_merge( $invalid, array( $valid_color, $int_slug ) ) ),
'blocks' => array(
'core/paragraph' => array(
'color' => array( 'palette' => array( 'custom' => array_merge( $invalid, array( $valid_color, $int_slug ) ) ) ),
),
),
),
)
);
$settings = $theme_json->get_settings();

$this->assertSame( array( $valid_color, $int_slug ), $settings['color']['palette']['theme'], 'Top-level preset list' );
$this->assertSame( array( $valid_color, $int_slug ), $settings['blocks']['core/paragraph']['color']['palette']['custom'], 'Block-level presets keyed by origin' );
}

/**
* @ticket 66304
*/
public function test_remove_insecure_properties_removes_preset_items_of_unexpected_types() {
$valid_color = array(
'slug' => 'black',
'color' => '#000',
'name' => 'Black',
);

$sanitized = WP_Theme_JSON::remove_insecure_properties(
array(
'version' => WP_Theme_JSON::LATEST_SCHEMA,
'settings' => array( 'color' => array( 'palette' => array( 'custom' => array( '#fff', $valid_color ) ) ) ),
),
'custom'
);

$this->assertSame( array( $valid_color ), $sanitized['settings']['color']['palette']['custom'] );
}

/**
* @ticket 66286
*/
Expand Down
Loading