[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * WP_Theme_JSON_Resolver class 4 * 5 * @package WordPress 6 * @subpackage Theme 7 * @since 5.8.0 8 */ 9 10 /** 11 * Class that abstracts the processing of the different data sources 12 * for site-level config and offers an API to work with them. 13 * 14 * This class is for internal core usage and is not supposed to be used by extenders (plugins and/or themes). 15 * This is a low-level API that may need to do breaking changes. Please, 16 * use get_global_settings(), get_global_styles(), and get_global_stylesheet() instead. 17 * 18 * @access private 19 */ 20 #[AllowDynamicProperties] 21 class WP_Theme_JSON_Resolver { 22 23 /** 24 * Container for keep track of registered blocks. 25 * 26 * @since 6.1.0 27 * @var array 28 */ 29 protected static $blocks_cache = array( 30 'core' => array(), 31 'blocks' => array(), 32 'theme' => array(), 33 'user' => array(), 34 ); 35 36 /** 37 * Container for data coming from core. 38 * 39 * @since 5.8.0 40 * @var WP_Theme_JSON 41 */ 42 protected static $core = null; 43 44 /** 45 * Container for data coming from the blocks. 46 * 47 * @since 6.1.0 48 * @var WP_Theme_JSON 49 */ 50 protected static $blocks = null; 51 52 /** 53 * Container for data coming from the theme. 54 * 55 * @since 5.8.0 56 * @var WP_Theme_JSON 57 */ 58 protected static $theme = null; 59 60 /** 61 * Container for data coming from the user. 62 * 63 * @since 5.9.0 64 * @var WP_Theme_JSON 65 */ 66 protected static $user = null; 67 68 /** 69 * Stores the ID of the custom post type 70 * that holds the user data. 71 * 72 * @since 5.9.0 73 * @var int 74 */ 75 protected static $user_custom_post_type_id = null; 76 77 /** 78 * Container to keep loaded i18n schema for `theme.json`. 79 * 80 * @since 5.8.0 As `$theme_json_i18n`. 81 * @since 5.9.0 Renamed from `$theme_json_i18n` to `$i18n_schema`. 82 * @var array 83 */ 84 protected static $i18n_schema = null; 85 86 /** 87 * `theme.json` file cache. 88 * 89 * @since 6.1.0 90 * @var array 91 */ 92 protected static $theme_json_file_cache = array(); 93 94 /** 95 * Processes a file that adheres to the theme.json schema 96 * and returns an array with its contents, or a void array if none found. 97 * 98 * @since 5.8.0 99 * @since 6.1.0 Added caching. 100 * 101 * @param string $file_path Path to file. Empty if no file. 102 * @return array Contents that adhere to the theme.json schema. 103 */ 104 protected static function read_json_file( $file_path ) { 105 if ( $file_path ) { 106 if ( array_key_exists( $file_path, static::$theme_json_file_cache ) ) { 107 return static::$theme_json_file_cache[ $file_path ]; 108 } 109 110 $decoded_file = wp_json_file_decode( $file_path, array( 'associative' => true ) ); 111 if ( is_array( $decoded_file ) ) { 112 static::$theme_json_file_cache[ $file_path ] = $decoded_file; 113 return static::$theme_json_file_cache[ $file_path ]; 114 } 115 } 116 117 return array(); 118 } 119 120 /** 121 * Returns a data structure used in theme.json translation. 122 * 123 * @since 5.8.0 124 * @deprecated 5.9.0 125 * 126 * @return array An array of theme.json fields that are translatable and the keys that are translatable. 127 */ 128 public static function get_fields_to_translate() { 129 _deprecated_function( __METHOD__, '5.9.0' ); 130 return array(); 131 } 132 133 /** 134 * Given a theme.json structure modifies it in place to update certain values 135 * by its translated strings according to the language set by the user. 136 * 137 * @since 5.8.0 138 * 139 * @param array $theme_json The theme.json to translate. 140 * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. 141 * Default 'default'. 142 * @return array Returns the modified $theme_json_structure. 143 */ 144 protected static function translate( $theme_json, $domain = 'default' ) { 145 if ( null === static::$i18n_schema ) { 146 $i18n_schema = wp_json_file_decode( __DIR__ . '/theme-i18n.json' ); 147 static::$i18n_schema = null === $i18n_schema ? array() : $i18n_schema; 148 } 149 150 return translate_settings_using_i18n_schema( static::$i18n_schema, $theme_json, $domain ); 151 } 152 153 /** 154 * Returns core's origin config. 155 * 156 * @since 5.8.0 157 * 158 * @return WP_Theme_JSON Entity that holds core data. 159 */ 160 public static function get_core_data() { 161 if ( null !== static::$core && static::has_same_registered_blocks( 'core' ) ) { 162 return static::$core; 163 } 164 165 $config = static::read_json_file( __DIR__ . '/theme.json' ); 166 $config = static::translate( $config ); 167 168 /** 169 * Filters the default data provided by WordPress for global styles & settings. 170 * 171 * @since 6.1.0 172 * 173 * @param WP_Theme_JSON_Data Class to access and update the underlying data. 174 */ 175 $theme_json = apply_filters( 'wp_theme_json_data_default', new WP_Theme_JSON_Data( $config, 'default' ) ); 176 $config = $theme_json->get_data(); 177 static::$core = new WP_Theme_JSON( $config, 'default' ); 178 179 return static::$core; 180 } 181 182 /** 183 * Checks whether the registered blocks were already processed for this origin. 184 * 185 * @since 6.1.0 186 * 187 * @param string $origin Data source for which to cache the blocks. 188 * Valid values are 'core', 'blocks', 'theme', and 'user'. 189 * @return bool True on success, false otherwise. 190 */ 191 protected static function has_same_registered_blocks( $origin ) { 192 // Bail out if the origin is invalid. 193 if ( ! isset( static::$blocks_cache[ $origin ] ) ) { 194 return false; 195 } 196 197 $registry = WP_Block_Type_Registry::get_instance(); 198 $blocks = $registry->get_all_registered(); 199 200 // Is there metadata for all currently registered blocks? 201 $block_diff = array_diff_key( $blocks, static::$blocks_cache[ $origin ] ); 202 if ( empty( $block_diff ) ) { 203 return true; 204 } 205 206 foreach ( $blocks as $block_name => $block_type ) { 207 static::$blocks_cache[ $origin ][ $block_name ] = true; 208 } 209 210 return false; 211 } 212 213 /** 214 * Returns the theme's data. 215 * 216 * Data from theme.json will be backfilled from existing 217 * theme supports, if any. Note that if the same data 218 * is present in theme.json and in theme supports, 219 * the theme.json takes precedence. 220 * 221 * @since 5.8.0 222 * @since 5.9.0 Theme supports have been inlined and the `$theme_support_data` argument removed. 223 * @since 6.0.0 Added an `$options` parameter to allow the theme data to be returned without theme supports. 224 * 225 * @param array $deprecated Deprecated. Not used. 226 * @param array $options { 227 * Options arguments. 228 * 229 * @type bool $with_supports Whether to include theme supports in the data. Default true. 230 * } 231 * @return WP_Theme_JSON Entity that holds theme data. 232 */ 233 public static function get_theme_data( $deprecated = array(), $options = array() ) { 234 if ( ! empty( $deprecated ) ) { 235 _deprecated_argument( __METHOD__, '5.9.0' ); 236 } 237 238 $options = wp_parse_args( $options, array( 'with_supports' => true ) ); 239 240 if ( null === static::$theme || ! static::has_same_registered_blocks( 'theme' ) ) { 241 $theme_json_file = static::get_file_path_from_theme( 'theme.json' ); 242 $wp_theme = wp_get_theme(); 243 if ( '' !== $theme_json_file ) { 244 $theme_json_data = static::read_json_file( $theme_json_file ); 245 $theme_json_data = static::translate( $theme_json_data, $wp_theme->get( 'TextDomain' ) ); 246 } else { 247 $theme_json_data = array(); 248 } 249 250 /** 251 * Filters the data provided by the theme for global styles and settings. 252 * 253 * @since 6.1.0 254 * 255 * @param WP_Theme_JSON_Data Class to access and update the underlying data. 256 */ 257 $theme_json = apply_filters( 'wp_theme_json_data_theme', new WP_Theme_JSON_Data( $theme_json_data, 'theme' ) ); 258 $theme_json_data = $theme_json->get_data(); 259 static::$theme = new WP_Theme_JSON( $theme_json_data ); 260 261 if ( $wp_theme->parent() ) { 262 // Get parent theme.json. 263 $parent_theme_json_file = static::get_file_path_from_theme( 'theme.json', true ); 264 if ( '' !== $parent_theme_json_file ) { 265 $parent_theme_json_data = static::read_json_file( $parent_theme_json_file ); 266 $parent_theme_json_data = static::translate( $parent_theme_json_data, $wp_theme->parent()->get( 'TextDomain' ) ); 267 $parent_theme = new WP_Theme_JSON( $parent_theme_json_data ); 268 269 /* 270 * Merge the child theme.json into the parent theme.json. 271 * The child theme takes precedence over the parent. 272 */ 273 $parent_theme->merge( static::$theme ); 274 static::$theme = $parent_theme; 275 } 276 } 277 } 278 279 if ( ! $options['with_supports'] ) { 280 return static::$theme; 281 } 282 283 /* 284 * We want the presets and settings declared in theme.json 285 * to override the ones declared via theme supports. 286 * So we take theme supports, transform it to theme.json shape 287 * and merge the static::$theme upon that. 288 */ 289 $theme_support_data = WP_Theme_JSON::get_from_editor_settings( get_classic_theme_supports_block_editor_settings() ); 290 if ( ! wp_theme_has_theme_json() ) { 291 if ( ! isset( $theme_support_data['settings']['color'] ) ) { 292 $theme_support_data['settings']['color'] = array(); 293 } 294 295 $default_palette = false; 296 if ( current_theme_supports( 'default-color-palette' ) ) { 297 $default_palette = true; 298 } 299 if ( ! isset( $theme_support_data['settings']['color']['palette'] ) ) { 300 // If the theme does not have any palette, we still want to show the core one. 301 $default_palette = true; 302 } 303 $theme_support_data['settings']['color']['defaultPalette'] = $default_palette; 304 305 $default_gradients = false; 306 if ( current_theme_supports( 'default-gradient-presets' ) ) { 307 $default_gradients = true; 308 } 309 if ( ! isset( $theme_support_data['settings']['color']['gradients'] ) ) { 310 // If the theme does not have any gradients, we still want to show the core ones. 311 $default_gradients = true; 312 } 313 $theme_support_data['settings']['color']['defaultGradients'] = $default_gradients; 314 315 // Classic themes without a theme.json don't support global duotone. 316 $theme_support_data['settings']['color']['defaultDuotone'] = false; 317 } 318 $with_theme_supports = new WP_Theme_JSON( $theme_support_data ); 319 $with_theme_supports->merge( static::$theme ); 320 return $with_theme_supports; 321 } 322 323 /** 324 * Gets the styles for blocks from the block.json file. 325 * 326 * @since 6.1.0 327 * 328 * @return WP_Theme_JSON 329 */ 330 public static function get_block_data() { 331 $registry = WP_Block_Type_Registry::get_instance(); 332 $blocks = $registry->get_all_registered(); 333 334 if ( null !== static::$blocks && static::has_same_registered_blocks( 'blocks' ) ) { 335 return static::$blocks; 336 } 337 338 $config = array( 'version' => 2 ); 339 foreach ( $blocks as $block_name => $block_type ) { 340 if ( isset( $block_type->supports['__experimentalStyle'] ) ) { 341 $config['styles']['blocks'][ $block_name ] = static::remove_json_comments( $block_type->supports['__experimentalStyle'] ); 342 } 343 344 if ( 345 isset( $block_type->supports['spacing']['blockGap']['__experimentalDefault'] ) && 346 null === _wp_array_get( $config, array( 'styles', 'blocks', $block_name, 'spacing', 'blockGap' ), null ) 347 ) { 348 // Ensure an empty placeholder value exists for the block, if it provides a default blockGap value. 349 // The real blockGap value to be used will be determined when the styles are rendered for output. 350 $config['styles']['blocks'][ $block_name ]['spacing']['blockGap'] = null; 351 } 352 } 353 354 /** 355 * Filters the data provided by the blocks for global styles & settings. 356 * 357 * @since 6.1.0 358 * 359 * @param WP_Theme_JSON_Data Class to access and update the underlying data. 360 */ 361 $theme_json = apply_filters( 'wp_theme_json_data_blocks', new WP_Theme_JSON_Data( $config, 'blocks' ) ); 362 $config = $theme_json->get_data(); 363 364 static::$blocks = new WP_Theme_JSON( $config, 'blocks' ); 365 return static::$blocks; 366 } 367 368 /** 369 * When given an array, this will remove any keys with the name `//`. 370 * 371 * @since 6.1.0 372 * 373 * @param array $input_array The array to filter. 374 * @return array The filtered array. 375 */ 376 private static function remove_json_comments( $input_array ) { 377 unset( $input_array['//'] ); 378 foreach ( $input_array as $k => $v ) { 379 if ( is_array( $v ) ) { 380 $input_array[ $k ] = static::remove_json_comments( $v ); 381 } 382 } 383 384 return $input_array; 385 } 386 387 /** 388 * Returns the custom post type that contains the user's origin config 389 * for the active theme or an empty array if none are found. 390 * 391 * This can also create and return a new draft custom post type. 392 * 393 * @since 5.9.0 394 * 395 * @param WP_Theme $theme The theme object. If empty, it 396 * defaults to the active theme. 397 * @param bool $create_post Optional. Whether a new custom post 398 * type should be created if none are 399 * found. Default false. 400 * @param array $post_status_filter Optional. Filter custom post type by 401 * post status. Default `array( 'publish' )`, 402 * so it only fetches published posts. 403 * @return array Custom Post Type for the user's origin config. 404 */ 405 public static function get_user_data_from_wp_global_styles( $theme, $create_post = false, $post_status_filter = array( 'publish' ) ) { 406 if ( ! $theme instanceof WP_Theme ) { 407 $theme = wp_get_theme(); 408 } 409 410 /* 411 * Bail early if the theme does not support a theme.json. 412 * 413 * Since wp_theme_has_theme_json() only supports the active 414 * theme, the extra condition for whether $theme is the active theme is 415 * present here. 416 */ 417 if ( $theme->get_stylesheet() === get_stylesheet() && ! wp_theme_has_theme_json() ) { 418 return array(); 419 } 420 421 $user_cpt = array(); 422 $post_type_filter = 'wp_global_styles'; 423 $stylesheet = $theme->get_stylesheet(); 424 $args = array( 425 'posts_per_page' => 1, 426 'orderby' => 'date', 427 'order' => 'desc', 428 'post_type' => $post_type_filter, 429 'post_status' => $post_status_filter, 430 'ignore_sticky_posts' => true, 431 'no_found_rows' => true, 432 'update_post_meta_cache' => false, 433 'update_post_term_cache' => false, 434 'tax_query' => array( 435 array( 436 'taxonomy' => 'wp_theme', 437 'field' => 'name', 438 'terms' => $stylesheet, 439 ), 440 ), 441 ); 442 443 $global_style_query = new WP_Query(); 444 $recent_posts = $global_style_query->query( $args ); 445 if ( count( $recent_posts ) === 1 ) { 446 $user_cpt = get_object_vars( $recent_posts[0] ); 447 } elseif ( $create_post ) { 448 $cpt_post_id = wp_insert_post( 449 array( 450 'post_content' => '{"version": ' . WP_Theme_JSON::LATEST_SCHEMA . ', "isGlobalStylesUserThemeJSON": true }', 451 'post_status' => 'publish', 452 'post_title' => 'Custom Styles', // Do not make string translatable, see https://core.trac.wordpress.org/ticket/54518. 453 'post_type' => $post_type_filter, 454 'post_name' => sprintf( 'wp-global-styles-%s', urlencode( $stylesheet ) ), 455 'tax_input' => array( 456 'wp_theme' => array( $stylesheet ), 457 ), 458 ), 459 true 460 ); 461 if ( ! is_wp_error( $cpt_post_id ) ) { 462 $user_cpt = get_object_vars( get_post( $cpt_post_id ) ); 463 } 464 } 465 466 return $user_cpt; 467 } 468 469 /** 470 * Returns the user's origin config. 471 * 472 * @since 5.9.0 473 * 474 * @return WP_Theme_JSON Entity that holds styles for user data. 475 */ 476 public static function get_user_data() { 477 if ( null !== static::$user && static::has_same_registered_blocks( 'user' ) ) { 478 return static::$user; 479 } 480 481 $config = array(); 482 $user_cpt = static::get_user_data_from_wp_global_styles( wp_get_theme() ); 483 484 if ( array_key_exists( 'post_content', $user_cpt ) ) { 485 $decoded_data = json_decode( $user_cpt['post_content'], true ); 486 487 $json_decoding_error = json_last_error(); 488 if ( JSON_ERROR_NONE !== $json_decoding_error ) { 489 trigger_error( 'Error when decoding a theme.json schema for user data. ' . json_last_error_msg() ); 490 /** 491 * Filters the data provided by the user for global styles & settings. 492 * 493 * @since 6.1.0 494 * 495 * @param WP_Theme_JSON_Data Class to access and update the underlying data. 496 */ 497 $theme_json = apply_filters( 'wp_theme_json_data_user', new WP_Theme_JSON_Data( $config, 'custom' ) ); 498 $config = $theme_json->get_data(); 499 return new WP_Theme_JSON( $config, 'custom' ); 500 } 501 502 // Very important to verify that the flag isGlobalStylesUserThemeJSON is true. 503 // If it's not true then the content was not escaped and is not safe. 504 if ( 505 is_array( $decoded_data ) && 506 isset( $decoded_data['isGlobalStylesUserThemeJSON'] ) && 507 $decoded_data['isGlobalStylesUserThemeJSON'] 508 ) { 509 unset( $decoded_data['isGlobalStylesUserThemeJSON'] ); 510 $config = $decoded_data; 511 } 512 } 513 514 /** This filter is documented in wp-includes/class-wp-theme-json-resolver.php */ 515 $theme_json = apply_filters( 'wp_theme_json_data_user', new WP_Theme_JSON_Data( $config, 'custom' ) ); 516 $config = $theme_json->get_data(); 517 static::$user = new WP_Theme_JSON( $config, 'custom' ); 518 519 return static::$user; 520 } 521 522 /** 523 * Returns the data merged from multiple origins. 524 * 525 * There are four sources of data (origins) for a site: 526 * 527 * - default => WordPress 528 * - blocks => each one of the blocks provides data for itself 529 * - theme => the active theme 530 * - custom => data provided by the user 531 * 532 * The custom's has higher priority than the theme's, the theme's higher than blocks', 533 * and block's higher than default's. 534 * 535 * Unlike the getters 536 * {@link https://developer.wordpress.org/reference/classes/wp_theme_json_resolver/get_core_data/ get_core_data}, 537 * {@link https://developer.wordpress.org/reference/classes/wp_theme_json_resolver/get_theme_data/ get_theme_data}, 538 * and {@link https://developer.wordpress.org/reference/classes/wp_theme_json_resolver/get_user_data/ get_user_data}, 539 * this method returns data after it has been merged with the previous origins. 540 * This means that if the same piece of data is declared in different origins 541 * (default, blocks, theme, custom), the last origin overrides the previous. 542 * 543 * For example, if the user has set a background color 544 * for the paragraph block, and the theme has done it as well, 545 * the user preference wins. 546 * 547 * @since 5.8.0 548 * @since 5.9.0 Added user data, removed the `$settings` parameter, 549 * added the `$origin` parameter. 550 * @since 6.1.0 Added block data and generation of spacingSizes array. 551 * @since 6.2.0 Changed ' $origin' parameter values to 'default', 'blocks', 'theme' or 'custom'. 552 * 553 * @param string $origin Optional. To what level should we merge data: 'default', 'blocks', 'theme' or 'custom'. 554 * 'custom' is used as default value as well as fallback value if the origin is unknown. 555 * @return WP_Theme_JSON 556 */ 557 public static function get_merged_data( $origin = 'custom' ) { 558 if ( is_array( $origin ) ) { 559 _deprecated_argument( __FUNCTION__, '5.9.0' ); 560 } 561 562 $result = new WP_Theme_JSON(); 563 $result->merge( static::get_core_data() ); 564 if ( 'default' === $origin ) { 565 $result->set_spacing_sizes(); 566 return $result; 567 } 568 569 $result->merge( static::get_block_data() ); 570 if ( 'blocks' === $origin ) { 571 return $result; 572 } 573 574 $result->merge( static::get_theme_data() ); 575 if ( 'theme' === $origin ) { 576 $result->set_spacing_sizes(); 577 return $result; 578 } 579 580 $result->merge( static::get_user_data() ); 581 $result->set_spacing_sizes(); 582 583 return $result; 584 } 585 586 /** 587 * Returns the ID of the custom post type 588 * that stores user data. 589 * 590 * @since 5.9.0 591 * 592 * @return integer|null 593 */ 594 public static function get_user_global_styles_post_id() { 595 if ( null !== static::$user_custom_post_type_id ) { 596 return static::$user_custom_post_type_id; 597 } 598 599 $user_cpt = static::get_user_data_from_wp_global_styles( wp_get_theme(), true ); 600 601 if ( array_key_exists( 'ID', $user_cpt ) ) { 602 static::$user_custom_post_type_id = $user_cpt['ID']; 603 } 604 605 return static::$user_custom_post_type_id; 606 } 607 608 /** 609 * Determines whether the active theme has a theme.json file. 610 * 611 * @since 5.8.0 612 * @since 5.9.0 Added a check in the parent theme. 613 * @deprecated 6.2.0 Use wp_theme_has_theme_json() instead. 614 * 615 * @return bool 616 */ 617 public static function theme_has_support() { 618 _deprecated_function( __METHOD__, '6.2.0', 'wp_theme_has_theme_json()' ); 619 620 return wp_theme_has_theme_json(); 621 } 622 623 /** 624 * Builds the path to the given file and checks that it is readable. 625 * 626 * If it isn't, returns an empty string, otherwise returns the whole file path. 627 * 628 * @since 5.8.0 629 * @since 5.9.0 Adapted to work with child themes, added the `$template` argument. 630 * 631 * @param string $file_name Name of the file. 632 * @param bool $template Optional. Use template theme directory. Default false. 633 * @return string The whole file path or empty if the file doesn't exist. 634 */ 635 protected static function get_file_path_from_theme( $file_name, $template = false ) { 636 $path = $template ? get_template_directory() : get_stylesheet_directory(); 637 $candidate = $path . '/' . $file_name; 638 639 return is_readable( $candidate ) ? $candidate : ''; 640 } 641 642 /** 643 * Cleans the cached data so it can be recalculated. 644 * 645 * @since 5.8.0 646 * @since 5.9.0 Added the `$user`, `$user_custom_post_type_id`, 647 * and `$i18n_schema` variables to reset. 648 * @since 6.1.0 Added the `$blocks` and `$blocks_cache` variables 649 * to reset. 650 */ 651 public static function clean_cached_data() { 652 static::$core = null; 653 static::$blocks = null; 654 static::$blocks_cache = array( 655 'core' => array(), 656 'blocks' => array(), 657 'theme' => array(), 658 'user' => array(), 659 ); 660 static::$theme = null; 661 static::$user = null; 662 static::$user_custom_post_type_id = null; 663 static::$i18n_schema = null; 664 } 665 666 /** 667 * Returns an array of all nested JSON files within a given directory. 668 * 669 * @since 6.2.0 670 * 671 * @param string $dir The directory to recursively iterate and list files of. 672 * @return array The merged array. 673 */ 674 private static function recursively_iterate_json( $dir ) { 675 $nested_files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $dir ) ); 676 $nested_json_files = iterator_to_array( new RegexIterator( $nested_files, '/^.+\.json$/i', RecursiveRegexIterator::GET_MATCH ) ); 677 return $nested_json_files; 678 } 679 680 681 /** 682 * Returns the style variations defined by the theme. 683 * 684 * @since 6.0.0 685 * @since 6.2.0 Returns parent theme variations if theme is a child. 686 * 687 * @return array 688 */ 689 public static function get_style_variations() { 690 $variation_files = array(); 691 $variations = array(); 692 $base_directory = get_stylesheet_directory() . '/styles'; 693 $template_directory = get_template_directory() . '/styles'; 694 if ( is_dir( $base_directory ) ) { 695 $variation_files = static::recursively_iterate_json( $base_directory ); 696 } 697 if ( is_dir( $template_directory ) && $template_directory !== $base_directory ) { 698 $variation_files_parent = static::recursively_iterate_json( $template_directory ); 699 // If the child and parent variation file basename are the same, only include the child theme's. 700 foreach ( $variation_files_parent as $parent_path => $parent ) { 701 foreach ( $variation_files as $child_path => $child ) { 702 if ( basename( $parent_path ) === basename( $child_path ) ) { 703 unset( $variation_files_parent[ $parent_path ] ); 704 } 705 } 706 } 707 $variation_files = array_merge( $variation_files, $variation_files_parent ); 708 } 709 ksort( $variation_files ); 710 foreach ( $variation_files as $path => $file ) { 711 $decoded_file = wp_json_file_decode( $path, array( 'associative' => true ) ); 712 if ( is_array( $decoded_file ) ) { 713 $translated = static::translate( $decoded_file, wp_get_theme()->get( 'TextDomain' ) ); 714 $variation = ( new WP_Theme_JSON( $translated ) )->get_raw_data(); 715 if ( empty( $variation['title'] ) ) { 716 $variation['title'] = basename( $path, '.json' ); 717 } 718 $variations[] = $variation; 719 } 720 } 721 return $variations; 722 } 723 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Sun Jun 4 08:20:02 2023 | Cross-referenced by PHPXref |