Skip to content

Commit

Permalink
Code improvements and tests for theme json class (#47668)
Browse files Browse the repository at this point in the history
  • Loading branch information
tellthemachines authored Feb 2, 2023
1 parent 56058ec commit 0fbd15a
Show file tree
Hide file tree
Showing 2 changed files with 335 additions and 26 deletions.
67 changes: 41 additions & 26 deletions lib/class-wp-theme-json-gutenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -721,7 +721,14 @@ protected static function sanitize( $input, $valid_block_names, $valid_element_n
$schema_settings_blocks = array();
foreach ( $valid_block_names as $block ) {
// Build the schema for each block style variation.
$style_variation_names = isset( $input['styles']['blocks'][ $block ]['variations'] ) ? array_keys( $input['styles']['blocks'][ $block ]['variations'] ) : array();
$style_variation_names = array();
if (
! empty( $input['styles']['blocks'][ $block ]['variations'] ) &&
is_array( $input['styles']['blocks'][ $block ]['variations'] )
) {
$style_variation_names = array_keys( $input['styles']['blocks'][ $block ]['variations'] );
}

$schema_styles_variations = array();
if ( ! empty( $style_variation_names ) ) {
$schema_styles_variations = array_fill_keys( $style_variation_names, $styles_non_top_level );
Expand Down Expand Up @@ -2315,33 +2322,41 @@ public function get_styles_for_block( $block_metadata ) {

// If the block has feature selectors, generate the declarations for them within the current style variation.
if ( ! empty( $block_metadata['features'] ) ) {
$clean_style_variation_selector = trim( $style_variation_selector );
foreach ( $block_metadata['features'] as $feature_name => $feature_selector ) {
if ( ! empty( $style_variation_node[ $feature_name ] ) ) {
// Prepend the variation selector to the feature selector.
$split_feature_selectors = explode( ',', $feature_selector );
$feature_selectors = array_map(
function( $split_feature_selector ) use ( $style_variation_selector ) {
return trim( $style_variation_selector ) . trim( $split_feature_selector );
},
$split_feature_selectors
);
$combined_feature_selectors = implode( ',', $feature_selectors );

// Compute declarations for the feature.
$new_feature_declarations = static::compute_style_properties( array( $feature_name => $style_variation_node[ $feature_name ] ), $settings, null, $this->theme_json );

// Merge new declarations with any that already exist for
// the feature selector. This may occur when multiple block
// support features use the same custom selector.
if ( isset( $style_variation_declarations[ $combined_feature_selectors ] ) ) {
$style_variation_declarations[ $combined_feature_selectors ] = array_merge( $style_variation_declarations[ $combined_feature_selectors ], $new_feature_declarations );
} else {
$style_variation_declarations[ $combined_feature_selectors ] = $new_feature_declarations;
}
// Remove the feature from the variation's node now the
// styles will be included under the feature level selector.
unset( $style_variation_node[ $feature_name ] );
if ( empty( $style_variation_node[ $feature_name ] ) ) {
continue;
}
// Prepend the variation selector to the feature selector.
$split_feature_selectors = explode( ',', $feature_selector );
$feature_selectors = array_map(
static function( $split_feature_selector ) use ( $clean_style_variation_selector ) {
return $clean_style_variation_selector . trim( $split_feature_selector );
},
$split_feature_selectors
);
$combined_feature_selectors = implode( ',', $feature_selectors );

// Compute declarations for the feature.
$new_feature_declarations = static::compute_style_properties( array( $feature_name => $style_variation_node[ $feature_name ] ), $settings, null, $this->theme_json );

/*
* Merge new declarations with any that already exist for
* the feature selector. This may occur when multiple block
* support features use the same custom selector.
*/
if ( isset( $style_variation_declarations[ $combined_feature_selectors ] ) ) {
$style_variation_declarations[ $combined_feature_selectors ] = array_merge( $style_variation_declarations[ $combined_feature_selectors ], $new_feature_declarations );
} else {
$style_variation_declarations[ $combined_feature_selectors ] = $new_feature_declarations;
}

/*
* Remove the feature from the variation's node now the
* styles will be included under the feature level selector.
*/
unset( $style_variation_node[ $feature_name ] );

}
}
// Compute declarations for remaining styles not covered by feature level selectors.
Expand Down
294 changes: 294 additions & 0 deletions phpunit/class-wp-theme-json-test.php
Original file line number Diff line number Diff line change
Expand Up @@ -1504,6 +1504,300 @@ public function test_get_styles_for_block_with_content_width() {
$this->assertEquals( $expected, $root_rules . $style_rules );
}

/**
* @dataProvider data_sanitize_for_block_with_style_variations
*
* @param array $theme_json_variations Theme.json variations to test.
* @param array $expected_sanitized Expected results after sanitizing.
*/
public function test_sanitize_for_block_with_style_variations( $theme_json_variations, $expected_sanitized ) {
$theme_json = new WP_Theme_JSON_Gutenberg(
array(
'version' => 2,
'styles' => array(
'blocks' => array(
'core/quote' => $theme_json_variations,
),
),
)
);

// Validate structure is sanitized.
$sanitized_theme_json = $theme_json->get_raw_data();
$this->assertIsArray( $sanitized_theme_json, 'Sanitized theme.json is not an array data type' );
$this->assertArrayHasKey( 'styles', $sanitized_theme_json, 'Sanitized theme.json does not have an "styles" key' );
$this->assertSameSetsWithIndex( $expected_sanitized, $sanitized_theme_json['styles'], 'Sanitized theme.json styles does not match' );
}

/**
* Data provider.
*
* @return array
*/
public function data_sanitize_for_block_with_style_variations() {
return array(
'1 variation with 1 invalid property' => array(
'theme_json_variations' => array(
'variations' => array(
'plain' => array(
'color' => array(
'background' => 'hotpink',
),
),
),
),
'expected_sanitized' => array(
'blocks' => array(
'core/quote' => array(
'variations' => array(
'plain' => array(
'color' => array(
'background' => 'hotpink',
),
),
),
),
),
),
),
'1 variation with 2 invalid properties' => array(
'theme_json_variations' => array(
'variations' => array(
'plain' => array(
'color' => array(
'background' => 'hotpink',
),
'invalidProperty1' => 'value1',
'invalidProperty2' => 'value2',
),
),
),
'expected_sanitized' => array(
'blocks' => array(
'core/quote' => array(
'variations' => array(
'plain' => array(
'color' => array(
'background' => 'hotpink',
),
),
),
),
),
),
),
'2 variations with 1 invalid property' => array(
'theme_json_variations' => array(
'variations' => array(
'plain' => array(
'color' => array(
'background' => 'hotpink',
),
'invalidProperty1' => 'value1',
),
'basic' => array(
'color' => array(
'background' => '#ffffff',
'text' => '#000000',
),
'foo' => 'bar',
),
),
),
'expected_sanitized' => array(
'blocks' => array(
'core/quote' => array(
'variations' => array(
'plain' => array(
'color' => array(
'background' => 'hotpink',
),
),
'basic' => array(
'color' => array(
'background' => '#ffffff',
'text' => '#000000',
),
),
),
),
),
),
),
);
}

/**
* @dataProvider data_sanitize_with_invalid_style_variation
*
* @param array $theme_json_variations The theme.json variations to test.
*/
public function test_sanitize_with_invalid_style_variation( $theme_json_variations ) {
$theme_json = new WP_Theme_JSON_Gutenberg(
array(
'version' => 2,
'styles' => array(
'blocks' => array(
'core/quote' => $theme_json_variations,
),
),
)
);

// Validate structure is sanitized.
$sanitized_theme_json = $theme_json->get_raw_data();
$this->assertIsArray( $sanitized_theme_json, 'Sanitized theme.json is not an array data type' );
$this->assertArrayNotHasKey( 'styles', $sanitized_theme_json, 'Sanitized theme.json should not have a "styles" key' );

}

/**
* Data provider.
*
* @return array
*/
public function data_sanitize_with_invalid_style_variation() {
return array(
'empty string variation' => array(
array(
'variations' => '',
),
),
'boolean variation' => array(
array(
'variations' => false,
),
),
);
}

/**
* @dataProvider data_get_styles_for_block_with_style_variations
*
* @param array $theme_json_variations Theme.json variations to test.
* @param string $metadata_variations Style variations to test.
* @param string $expected Expected results for styling.
*/
public function test_get_styles_for_block_with_style_variations( $theme_json_variations, $metadata_variations, $expected ) {
$theme_json = new WP_Theme_JSON_Gutenberg(
array(
'version' => 2,
'styles' => array(
'blocks' => array(
'core/quote' => $theme_json_variations,
),
),
)
);

// Validate styles are generated properly.
$metadata = array(
'path' => array( 'styles', 'blocks', 'core/quote' ),
'selector' => '.wp-block-quote',
'variations' => $metadata_variations,
);
$actual_styles = $theme_json->get_styles_for_block( $metadata );
$this->assertSame( $expected, $actual_styles );
}

/**
* Data provider.
*
* @return array
*/
public function data_get_styles_for_block_with_style_variations() {
$plain = array(
'metadata' => array(
'path' => array( 'styles', 'blocks', 'core/quote', 'variations', 'plain' ),
'selector' => '.is-style-plain.is-style-plain.wp-block-quote',
),
'styles' => '.is-style-plain.is-style-plain.wp-block-quote{background-color: hotpink;}',
);
$basic = array(
'metadata' => array(
'path' => array( 'styles', 'blocks', 'core/quote', 'variations', 'basic' ),
'selector' => '.is-style-basic.is-style-basic.wp-block-quote',
),
'styles' => '.is-style-basic.is-style-basic.wp-block-quote{background-color: #ffffff;color: #000000;}',
);

return array(
'1 variation with 1 invalid property' => array(
'theme_json_variations' => array(
'variations' => array(
'plain' => array(
'color' => array(
'background' => 'hotpink',
),
),
),
),
'metadata_variation' => array( $plain['metadata'] ),
'expected' => $plain['styles'],
),
'1 variation with 2 invalid properties' => array(
'theme_json_variations' => array(
'variations' => array(
'plain' => array(
'color' => array(
'background' => 'hotpink',
),
'invalidProperty1' => 'value1',
'invalidProperty2' => 'value2',
),
),
),
'metadata_variation' => array( $plain['metadata'] ),
'expected' => $plain['styles'],
),
'2 variations with 1 invalid property' => array(
'theme_json_variations' => array(
'variations' => array(
'plain' => array(
'color' => array(
'background' => 'hotpink',
),
'invalidProperty1' => 'value1',
),
'basic' => array(
'color' => array(
'background' => '#ffffff',
'text' => '#000000',
),
'foo' => 'bar',
),
),
),
'metadata_variation' => array( $plain['metadata'], $basic['metadata'] ),
'expected_styles' => $plain['styles'] . $basic['styles'],
),
'2 variations with multiple invalid properties' => array(
'theme_json_variations' => array(
'variations' => array(
'plain' => array(
'color' => array(
'background' => 'hotpink',
),
'invalidProperty1' => 'value1',
'invalidProperty2' => 'value2',
),
'basic' => array(
'foo' => 'foo',
'color' => array(
'background' => '#ffffff',
'text' => '#000000',
),
'bar' => 'bar',
'baz' => 'baz',
),
),
),
'metadata_variation' => array( $plain['metadata'], $basic['metadata'] ),
'expected_styles' => $plain['styles'] . $basic['styles'],
),
);
}

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(
Expand Down

1 comment on commit 0fbd15a

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flaky tests detected in 0fbd15a.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/4072145148
📝 Reported issues:

Please sign in to comment.