Skip to content

Commit da16e42

Browse files
authored
Make child themes inherit parent's style variations. (#46554)
* Include parent theme dir in style variation getter. * Fix mismatched variable names. * Refactor to static utility function. * Check for naming collisions via basename. * Fix linting errors and warnings. * Rebase trunk. * Update version since. * Use _Gutenberg class. * Add back line break. * Fix linting errors. * Refactor to allow parent theme variations to show up when child has no variations. * Add unit test for resolver class. * Comment the test. * Fix lint. * Rename variations to account for child overwriting parent variation.
1 parent 77aec3d commit da16e42

File tree

8 files changed

+190
-18
lines changed

8 files changed

+190
-18
lines changed

lib/class-wp-theme-json-resolver-gutenberg.php

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -670,32 +670,58 @@ public static function clean_cached_data() {
670670
}
671671

672672
/**
673-
* Returns the style variations defined by the theme.
673+
* Returns an array of all nested json files within a given directory.
674674
*
675-
* @since 6.0.0
675+
* @since 6.2.0
676+
*
677+
* @param dir $dir The directory to recursively iterate and list files of.
678+
* @return array The merged array.
679+
*/
680+
private static function recursively_iterate_json( $dir ) {
681+
$nested_files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $dir ) );
682+
$nested_json_files = iterator_to_array( new RegexIterator( $nested_files, '/^.+\.json$/i', RecursiveRegexIterator::GET_MATCH ) );
683+
return $nested_json_files;
684+
}
685+
686+
/**
687+
* Returns the style variations defined by the theme (parent and child).
688+
*
689+
* @since 6.2.0 Returns parent theme variations if theme is a child.
676690
*
677691
* @return array
678692
*/
679693
public static function get_style_variations() {
680-
$variations = array();
681-
$base_directory = get_stylesheet_directory() . '/styles';
694+
$variation_files = array();
695+
$variations = array();
696+
$base_directory = get_stylesheet_directory() . '/styles';
697+
$template_directory = get_template_directory() . '/styles';
682698
if ( is_dir( $base_directory ) ) {
683-
$nested_files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $base_directory ) );
684-
$nested_html_files = iterator_to_array( new RegexIterator( $nested_files, '/^.+\.json$/i', RecursiveRegexIterator::GET_MATCH ) );
685-
ksort( $nested_html_files );
686-
foreach ( $nested_html_files as $path => $file ) {
687-
$decoded_file = wp_json_file_decode( $path, array( 'associative' => true ) );
688-
if ( is_array( $decoded_file ) ) {
689-
$translated = static::translate( $decoded_file, wp_get_theme()->get( 'TextDomain' ) );
690-
$variation = ( new WP_Theme_JSON_Gutenberg( $translated ) )->get_raw_data();
691-
if ( empty( $variation['title'] ) ) {
692-
$variation['title'] = basename( $path, '.json' );
699+
$variation_files = static::recursively_iterate_json( $base_directory );
700+
}
701+
if ( is_dir( $template_directory ) && $template_directory !== $base_directory ) {
702+
$variation_files_parent = static::recursively_iterate_json( $template_directory );
703+
// If the child and parent variation file basename are the same, only include the child theme's.
704+
foreach ( $variation_files_parent as $parent_path => $parent ) {
705+
foreach ( $variation_files as $child_path => $child ) {
706+
if ( basename( $parent_path ) === basename( $child_path ) ) {
707+
unset( $variation_files_parent[ $parent_path ] );
693708
}
694-
$variations[] = $variation;
695709
}
696710
}
711+
$variation_files = array_merge( $variation_files, $variation_files_parent );
712+
}
713+
ksort( $variation_files );
714+
foreach ( $variation_files as $path => $file ) {
715+
$decoded_file = wp_json_file_decode( $path, array( 'associative' => true ) );
716+
if ( is_array( $decoded_file ) ) {
717+
$translated = static::translate( $decoded_file, wp_get_theme()->get( 'TextDomain' ) );
718+
$variation = ( new WP_Theme_JSON_Gutenberg( $translated ) )->get_raw_data();
719+
if ( empty( $variation['title'] ) ) {
720+
$variation['title'] = basename( $path, '.json' );
721+
}
722+
$variations[] = $variation;
723+
}
697724
}
698725
return $variations;
699726
}
700-
701727
}

lib/compat/wordpress-6.2/class-gutenberg-rest-global-styles-controller-6-2.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,4 +275,30 @@ public function get_theme_item( $request ) {
275275

276276
return $response;
277277
}
278+
279+
/**
280+
* Returns the given theme global styles variations.
281+
*
282+
* @since 6.0.0
283+
* @since 6.2.0 Returns parent theme variations, if they exist.
284+
*
285+
* @param WP_REST_Request $request The request instance.
286+
*
287+
* @return WP_REST_Response|WP_Error
288+
*/
289+
public function get_theme_items( $request ) {
290+
if ( get_stylesheet() !== $request['stylesheet'] ) {
291+
// This endpoint only supports the active or parent theme for now.
292+
return new WP_Error(
293+
sprintf( '%s', $request['template'] ),
294+
__( 'Theme not found.', 'gutenberg' ),
295+
array( 'status' => 404 )
296+
);
297+
}
298+
299+
$variations = WP_Theme_JSON_Resolver_Gutenberg::get_style_variations();
300+
$response = rest_ensure_response( $variations );
301+
302+
return $response;
303+
}
278304
}

phpunit/class-wp-theme-json-resolver-test.php

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,4 +503,70 @@ public function data_get_merged_data_returns_origin() {
503503
);
504504
}
505505

506+
507+
/**
508+
* Test that get_style_variations returns all variations, including parent theme variations if the theme is a child,
509+
* and that the child variation overwrites the parent variation of the same name.
510+
*
511+
* @covers WP_Theme_JSON_Resolver::get_style_variations
512+
**/
513+
public function test_get_style_variations_returns_all_variations() {
514+
// Switch to a child theme.
515+
switch_theme( 'block-theme-child' );
516+
wp_set_current_user( self::$administrator_id );
517+
518+
$actual_settings = WP_Theme_JSON_Resolver_Gutenberg::get_style_variations();
519+
$expected_settings = array(
520+
array(
521+
'version' => 2,
522+
'title' => 'variation-a',
523+
'settings' => array(
524+
'blocks' => array(
525+
'core/paragraph' => array(
526+
'color' => array(
527+
'palette' => array(
528+
'theme' => array(
529+
array(
530+
'slug' => 'dark',
531+
'name' => 'Dark',
532+
'color' => '#010101',
533+
),
534+
),
535+
),
536+
),
537+
),
538+
),
539+
),
540+
),
541+
array(
542+
'version' => 2,
543+
'title' => 'variation-b',
544+
'settings' => array(
545+
'blocks' => array(
546+
'core/post-title' => array(
547+
'color' => array(
548+
'palette' => array(
549+
'theme' => array(
550+
array(
551+
'slug' => 'light',
552+
'name' => 'Light',
553+
'color' => '#f1f1f1',
554+
),
555+
),
556+
),
557+
),
558+
),
559+
),
560+
),
561+
),
562+
);
563+
self::recursive_ksort( $actual_settings );
564+
self::recursive_ksort( $expected_settings );
565+
566+
$this->assertSame(
567+
$expected_settings,
568+
$actual_settings
569+
);
570+
}
571+
506572
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"version": 2,
3+
"settings": {
4+
"blocks": {
5+
"core/paragraph": {
6+
"color": {
7+
"palette": [
8+
{
9+
"slug": "dark",
10+
"name": "Dark",
11+
"color": "#010101"
12+
}
13+
]
14+
}
15+
}
16+
}
17+
}
18+
}

phpunit/data/themedir1/block-theme-child/theme.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": 1,
2+
"version": 2,
33
"settings": {
44
"color": {
55
"palette": [
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"version": 2,
3+
"settings": {
4+
"blocks": {
5+
"core/paragraph": {
6+
"color": {
7+
"palette": [
8+
{
9+
"slug": "light",
10+
"name": "Light",
11+
"color": "#f2f2f2"
12+
}
13+
]
14+
}
15+
}
16+
}
17+
}
18+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"version": 2,
3+
"settings": {
4+
"blocks": {
5+
"core/post-title": {
6+
"color": {
7+
"palette": [
8+
{
9+
"slug": "light",
10+
"name": "Light",
11+
"color": "#f1f1f1"
12+
}
13+
]
14+
}
15+
}
16+
}
17+
}
18+
}

phpunit/data/themedir1/block-theme/theme.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": 1,
2+
"version": 2,
33
"settings": {
44
"color": {
55
"palette": [

0 commit comments

Comments
 (0)