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

Make child themes inherit parent's style variations. #46554

Merged
merged 15 commits into from
Jan 18, 2023
58 changes: 42 additions & 16 deletions lib/class-wp-theme-json-resolver-gutenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -670,32 +670,58 @@ public static function clean_cached_data() {
}

/**
* Returns the style variations defined by the theme.
* Returns an array of all nested json files within a given directory.
*
* @since 6.0.0
* @since 6.2.0
*
* @param dir $dir The directory to recursively iterate and list files of.
* @return array The merged array.
*/
private static function recursively_iterate_json( $dir ) {
$nested_files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $dir ) );
$nested_json_files = iterator_to_array( new RegexIterator( $nested_files, '/^.+\.json$/i', RecursiveRegexIterator::GET_MATCH ) );
return $nested_json_files;
}

/**
* Returns the style variations defined by the theme (parent and child).
*
* @since 6.2.0 Returns parent theme variations if theme is a child.
*
* @return array
*/
public static function get_style_variations() {
$variations = array();
$base_directory = get_stylesheet_directory() . '/styles';
$variation_files = array();
$variations = array();
$base_directory = get_stylesheet_directory() . '/styles';
$template_directory = get_template_directory() . '/styles';
if ( is_dir( $base_directory ) ) {
$nested_files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $base_directory ) );
$nested_html_files = iterator_to_array( new RegexIterator( $nested_files, '/^.+\.json$/i', RecursiveRegexIterator::GET_MATCH ) );
ksort( $nested_html_files );
foreach ( $nested_html_files as $path => $file ) {
$decoded_file = wp_json_file_decode( $path, array( 'associative' => true ) );
if ( is_array( $decoded_file ) ) {
$translated = static::translate( $decoded_file, wp_get_theme()->get( 'TextDomain' ) );
$variation = ( new WP_Theme_JSON_Gutenberg( $translated ) )->get_raw_data();
if ( empty( $variation['title'] ) ) {
$variation['title'] = basename( $path, '.json' );
$variation_files = static::recursively_iterate_json( $base_directory );
}
if ( is_dir( $template_directory ) && $template_directory !== $base_directory ) {
$variation_files_parent = static::recursively_iterate_json( $template_directory );
// If the child and parent variation file basename are the same, only include the child theme's.
foreach ( $variation_files_parent as $parent_path => $parent ) {
foreach ( $variation_files as $child_path => $child ) {
if ( basename( $parent_path ) === basename( $child_path ) ) {
unset( $variation_files_parent[ $parent_path ] );
}
$variations[] = $variation;
}
}
$variation_files = array_merge( $variation_files, $variation_files_parent );
}
ksort( $variation_files );
foreach ( $variation_files as $path => $file ) {
$decoded_file = wp_json_file_decode( $path, array( 'associative' => true ) );
if ( is_array( $decoded_file ) ) {
$translated = static::translate( $decoded_file, wp_get_theme()->get( 'TextDomain' ) );
$variation = ( new WP_Theme_JSON_Gutenberg( $translated ) )->get_raw_data();
if ( empty( $variation['title'] ) ) {
$variation['title'] = basename( $path, '.json' );
}
$variations[] = $variation;
}
}
return $variations;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -252,4 +252,30 @@ public function get_theme_item( $request ) {

return $response;
}

/**
* Returns the given theme global styles variations.
*
* @since 6.0.0
* @since 6.2.0 Returns parent theme variations, if they exist.
*
* @param WP_REST_Request $request The request instance.
*
* @return WP_REST_Response|WP_Error
*/
public function get_theme_items( $request ) {
if ( get_stylesheet() !== $request['stylesheet'] ) {
// This endpoint only supports the active or parent theme for now.
return new WP_Error(
sprintf( '%s', $request['template'] ),
__( 'Theme not found.', 'gutenberg' ),
array( 'status' => 404 )
);
}

$variations = WP_Theme_JSON_Resolver_Gutenberg::get_style_variations();
$response = rest_ensure_response( $variations );

return $response;
}
}
66 changes: 66 additions & 0 deletions phpunit/class-wp-theme-json-resolver-test.php
Original file line number Diff line number Diff line change
Expand Up @@ -503,4 +503,70 @@ public function data_get_merged_data_returns_origin() {
);
}


/**
* Test that get_style_variations returns all variations, including parent theme variations if the theme is a child,
* and that the child variation overwrites the parent variation of the same name.
*
* @covers WP_Theme_JSON_Resolver::get_style_variations
**/
public function test_get_style_variations_returns_all_variations() {
// Switch to a child theme.
switch_theme( 'block-theme-child' );
wp_set_current_user( self::$administrator_id );

$actual_settings = WP_Theme_JSON_Resolver_Gutenberg::get_style_variations();
$expected_settings = array(
array(
'version' => 2,
'title' => 'variation-a',
'settings' => array(
'blocks' => array(
'core/paragraph' => array(
'color' => array(
'palette' => array(
'theme' => array(
array(
'slug' => 'dark',
'name' => 'Dark',
'color' => '#010101',
),
),
),
),
),
),
),
),
array(
'version' => 2,
'title' => 'variation-b',
'settings' => array(
'blocks' => array(
'core/post-title' => array(
'color' => array(
'palette' => array(
'theme' => array(
array(
'slug' => 'light',
'name' => 'Light',
'color' => '#f1f1f1',
),
),
),
),
),
),
),
),
);
self::recursive_ksort( $actual_settings );
self::recursive_ksort( $expected_settings );

$this->assertSame(
$expected_settings,
$actual_settings
);
}

}
18 changes: 18 additions & 0 deletions phpunit/data/themedir1/block-theme-child/styles/variation-a.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"version": 2,
"settings": {
"blocks": {
"core/paragraph": {
"color": {
"palette": [
{
"slug": "dark",
"name": "Dark",
"color": "#010101"
}
]
}
}
}
}
}
2 changes: 1 addition & 1 deletion phpunit/data/themedir1/block-theme-child/theme.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": 1,
"version": 2,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I updated the version number here, which seems like it was incorrect to begin with since it was already using the customTemplates and templateParts properties which were added in v2.

"settings": {
"color": {
"palette": [
Expand Down
18 changes: 18 additions & 0 deletions phpunit/data/themedir1/block-theme/styles/variation-a.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"version": 2,
"settings": {
"blocks": {
"core/paragraph": {
"color": {
"palette": [
{
"slug": "light",
"name": "Light",
"color": "#f2f2f2"
}
]
}
}
}
}
}
18 changes: 18 additions & 0 deletions phpunit/data/themedir1/block-theme/styles/variation-b.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"version": 2,
"settings": {
"blocks": {
"core/post-title": {
"color": {
"palette": [
{
"slug": "light",
"name": "Light",
"color": "#f1f1f1"
}
]
}
}
}
}
}
2 changes: 1 addition & 1 deletion phpunit/data/themedir1/block-theme/theme.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": 1,
"version": 2,
"settings": {
"color": {
"palette": [
Expand Down