PluginProbe
Gutenberg / 17.0.2
Gutenberg v17.0.2
24.0.0 23.9.1 23.9.0 23.8.0 23.7.2 23.7.1 23.7.0 23.6.1 23.6.2 23.6.0 23.5.3 23.5.2 23.5.1 23.5.0 23.4.0 23.3.2 23.3.1 23.3.0 23.2.0 23.2.1 23.2.2 23.1.1 23.1.0 23.0.1 12.6.0 All 403 releases
← All changes | lib/class-wp-theme-json-resolver-gutenberg.php +84 -328 23.7.0 → 17.0.2 View file →
@@ -1,12 +1,16 @@
1 1 <?php
2 2 /**
3 - * WP_Theme_JSON_Resolver_Gutenberg class
3 + * WP_Theme_JSON_Resolver class
4 4 *
5 5 * @package gutenberg
6 6 * @since 5.8.0
7 7 */
8 8
9 +if ( class_exists( 'WP_Theme_JSON_Resolver_Gutenberg' ) ) {
10 + return;
11 +}
12 +
9 13 /**
10 14 * Class that abstracts the processing of the different data sources
11 15 * for site-level config and offers an API to work with them.
12 16 *
@@ -13,9 +17,8 @@
13 17 * This class is for internal core usage and is not supposed to be used by extenders (plugins and/or themes).
14 18 * This is a low-level API that may need to do breaking changes. Please,
15 19 * use gutenberg_get_global_settings, gutenberg_get_global_styles, and gutenberg_get_global_stylesheet instead.
16 20 *
17 - * @since 5.8.0
18 21 * @access private
19 22 */
20 23 #[AllowDynamicProperties]
21 24 class WP_Theme_JSON_Resolver_Gutenberg {
@@ -36,9 +39,9 @@
36 39 /**
37 40 * Container for data coming from core.
38 41 *
39 42 * @since 5.8.0
40 - * @var WP_Theme_JSON_Gutenberg
43 + * @var WP_Theme_JSON
41 44 */
42 45 protected static $core = null;
43 46
44 47 /**
@@ -44,9 +47,9 @@
44 47 /**
45 48 * Container for data coming from the blocks.
46 49 *
47 50 * @since 6.1.0
48 - * @var WP_Theme_JSON_Gutenberg
51 + * @var WP_Theme_JSON
49 52 */
50 53 protected static $blocks = null;
51 54
52 55 /**
@@ -52,9 +55,9 @@
52 55 /**
53 56 * Container for data coming from the theme.
54 57 *
55 58 * @since 5.8.0
56 - * @var WP_Theme_JSON_Gutenberg
59 + * @var WP_Theme_JSON
57 60 */
58 61 protected static $theme = null;
59 62
60 63 /**
@@ -60,9 +63,9 @@
60 63 /**
61 64 * Container for data coming from the user.
62 65 *
63 66 * @since 5.9.0
64 - * @var WP_Theme_JSON_Gutenberg
67 + * @var WP_Theme_JSON
65 68 */
66 69 protected static $user = null;
67 70
68 71 /**
@@ -143,9 +146,9 @@
143 146 */
144 147 protected static function translate( $theme_json, $domain = 'default' ) {
145 148 if ( null === static::$i18n_schema ) {
146 149 $i18n_schema = wp_json_file_decode( __DIR__ . '/theme-i18n.json' );
147 - static::$i18n_schema = $i18n_schema ?? array();
150 + static::$i18n_schema = null === $i18n_schema ? array() : $i18n_schema;
148 151 }
149 152
150 153 return translate_settings_using_i18n_schema( static::$i18n_schema, $theme_json, $domain );
151 154 }
@@ -154,9 +157,9 @@
154 157 * Returns core's origin config.
155 158 *
156 159 * @since 5.8.0
157 160 *
158 - * @return WP_Theme_JSON_Gutenberg Entity that holds core data.
161 + * @return WP_Theme_JSON Entity that holds core data.
159 162 */
160 163 public static function get_core_data() {
161 164 if ( null !== static::$core && static::has_same_registered_blocks( 'core' ) ) {
162 165 return static::$core;
@@ -169,12 +172,13 @@
169 172 * Filters the default data provided by WordPress for global styles & settings.
170 173 *
171 174 * @since 6.1.0
172 175 *
173 - * @param WP_Theme_JSON_Data_Gutenberg Class to access and update the underlying data.
176 + * @param WP_Theme_JSON_Data Class to access and update the underlying data.
174 177 */
175 178 $theme_json = apply_filters( 'wp_theme_json_data_default', new WP_Theme_JSON_Data_Gutenberg( $config, 'default' ) );
176 - static::$core = $theme_json->get_theme_json();
179 + $config = $theme_json->get_data();
180 + static::$core = new WP_Theme_JSON_Gutenberg( $config, 'default' );
177 181
178 182 return static::$core;
179 183 }
180 184
@@ -219,10 +223,8 @@
219 223 *
220 224 * @since 5.8.0
221 225 * @since 5.9.0 Theme supports have been inlined and the `$theme_support_data` argument removed.
222 226 * @since 6.0.0 Added an `$options` parameter to allow the theme data to be returned without theme supports.
223 - * @since 6.6.0 Added support for 'default-font-sizes' and 'default-spacing-sizes' theme supports.
224 - * Added registration and merging of block style variations from partial theme.json files and the block styles registry.
225 227 *
226 228 * @param array $deprecated Deprecated. Not used.
227 229 * @param array $options {
228 230 * Options arguments.
@@ -228,9 +230,9 @@
228 230 * Options arguments.
229 231 *
230 232 * @type bool $with_supports Whether to include theme supports in the data. Default true.
231 233 * }
232 - * @return WP_Theme_JSON_Gutenberg Entity that holds theme data.
234 + * @return WP_Theme_JSON Entity that holds theme data.
233 235 */
234 236 public static function get_theme_data( $deprecated = array(), $options = array() ) {
235 237 if ( ! empty( $deprecated ) ) {
236 238 _deprecated_argument( __METHOD__, '5.9.0' );
@@ -244,43 +246,21 @@
244 246 if ( is_readable( $theme_json_file ) ) {
245 247 $theme_json_data = static::read_json_file( $theme_json_file );
246 248 $theme_json_data = static::translate( $theme_json_data, $wp_theme->get( 'TextDomain' ) );
247 249 } else {
248 - $theme_json_data = array( 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA );
250 + $theme_json_data = array();
249 251 }
250 252
251 - /*
252 - * Register variations defined by theme partials (theme.json files in the styles directory).
253 - * This is required so the variations pass sanitization of theme.json data.
254 - */
255 - $variations = static::get_style_variations( 'block' );
256 - gutenberg_register_block_style_variations_from_theme_json_partials( $variations );
257 -
258 - /*
259 - * Source variations from the block styles registry and block style variation files. Then, merge them into the existing theme.json data.
260 - *
261 - * In case the same style properties are defined in several sources, this is how we should resolve the values,
262 - * from higher to lower priority:
263 - *
264 - * - styles.blocks.blockType.variations from theme.json
265 - * - styles.variations from theme.json
266 - * - variations from block style variation files
267 - * - variations from block styles registry
268 - *
269 - * See test_add_registered_block_styles_to_theme_data and test_unwraps_block_style_variations.
270 - */
271 - $theme_json_data = static::inject_variations_from_block_style_variation_files( $theme_json_data, $variations );
272 - $theme_json_data = static::inject_variations_from_block_styles_registry( $theme_json_data );
273 -
274 253 /**
275 254 * Filters the data provided by the theme for global styles and settings.
276 255 *
277 256 * @since 6.1.0
278 257 *
279 - * @param WP_Theme_JSON_Data_Gutenberg Class to access and update the underlying data.
258 + * @param WP_Theme_JSON_Data Class to access and update the underlying data.
280 259 */
281 - $theme_json = apply_filters( 'wp_theme_json_data_theme', new WP_Theme_JSON_Data_Gutenberg( $theme_json_data, 'theme' ) );
282 - static::$theme = $theme_json->get_theme_json();
260 + $theme_json = apply_filters( 'wp_theme_json_data_theme', new WP_Theme_JSON_Data_Gutenberg( $theme_json_data, 'theme' ) );
261 + $theme_json_data = $theme_json->get_data();
262 + static::$theme = new WP_Theme_JSON_Gutenberg( $theme_json_data );
283 263
284 264 if ( $wp_theme->parent() ) {
285 265 // Get parent theme.json.
286 266 $parent_theme_json_file = $wp_theme->parent()->get_file_path( 'theme.json' );
@@ -317,35 +297,35 @@
317 297 * and merge the static::$theme upon that.
318 298 */
319 299 $theme_support_data = WP_Theme_JSON_Gutenberg::get_from_editor_settings( get_classic_theme_supports_block_editor_settings() );
320 300 if ( ! wp_theme_has_theme_json() ) {
321 - /*
322 - * Unlike block themes, classic themes without a theme.json disable
323 - * default presets when custom preset theme support is added. This
324 - * behavior can be overridden by using the corresponding default
325 - * preset theme support.
326 - */
327 - $theme_support_data['settings']['color']['defaultPalette'] =
328 - ! isset( $theme_support_data['settings']['color']['palette'] ) ||
329 - current_theme_supports( 'default-color-palette' );
330 - $theme_support_data['settings']['color']['defaultGradients'] =
331 - ! isset( $theme_support_data['settings']['color']['gradients'] ) ||
332 - current_theme_supports( 'default-gradient-presets' );
333 - $theme_support_data['settings']['typography']['defaultFontSizes'] =
334 - ! isset( $theme_support_data['settings']['typography']['fontSizes'] ) ||
335 - current_theme_supports( 'default-font-sizes' );
336 - $theme_support_data['settings']['spacing']['defaultSpacingSizes'] =
337 - ! isset( $theme_support_data['settings']['spacing']['spacingSizes'] ) ||
338 - current_theme_supports( 'default-spacing-sizes' );
301 + if ( ! isset( $theme_support_data['settings']['color'] ) ) {
302 + $theme_support_data['settings']['color'] = array();
303 + }
339 304
340 - /*
341 - * Shadow presets are explicitly disabled for classic themes until a
342 - * decision is made for whether the default presets should match the
343 - * other presets or if they should be disabled by default in classic
344 - * themes. See https://github.com/WordPress/gutenberg/issues/59989.
345 - */
346 - $theme_support_data['settings']['shadow']['defaultPresets'] = false;
305 + $default_palette = false;
306 + if ( current_theme_supports( 'default-color-palette' ) ) {
307 + $default_palette = true;
308 + }
309 + if ( ! isset( $theme_support_data['settings']['color']['palette'] ) ) {
310 + // If the theme does not have any palette, we still want to show the core one.
311 + $default_palette = true;
312 + }
313 + $theme_support_data['settings']['color']['defaultPalette'] = $default_palette;
347 314
315 + $default_gradients = false;
316 + if ( current_theme_supports( 'default-gradient-presets' ) ) {
317 + $default_gradients = true;
318 + }
319 + if ( ! isset( $theme_support_data['settings']['color']['gradients'] ) ) {
320 + // If the theme does not have any gradients, we still want to show the core ones.
321 + $default_gradients = true;
322 + }
323 + $theme_support_data['settings']['color']['defaultGradients'] = $default_gradients;
324 +
325 + // Classic themes without a theme.json don't support global duotone.
326 + $theme_support_data['settings']['color']['defaultDuotone'] = false;
327 +
348 328 // Allow themes to enable all border settings via theme_support.
349 329 if ( current_theme_supports( 'border' ) ) {
350 330 $theme_support_data['settings']['border']['color'] = true;
351 331 $theme_support_data['settings']['border']['radius'] = true;
@@ -358,18 +338,23 @@
358 338 $theme_support_data['settings']['color']['link'] = true;
359 339 }
360 340 if ( current_theme_supports( 'experimental-link-color' ) ) {
361 341 _doing_it_wrong(
362 - "add_theme_support( 'experimental-link-color' )",
342 + current_theme_supports( 'experimental-link-color' ),
363 343 __( '`experimental-link-color` is no longer supported. Use `link-color` instead.', 'gutenberg' ),
364 344 '6.3.0'
365 345 );
366 346 }
367 347
348 + // BEGIN EXPERIMENTAL.
368 349 // Allow themes to enable appearance tools via theme_support.
350 + // This feature was backported for WordPress 6.2 as of https://core.trac.wordpress.org/ticket/56487
351 + // and then reverted as of https://core.trac.wordpress.org/ticket/57649
352 + // Not to backport until the issues are resolved.
369 353 if ( current_theme_supports( 'appearance-tools' ) ) {
370 354 $theme_support_data['settings']['appearanceTools'] = true;
371 355 }
356 + // END EXPERIMENTAL.
372 357 }
373 358 $with_theme_supports = new WP_Theme_JSON_Gutenberg( $theme_support_data );
374 359 $with_theme_supports->merge( static::$theme );
375 360 return $with_theme_supports;
@@ -379,9 +364,9 @@
379 364 * Gets the styles for blocks from the block.json file.
380 365 *
381 366 * @since 6.1.0
382 367 *
383 - * @return WP_Theme_JSON_Gutenberg
368 + * @return WP_Theme_JSON
384 369 */
385 370 public static function get_block_data() {
386 371 $registry = WP_Block_Type_Registry::get_instance();
387 372 $blocks = $registry->get_all_registered();
@@ -389,9 +374,9 @@
389 374 if ( null !== static::$blocks && static::has_same_registered_blocks( 'blocks' ) ) {
390 375 return static::$blocks;
391 376 }
392 377
393 - $config = array( 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA );
378 + $config = array( 'version' => 2 );
394 379 foreach ( $blocks as $block_name => $block_type ) {
395 380 if ( isset( $block_type->supports['__experimentalStyle'] ) ) {
396 381 $config['styles']['blocks'][ $block_name ] = static::remove_json_comments( $block_type->supports['__experimentalStyle'] );
397 382 }
@@ -410,13 +395,14 @@
410 395 * Filters the data provided by the blocks for global styles & settings.
411 396 *
412 397 * @since 6.1.0
413 398 *
414 - * @param WP_Theme_JSON_Data_Gutenberg Class to access and update the underlying data.
399 + * @param WP_Theme_JSON_Data Class to access and update the underlying data.
415 400 */
416 - $theme_json = apply_filters( 'wp_theme_json_data_blocks', new WP_Theme_JSON_Data_Gutenberg( $config, 'blocks' ) );
417 - static::$blocks = $theme_json->get_theme_json();
401 + $theme_json = apply_filters( 'wp_theme_json_data_blocks', new WP_Theme_JSON_Data_Gutenberg( $config, 'blocks' ) );
402 + $config = $theme_json->get_data();
418 403
404 + static::$blocks = new WP_Theme_JSON_Gutenberg( $config, 'blocks' );
419 405 return static::$blocks;
420 406 }
421 407
422 408 /**
@@ -458,8 +444,19 @@
458 444 if ( ! $theme instanceof WP_Theme ) {
459 445 $theme = wp_get_theme();
460 446 }
461 447
448 + /*
449 + * Bail early if the theme does not support a theme.json.
450 + *
451 + * Since wp_theme_has_theme_json only supports the active
452 + * theme, the extra condition for whether $theme is the active theme is
453 + * present here.
454 + */
455 + if ( $theme->get_stylesheet() === get_stylesheet() && ! wp_theme_has_theme_json() ) {
456 + return array();
457 + }
458 +
462 459 $user_cpt = array();
463 460 $post_type_filter = 'wp_global_styles';
464 461 $stylesheet = $theme->get_stylesheet();
465 462 $args = array(
@@ -482,9 +479,9 @@
482 479 );
483 480
484 481 $global_style_query = new WP_Query();
485 482 $recent_posts = $global_style_query->query( $args );
486 - if ( count( $recent_posts ) === 1 && $recent_posts[0] instanceof WP_Post ) {
483 + if ( count( $recent_posts ) === 1 ) {
487 484 $user_cpt = get_object_vars( $recent_posts[0] );
488 485 } elseif ( $create_post ) {
489 486 $cpt_post_id = wp_insert_post(
490 487 array(
@@ -499,12 +496,9 @@
499 496 ),
500 497 true
501 498 );
502 499 if ( ! is_wp_error( $cpt_post_id ) ) {
503 - $post = get_post( $cpt_post_id );
504 - if ( $post instanceof WP_Post ) {
505 - $user_cpt = get_object_vars( $post );
506 - }
500 + $user_cpt = get_object_vars( get_post( $cpt_post_id ) );
507 501 }
508 502 }
509 503
510 504 return $user_cpt;
@@ -514,9 +508,9 @@
514 508 * Returns the user's origin config.
515 509 *
516 510 * @since 5.9.0
517 511 *
518 - * @return WP_Theme_JSON_Gutenberg Entity that holds styles for user data.
512 + * @return WP_Theme_JSON Entity that holds styles for user data.
519 513 */
520 514 public static function get_user_data() {
521 515 if ( null !== static::$user && static::has_same_registered_blocks( 'user' ) ) {
522 516 return static::$user;
@@ -535,13 +529,13 @@
535 529 * Filters the data provided by the user for global styles & settings.
536 530 *
537 531 * @since 6.1.0
538 532 *
539 - * @param WP_Theme_JSON_Data_Gutenberg Class to access and update the underlying data.
533 + * @param WP_Theme_JSON_Data Class to access and update the underlying data.
540 534 */
541 535 $theme_json = apply_filters( 'wp_theme_json_data_user', new WP_Theme_JSON_Data_Gutenberg( $config, 'custom' ) );
542 -
543 - return $theme_json->get_theme_json();
536 + $config = $theme_json->get_data();
537 + return new WP_Theme_JSON_Gutenberg( $config, 'custom' );
544 538 }
545 539
546 540 // Very important to verify that the flag isGlobalStylesUserThemeJSON is true.
547 541 // If it's not true then the content was not escaped and is not safe.
@@ -556,9 +550,10 @@
556 550 }
557 551
558 552 /** This filter is documented in wp-includes/class-wp-theme-json-resolver.php */
559 553 $theme_json = apply_filters( 'wp_theme_json_data_user', new WP_Theme_JSON_Data_Gutenberg( $config, 'custom' ) );
560 - static::$user = $theme_json->get_theme_json();
554 + $config = $theme_json->get_data();
555 + static::$user = new WP_Theme_JSON_Gutenberg( $config, 'custom' );
561 556
562 557 return static::$user;
563 558 }
564 559
@@ -594,9 +589,9 @@
594 589 *
595 590 * @param string $origin Optional. To what level should we merge data:'default', 'blocks', 'theme' or 'custom'.
596 591 * 'custom' is used as default value as well as fallback value if the origin is unknown.
597 592 *
598 - * @return WP_Theme_JSON_Gutenberg
593 + * @return WP_Theme_JSON
599 594 */
600 595 public static function get_merged_data( $origin = 'custom' ) {
601 596 if ( is_array( $origin ) ) {
602 597 _deprecated_argument( __FUNCTION__, '5.9.0' );
@@ -604,8 +599,9 @@
604 599
605 600 $result = new WP_Theme_JSON_Gutenberg();
606 601 $result->merge( static::get_core_data() );
607 602 if ( 'default' === $origin ) {
603 + $result->set_spacing_sizes();
608 604 return $result;
609 605 }
610 606
611 607 $result->merge( static::get_block_data() );
@@ -614,12 +610,14 @@
614 610 }
615 611
616 612 $result->merge( static::get_theme_data() );
617 613 if ( 'theme' === $origin ) {
614 + $result->set_spacing_sizes();
618 615 return $result;
619 616 }
620 617
621 618 $result->merge( static::get_user_data() );
619 + $result->set_spacing_sizes();
622 620 return $result;
623 621 }
624 622
625 623 /**
@@ -718,57 +716,17 @@
718 716 return $nested_json_files;
719 717 }
720 718
721 719 /**
722 - * Determines if a supplied style variation matches the provided scope.
723 - *
724 - * For backwards compatibility, if a variation does not define any scope
725 - * related property, e.g. `blockTypes`, it is assumed to be a theme style
726 - * variation.
727 - *
728 - * @since 6.6.0
729 - *
730 - * @param array $variation Theme.json shaped style variation object.
731 - * @param string $scope Scope to check e.g. theme, block etc.
732 - *
733 - * @return boolean
734 - */
735 - private static function style_variation_has_scope( $variation, $scope ) {
736 - if ( 'block' === $scope ) {
737 - return isset( $variation['blockTypes'] );
738 - }
739 -
740 - if ( 'theme' === $scope ) {
741 - return ! isset( $variation['blockTypes'] );
742 - }
743 -
744 - return false;
745 - }
746 -
747 - /**
748 720 * Returns the style variations defined by the theme (parent and child).
749 721 *
750 722 * @since 6.2.0 Returns parent theme variations if theme is a child.
751 - * @since 6.6.0 Added configurable scope parameter to allow filtering
752 - * theme.json partial files by the scope to which they
753 - * can be applied e.g. theme vs block etc.
754 723 *
755 - * @param string $scope The scope or type of style variation to retrieve e.g. theme, block etc.
756 724 * @return array
757 725 */
758 - public static function get_style_variations( $scope = 'theme' ) {
759 - return static::get_style_variations_from_directory( get_stylesheet_directory(), $scope );
760 - }
761 -
762 - /**
763 - * Returns the style variation files defined by the theme (parent and child).
764 - *
765 - * @since 6.7.0
766 - *
767 - * @return array An array of style variation files.
768 - */
769 - protected static function get_style_variation_files_from_current_theme() {
726 + public static function get_style_variations() {
770 727 $variation_files = array();
728 + $variations = array();
771 729 $base_directory = get_stylesheet_directory() . '/styles';
772 730 $template_directory = get_template_directory() . '/styles';
773 731 if ( is_dir( $base_directory ) ) {
774 732 $variation_files = static::recursively_iterate_json( $base_directory );
@@ -784,35 +742,12 @@
784 742 }
785 743 }
786 744 $variation_files = array_merge( $variation_files, $variation_files_parent );
787 745 }
788 -
789 - return $variation_files;
790 - }
791 -
792 - /**
793 - * Returns the style variations in the given directory.
794 - *
795 - * @since 6.7.0
796 - *
797 - * @param string $directory The directory to get the style variations from.
798 - * @param string $scope The scope or type of style variation to retrieve e.g. theme, block etc.
799 - * @return array
800 - */
801 - public static function get_style_variations_from_directory( $directory, $scope = 'theme' ) {
802 - $variation_files = array();
803 - $variations = array();
804 - if ( is_dir( $directory ) ) {
805 - if ( get_stylesheet_directory() === $directory ) {
806 - $variation_files = static::get_style_variation_files_from_current_theme();
807 - } else {
808 - $variation_files = static::recursively_iterate_json( $directory );
809 - }
810 - }
811 746 ksort( $variation_files );
812 747 foreach ( $variation_files as $path => $file ) {
813 - $decoded_file = self::read_json_file( $path );
814 - if ( is_array( $decoded_file ) && static::style_variation_has_scope( $decoded_file, $scope ) ) {
748 + $decoded_file = wp_json_file_decode( $path, array( 'associative' => true ) );
749 + if ( is_array( $decoded_file ) ) {
815 750 $translated = static::translate( $decoded_file, wp_get_theme()->get( 'TextDomain' ) );
816 751 $variation = ( new WP_Theme_JSON_Gutenberg( $translated ) )->get_raw_data();
817 752 if ( empty( $variation['title'] ) ) {
818 753 $variation['title'] = basename( $path, '.json' );
@@ -820,185 +755,6 @@
820 755 $variations[] = $variation;
821 756 }
822 757 }
823 758 return $variations;
824 - }
825 -
826 -
827 - /**
828 - * Resolves relative paths in theme.json styles to theme absolute paths
829 - * and returns them in an array that can be embedded
830 - * as the value of `_link` object in REST API responses.
831 - *
832 - * @since 6.6.0
833 - * @since 6.7.0 Added support for resolving block styles.
834 - *
835 - * @param WP_Theme_JSON_Gutenberg $theme_json A theme json instance.
836 - * @return array An array of resolved paths.
837 - */
838 - public static function get_resolved_theme_uris( $theme_json ) {
839 - $resolved_theme_uris = array();
840 -
841 - if ( ! $theme_json instanceof WP_Theme_JSON_Gutenberg ) {
842 - return $resolved_theme_uris;
843 - }
844 -
845 - $theme_json_data = $theme_json->get_raw_data();
846 -
847 - // Using the same file convention when registering web fonts. See: WP_Font_Face_Resolver:: to_theme_file_uri.
848 - $placeholder = 'file:./';
849 -
850 - // Top level styles.
851 - $background_image_url = $theme_json_data['styles']['background']['backgroundImage']['url'] ?? null;
852 - if (
853 - isset( $background_image_url ) &&
854 - is_string( $background_image_url ) &&
855 - // Skip if the src doesn't start with the placeholder, as there's nothing to replace.
856 - str_starts_with( $background_image_url, $placeholder ) ) {
857 - $file_type = wp_check_filetype( $background_image_url );
858 - $src_url = str_replace( $placeholder, '', $background_image_url );
859 - $resolved_theme_uri = array(
860 - 'name' => $background_image_url,
861 - 'href' => sanitize_url( get_theme_file_uri( $src_url ) ),
862 - 'target' => 'styles.background.backgroundImage.url',
863 - );
864 - if ( isset( $file_type['type'] ) ) {
865 - $resolved_theme_uri['type'] = $file_type['type'];
866 - }
867 - $resolved_theme_uris[] = $resolved_theme_uri;
868 - }
869 -
870 - // Block styles.
871 - if ( ! empty( $theme_json_data['styles']['blocks'] ) ) {
872 - foreach ( $theme_json_data['styles']['blocks'] as $block_name => $block_styles ) {
873 - if ( ! isset( $block_styles['background']['backgroundImage']['url'] ) ) {
874 - continue;
875 - }
876 - $background_image_url = $block_styles['background']['backgroundImage']['url'] ?? null;
877 - if (
878 - isset( $background_image_url ) &&
879 - is_string( $background_image_url ) &&
880 - // Skip if the src doesn't start with the placeholder, as there's nothing to replace.
881 - str_starts_with( $background_image_url, $placeholder ) ) {
882 - $file_type = wp_check_filetype( $background_image_url );
883 - $src_url = str_replace( $placeholder, '', $background_image_url );
884 - $resolved_theme_uri = array(
885 - 'name' => $background_image_url,
886 - 'href' => sanitize_url( get_theme_file_uri( $src_url ) ),
887 - 'target' => "styles.blocks.{$block_name}.background.backgroundImage.url",
888 - );
889 - if ( isset( $file_type['type'] ) ) {
890 - $resolved_theme_uri['type'] = $file_type['type'];
891 - }
892 - $resolved_theme_uris[] = $resolved_theme_uri;
893 - }
894 - }
895 - }
896 -
897 - return $resolved_theme_uris;
898 - }
899 -
900 - /**
901 - * Resolves relative paths in theme.json styles to theme absolute paths
902 - * and merges them with incoming theme JSON.
903 - *
904 - * @since 6.6.0
905 - *
906 - * @param WP_Theme_JSON_Gutenberg $theme_json A theme json instance.
907 - * @return WP_Theme_JSON_Gutenberg Theme merged with resolved paths, if any found.
908 - */
909 - public static function resolve_theme_file_uris( $theme_json ) {
910 - $resolved_urls = static::get_resolved_theme_uris( $theme_json );
911 - if ( empty( $resolved_urls ) ) {
912 - return $theme_json;
913 - }
914 -
915 - $resolved_theme_json_data = $theme_json->get_raw_data();
916 -
917 - foreach ( $resolved_urls as $resolved_url ) {
918 - $path = explode( '.', $resolved_url['target'] );
919 - _wp_array_set( $resolved_theme_json_data, $path, $resolved_url['href'] );
920 - }
921 -
922 - return new WP_Theme_JSON_Gutenberg( $resolved_theme_json_data );
923 - }
924 -
925 - /**
926 - * Adds variations sourced from block style variations files to the supplied theme.json data.
927 - *
928 - * @since 6.6.0
929 - *
930 - * @param array $data Array following the theme.json specification.
931 - * @param array $variations Shared block style variations.
932 - * @return array Theme json data including shared block style variation definitions.
933 - */
934 - private static function inject_variations_from_block_style_variation_files( $data, $variations ) {
935 - if ( empty( $variations ) ) {
936 - return $data;
937 - }
938 -
939 - foreach ( $variations as $variation ) {
940 - if ( empty( $variation['styles'] ) || empty( $variation['blockTypes'] ) ) {
941 - continue;
942 - }
943 -
944 - $variation_name = $variation['slug'] ?? _wp_to_kebab_case( $variation['title'] );
945 -
946 - foreach ( $variation['blockTypes'] as $block_type ) {
947 - // First, override partial styles with any top-level styles.
948 - $top_level_data = $data['styles']['variations'][ $variation_name ] ?? array();
949 - if ( ! empty( $top_level_data ) ) {
950 - $variation['styles'] = array_replace_recursive( $variation['styles'], $top_level_data );
951 - }
952 -
953 - // Then, override styles so far with any block-level styles.
954 - $block_level_data = $data['styles']['blocks'][ $block_type ]['variations'][ $variation_name ] ?? array();
955 - if ( ! empty( $block_level_data ) ) {
956 - $variation['styles'] = array_replace_recursive( $variation['styles'], $block_level_data );
957 - }
958 -
959 - $path = array( 'styles', 'blocks', $block_type, 'variations', $variation_name );
960 - _wp_array_set( $data, $path, $variation['styles'] );
961 - }
962 - }
963 -
964 - return $data;
965 - }
966 -
967 - /**
968 - * Adds variations sourced from the block styles registry to the supplied theme.json data.
969 - *
970 - * @since 6.6.0
971 - *
972 - * @param array $data Array following the theme.json specification.
973 - * @return array Theme json data including variations from the block styles registry.
974 - */
975 - private static function inject_variations_from_block_styles_registry( $data ) {
976 - $registry = WP_Block_Styles_Registry::get_instance();
977 - $styles = $registry->get_all_registered();
978 -
979 - foreach ( $styles as $block_type => $variations ) {
980 - foreach ( $variations as $variation_name => $variation ) {
981 - if ( empty( $variation['style_data'] ) ) {
982 - continue;
983 - }
984 -
985 - // First, override registry styles with any top-level styles.
986 - $top_level_data = $data['styles']['variations'][ $variation_name ] ?? array();
987 - if ( ! empty( $top_level_data ) ) {
988 - $variation['style_data'] = array_replace_recursive( $variation['style_data'], $top_level_data );
989 - }
990 -
991 - // Then, override styles so far with any block-level styles.
992 - $block_level_data = $data['styles']['blocks'][ $block_type ]['variations'][ $variation_name ] ?? array();
993 - if ( ! empty( $block_level_data ) ) {
994 - $variation['style_data'] = array_replace_recursive( $variation['style_data'], $block_level_data );
995 - }
996 -
997 - $path = array( 'styles', 'blocks', $block_type, 'variations', $variation_name );
998 - _wp_array_set( $data, $path, $variation['style_data'] );
999 - }
1000 - }
1001 -
1002 - return $data;
1003 759 }
1004 760 }