Skip to content

Commit

Permalink
Code improvements and tests for theme json class
Browse files Browse the repository at this point in the history
  • Loading branch information
tellthemachines committed Feb 2, 2023
1 parent f66aa3a commit e39e451
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

0 comments on commit e39e451

Please sign in to comment.