Changeset 52275 for trunk/src/wp-includes/class-wp-theme-json.php
- Timestamp:
- 11/30/2021 12:22:30 AM (3 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/class-wp-theme-json.php
r52232 r52275 54 54 'default', 55 55 'theme', 56 ' user',56 'custom', 57 57 ); 58 58 … … 76 76 * 77 77 * - path => where to find the preset within the settings section 78 * - override => whether a theme preset with the same slug as a default preset 79 * can override it 78 80 * - value_key => the key that represents the value 79 * - value_func => the callback to render the value (either value_key or value_func should be present) 81 * - value_func => optionally, instead of value_key, a function to generate 82 * the value that takes a preset as an argument 83 * (either value_key or value_func should be present) 80 84 * - css_vars => template string to use in generating the CSS Custom Property. 81 85 * Example output: "--wp--preset--duotone--blue: <value>" will generate as many CSS Custom Properties as presets defined 82 86 * substituting the $slug for the slug's value for each preset value. 83 * - classes => array containing a structure with the classes to generate for the presets. 84 * Each key is a template string to resolve similarly to the css_vars and each value is the CSS property to use for that class. 85 * Example output: ".has-blue-color { color: <value> }" 86 * - properties => a list of CSS properties to be used by kses to check the preset value is safe. 87 * - classes => array containing a structure with the classes to 88 * generate for the presets, where for each array item 89 * the key is the class name and the value the property name. 90 * The "$slug" substring will be replaced by the slug of each preset. 91 * For example: 92 * 'classes' => array( 93 * '.has-$slug-color' => 'color', 94 * '.has-$slug-background-color' => 'background-color', 95 * '.has-$slug-border-color' => 'border-color', 96 * ) 97 * - properties => array of CSS properties to be used by kses to 98 * validate the content of each preset 99 * by means of the remove_insecure_properties method. 87 100 * 88 101 * @since 5.8.0 … … 93 106 array( 94 107 'path' => array( 'color', 'palette' ), 108 'override' => false, 95 109 'value_key' => 'color', 96 110 'css_vars' => '--wp--preset--color--$slug', … … 104 118 array( 105 119 'path' => array( 'color', 'gradients' ), 120 'override' => false, 106 121 'value_key' => 'gradient', 107 122 'css_vars' => '--wp--preset--gradient--$slug', … … 111 126 array( 112 127 'path' => array( 'color', 'duotone' ), 128 'override' => true, 113 129 'value_func' => 'wp_render_duotone_filter_preset', 114 130 'css_vars' => '--wp--preset--duotone--$slug', … … 118 134 array( 119 135 'path' => array( 'typography', 'fontSizes' ), 136 'override' => true, 120 137 'value_key' => 'size', 121 138 'css_vars' => '--wp--preset--font-size--$slug', … … 125 142 array( 126 143 'path' => array( 'typography', 'fontFamilies' ), 144 'override' => true, 127 145 'value_key' => 'fontFamily', 128 146 'css_vars' => '--wp--preset--font-family--$slug', … … 214 232 */ 215 233 const VALID_SETTINGS = array( 216 'border' => array( 234 'appearanceTools' => null, 235 'border' => array( 217 236 'color' => null, 218 237 'radius' => null, … … 220 239 'width' => null, 221 240 ), 222 'color' => array(241 'color' => array( 223 242 'background' => null, 224 243 'custom' => null, … … 233 252 'text' => null, 234 253 ), 235 'custom' => null,236 'layout' => array(254 'custom' => null, 255 'layout' => array( 237 256 'contentSize' => null, 238 257 'wideSize' => null, 239 258 ), 240 'spacing' => array(259 'spacing' => array( 241 260 'blockGap' => null, 242 261 'margin' => null, … … 244 263 'units' => null, 245 264 ), 246 'typography' => array(265 'typography' => array( 247 266 'customFontSize' => null, 248 267 'dropCap' => null, … … 298 317 299 318 /** 319 * The valid elements that can be found under styles. 320 * 300 321 * @since 5.8.0 301 322 * @var string[] … … 327 348 * @param array $theme_json A structure that follows the theme.json schema. 328 349 * @param string $origin Optional. What source of data this object represents. 329 * One of 'default', 'theme', or ' user'. Default 'theme'.350 * One of 'default', 'theme', or 'custom'. Default 'theme'. 330 351 */ 331 352 public function __construct( $theme_json = array(), $origin = 'theme' ) { … … 337 358 $valid_block_names = array_keys( self::get_blocks_metadata() ); 338 359 $valid_element_names = array_keys( self::ELEMENTS ); 339 $this->theme_json = self::sanitize( $this->theme_json, $valid_block_names, $valid_element_names ); 360 $theme_json = self::sanitize( $this->theme_json, $valid_block_names, $valid_element_names ); 361 $this->theme_json = self::maybe_opt_in_into_settings( $theme_json ); 340 362 341 363 // Internally, presets are keyed by origin. … … 346 368 $preset = _wp_array_get( $this->theme_json, $path, null ); 347 369 if ( null !== $preset ) { 348 if ( 'user' !== $origin || isset( $preset[0] ) ) { 370 // If the preset is not already keyed by origin. 371 if ( isset( $preset[0] ) || empty( $preset ) ) { 349 372 _wp_array_set( $this->theme_json, $path, array( $origin => $preset ) ); 350 373 } … … 352 375 } 353 376 } 377 } 378 379 /** 380 * Enables some opt-in settings if theme declared support. 381 * 382 * @since 5.9.0 383 * 384 * @param array $theme_json A theme.json structure to modify. 385 * @return array The modified theme.json structure. 386 */ 387 private static function maybe_opt_in_into_settings( $theme_json ) { 388 $new_theme_json = $theme_json; 389 390 if ( isset( $new_theme_json['settings']['appearanceTools'] ) ) { 391 self::do_opt_in_into_settings( $new_theme_json['settings'] ); 392 } 393 394 if ( isset( $new_theme_json['settings']['blocks'] ) && is_array( $new_theme_json['settings']['blocks'] ) ) { 395 foreach ( $new_theme_json['settings']['blocks'] as &$block ) { 396 if ( isset( $block['appearanceTools'] ) ) { 397 self::do_opt_in_into_settings( $block ); 398 } 399 } 400 } 401 402 return $new_theme_json; 403 } 404 405 /** 406 * Enables some settings. 407 * 408 * @since 5.9.0 409 * 410 * @param array $context The context to which the settings belong. 411 */ 412 private static function do_opt_in_into_settings( &$context ) { 413 $to_opt_in = array( 414 array( 'border', 'color' ), 415 array( 'border', 'radius' ), 416 array( 'border', 'style' ), 417 array( 'border', 'width' ), 418 array( 'color', 'link' ), 419 array( 'spacing', 'blockGap' ), 420 array( 'spacing', 'margin' ), 421 array( 'spacing', 'padding' ), 422 array( 'typography', 'lineHeight' ), 423 ); 424 425 foreach ( $to_opt_in as $path ) { 426 if ( null === _wp_array_get( $context, $path, null ) ) { 427 _wp_array_set( $context, $path, true ); 428 } 429 } 430 431 unset( $context['appearanceTools'] ); 354 432 } 355 433 … … 415 493 return $output; 416 494 } 495 417 496 /** 418 497 * Returns the metadata for each block. … … 1379 1458 1380 1459 /* 1381 * The array_replace_recursive algorithm merges at the leaf level. 1382 * For leaf values that are arrays it will use the numeric indexes for replacement. 1383 * In those cases, we want to replace the existing with the incoming value, if it exists. 1460 * The array_replace_recursive algorithm merges at the leaf level, 1461 * but we don't want leaf arrays to be merged, so we overwrite it. 1462 * 1463 * For leaf values that are sequential arrays it will use the numeric indexes for replacement. 1464 * We rather replace the existing with the incoming value, if it exists. 1465 * This is the case of spacing.units. 1466 * 1467 * For leaf values that are associative arrays it will merge them as expected. 1468 * This is also not the behavior we want for the current associative arrays (presets). 1469 * We rather replace the existing with the incoming value, if it exists. 1470 * This happens, for example, when we merge data from theme.json upon existing 1471 * theme supports or when we merge anything coming from the same source twice. 1472 * This is the case of color.palette, color.gradients, color.duotone, 1473 * typography.fontSizes, or typography.fontFamilies. 1474 * 1475 * Additionally, for some preset types, we also want to make sure the 1476 * values they introduce don't conflict with default values. We do so 1477 * by checking the incoming slugs for theme presets and compare them 1478 * with the equivalent dfefault presets: if a slug is present as a default 1479 * we remove it from the theme presets. 1384 1480 */ 1385 $to_replace = array(); 1386 $to_replace[] = array( 'spacing', 'units' ); 1387 foreach ( self::VALID_ORIGINS as $origin ) { 1388 $to_replace[] = array( 'color', 'duotone', $origin ); 1389 $to_replace[] = array( 'color', 'palette', $origin ); 1390 $to_replace[] = array( 'color', 'gradients', $origin ); 1391 $to_replace[] = array( 'typography', 'fontSizes', $origin ); 1392 $to_replace[] = array( 'typography', 'fontFamilies', $origin ); 1393 } 1394 1395 $nodes = self::get_setting_nodes( $this->theme_json ); 1396 foreach ( $nodes as $metadata ) { 1397 foreach ( $to_replace as $property_path ) { 1398 $path = array_merge( $metadata['path'], $property_path ); 1399 $node = _wp_array_get( $incoming_data, $path, null ); 1400 if ( isset( $node ) ) { 1401 _wp_array_set( $this->theme_json, $path, $node ); 1481 $nodes = self::get_setting_nodes( $incoming_data ); 1482 $slugs_global = self::get_slugs_not_to_override( $this->theme_json ); 1483 foreach ( $nodes as $node ) { 1484 $slugs_node = self::get_slugs_not_to_override( $this->theme_json, $node['path'] ); 1485 $slugs = array_merge_recursive( $slugs_global, $slugs_node ); 1486 1487 // Replace the spacing.units. 1488 $path = array_merge( $node['path'], array( 'spacing', 'units' ) ); 1489 $content = _wp_array_get( $incoming_data, $path, null ); 1490 if ( isset( $content ) ) { 1491 _wp_array_set( $this->theme_json, $path, $content ); 1492 } 1493 1494 // Replace the presets. 1495 foreach ( self::PRESETS_METADATA as $preset ) { 1496 foreach ( self::VALID_ORIGINS as $origin ) { 1497 $path = array_merge( $node['path'], $preset['path'], array( $origin ) ); 1498 $content = _wp_array_get( $incoming_data, $path, null ); 1499 if ( ! isset( $content ) ) { 1500 continue; 1501 } 1502 1503 if ( 1504 ( 'theme' !== $origin ) || 1505 ( 'theme' === $origin && $preset['override'] ) 1506 ) { 1507 _wp_array_set( $this->theme_json, $path, $content ); 1508 } 1509 1510 if ( 'theme' === $origin && ! $preset['override'] ) { 1511 $content = self::filter_slugs( $content, $preset['path'], $slugs ); 1512 _wp_array_set( $this->theme_json, $path, $content ); 1513 } 1402 1514 } 1403 1515 } 1404 1516 } 1405 1517 } 1518 1519 /** 1520 * Returns the slugs for all the presets that cannot be overriden 1521 * in the given path. It returns an associative array 1522 * whose keys are the preset paths and the leafs is the list of slugs. 1523 * 1524 * For example: 1525 * 1526 * array( 1527 * 'color' => array( 1528 * 'palette' => array( 'slug-1', 'slug-2' ), 1529 * 'gradients' => array( 'slug-3', 'slug-4' ), 1530 * ), 1531 * ) 1532 * 1533 * @since 5.9.0 1534 * 1535 * @param array $data A theme.json like structure to inspect. 1536 * @param array $node_path The path to inspect. It's 'settings' by default. 1537 * 1538 * @return array An associative array containing the slugs for the given path. 1539 */ 1540 private static function get_slugs_not_to_override( $data, $node_path = array( 'settings' ) ) { 1541 $slugs = array(); 1542 foreach ( self::PRESETS_METADATA as $metadata ) { 1543 if ( $metadata['override'] ) { 1544 continue; 1545 } 1546 1547 $slugs_for_preset = array(); 1548 $path = array_merge( $node_path, $metadata['path'], array( 'default' ) ); 1549 $preset = _wp_array_get( $data, $path, null ); 1550 if ( ! isset( $preset ) ) { 1551 continue; 1552 } 1553 1554 $slugs_for_preset = array_map( 1555 function( $value ) { 1556 return isset( $value['slug'] ) ? $value['slug'] : null; 1557 }, 1558 $preset 1559 ); 1560 _wp_array_set( $slugs, $metadata['path'], $slugs_for_preset ); 1561 } 1562 1563 return $slugs; 1564 } 1565 1566 /** 1567 * Removes the preset values whose slug is equal to any of given slugs. 1568 * 1569 * @since 5.9.0 1570 * 1571 * @param array $node The node with the presets to validate. 1572 * @param array $path The path to the preset type to inspect. 1573 * @param array $slugs The slugs that should not be overriden. 1574 * 1575 * @return array The new node 1576 */ 1577 private static function filter_slugs( $node, $path, $slugs ) { 1578 $slugs_for_preset = _wp_array_get( $slugs, $path, array() ); 1579 if ( empty( $slugs_for_preset ) ) { 1580 return $node; 1581 } 1582 1583 $new_node = array(); 1584 foreach ( $node as $value ) { 1585 if ( isset( $value['slug'] ) && ! in_array( $value['slug'], $slugs_for_preset, true ) ) { 1586 $new_node[] = $value; 1587 } 1588 } 1589 1590 return $new_node; 1406 1591 } 1407 1592
Note: See TracChangeset
for help on using the changeset viewer.