Changeset 54162
- Timestamp:
- 09/14/2022 06:42:04 PM (2 years ago)
- Location:
- trunk
- Files:
-
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/block-editor.php
r54160 r54162 210 210 'disableCustomFontSizes' => get_theme_support( 'disable-custom-font-sizes' ), 211 211 'disableCustomGradients' => get_theme_support( 'disable-custom-gradients' ), 212 'disableLayoutStyles' => get_theme_support( 'disable-layout-styles' ), 212 213 'enableCustomLineHeight' => get_theme_support( 'custom-line-height' ), 213 214 'enableCustomSpacing' => get_theme_support( 'custom-spacing' ), … … 418 419 $global_styles[] = $block_classes; 419 420 } 421 } else { 422 // If there is no `theme.json` file, ensure base layout styles are still available. 423 $block_classes = array( 424 'css' => 'base-layout-styles', 425 '__unstableType' => 'base-layout', 426 'isGlobalStyles' => true, 427 ); 428 $actual_css = wp_get_global_stylesheet( array( $block_classes['css'] ) ); 429 if ( '' !== $actual_css ) { 430 $block_classes['css'] = $actual_css; 431 $global_styles[] = $block_classes; 432 } 420 433 } 421 434 … … 475 488 unset( $editor_settings['__experimentalFeatures']['spacing']['padding'] ); 476 489 } 490 if ( isset( $editor_settings['__experimentalFeatures']['spacing']['customSpacingSize'] ) ) { 491 $editor_settings['disableCustomSpacingSizes'] = ! $editor_ettings['__experimentalFeatures']['spacing']['customSpacingSize']; 492 unset( $editor_settings['__experimentalFeatures']['spacing']['customSpacingSize'] ); 493 } 494 495 if ( isset( $editor_settings['__experimentalFeatures']['spacing']['spacingSizes'] ) ) { 496 $spacing_sizes_by_origin = $editor_settings['__experimentalFeatures']['spacing']['spacingSizes']; 497 $editor_settings['spacingSizes'] = isset( $spacing_sizes_by_origin['custom'] ) ? 498 $spacing_sizes_by_origin['custom'] : ( 499 isset( $spacing_sizes_by_origin['theme'] ) ? 500 $spacing_sizes_by_origin['theme'] : 501 $spacing_sizes_by_origin['default'] 502 ); 503 } 477 504 478 505 $editor_settings['__unstableResolvedAssets'] = _wp_get_iframed_editor_assets(); 479 506 $editor_settings['localAutosaveInterval'] = 15; 507 $editor_settings['disableLayoutStyles'] = current_theme_supports( 'disable-layout-styles' ); 480 508 $editor_settings['__experimentalDiscussionSettings'] = array( 481 509 'commentOrder' => get_option( 'comment_order' ), -
trunk/src/wp-includes/class-wp-theme-json-resolver.php
r54160 r54162 231 231 232 232 return $with_theme_supports; 233 } 234 235 /** 236 * Gets the styles for blocks from the block.json file. 237 * 238 * @since 6.1.0 239 * 240 * @return WP_Theme_JSON 241 */ 242 public static function get_block_data() { 243 $registry = WP_Block_Type_Registry::get_instance(); 244 $blocks = $registry->get_all_registered(); 245 $config = array( 'version' => 1 ); 246 foreach ( $blocks as $block_name => $block_type ) { 247 if ( isset( $block_type->supports['__experimentalStyle'] ) ) { 248 $config['styles']['blocks'][ $block_name ] = static::remove_json_comments( $block_type->supports['__experimentalStyle'] ); 249 } 250 251 if ( 252 isset( $block_type->supports['spacing']['blockGap']['__experimentalDefault'] ) && 253 null === _wp_array_get( $config, array( 'styles', 'blocks', $block_name, 'spacing', 'blockGap' ), null ) 254 ) { 255 // Ensure an empty placeholder value exists for the block, if it provides a default blockGap value. 256 // The real blockGap value to be used will be determined when the styles are rendered for output. 257 $config['styles']['blocks'][ $block_name ]['spacing']['blockGap'] = null; 258 } 259 } 260 261 // Core here means it's the lower level part of the styles chain. 262 // It can be a core or a third-party block. 263 return new WP_Theme_JSON( $config, 'core' ); 264 } 265 266 /** 267 * When given an array, this will remove any keys with the name `//`. 268 * 269 * @param array $array The array to filter. 270 * @return array The filtered array. 271 */ 272 private static function remove_json_comments( $array ) { 273 unset( $array['//'] ); 274 foreach ( $array as $k => $v ) { 275 if ( is_array( $v ) ) { 276 $array[ $k ] = static::remove_json_comments( $v ); 277 } 278 } 279 280 return $array; 233 281 } 234 282 … … 371 419 * @since 5.9.0 Added user data, removed the `$settings` parameter, 372 420 * added the `$origin` parameter. 421 * @since 6.1.0 Added block data. 373 422 * 374 423 * @param string $origin Optional. To what level should we merge data. … … 383 432 $result = new WP_Theme_JSON(); 384 433 $result->merge( static::get_core_data() ); 434 $result->merge( static::get_block_data() ); 385 435 $result->merge( static::get_theme_data() ); 386 436 -
trunk/src/wp-includes/class-wp-theme-json.php
r54160 r54162 178 178 * `text-decoration`, `text-transform`, and `filter` properties, 179 179 * simplified the metadata structure. 180 * @since 6.1.0 Added the `border-*-color`, `border-*-width`, `border-*-style`, 181 * `--wp--style--root--padding-*`, and `box-shadow` properties, 182 * removed the `--wp--style--block-gap` property. 180 183 * @var array 181 184 */ 182 185 const PROPERTIES_METADATA = array( 183 'background' => array( 'color', 'gradient' ), 184 'background-color' => array( 'color', 'background' ), 185 'border-radius' => array( 'border', 'radius' ), 186 'border-top-left-radius' => array( 'border', 'radius', 'topLeft' ), 187 'border-top-right-radius' => array( 'border', 'radius', 'topRight' ), 188 'border-bottom-left-radius' => array( 'border', 'radius', 'bottomLeft' ), 189 'border-bottom-right-radius' => array( 'border', 'radius', 'bottomRight' ), 190 'border-color' => array( 'border', 'color' ), 191 'border-width' => array( 'border', 'width' ), 192 'border-style' => array( 'border', 'style' ), 193 'color' => array( 'color', 'text' ), 194 'font-family' => array( 'typography', 'fontFamily' ), 195 'font-size' => array( 'typography', 'fontSize' ), 196 'font-style' => array( 'typography', 'fontStyle' ), 197 'font-weight' => array( 'typography', 'fontWeight' ), 198 'letter-spacing' => array( 'typography', 'letterSpacing' ), 199 'line-height' => array( 'typography', 'lineHeight' ), 200 'margin' => array( 'spacing', 'margin' ), 201 'margin-top' => array( 'spacing', 'margin', 'top' ), 202 'margin-right' => array( 'spacing', 'margin', 'right' ), 203 'margin-bottom' => array( 'spacing', 'margin', 'bottom' ), 204 'margin-left' => array( 'spacing', 'margin', 'left' ), 205 'padding' => array( 'spacing', 'padding' ), 206 'padding-top' => array( 'spacing', 'padding', 'top' ), 207 'padding-right' => array( 'spacing', 'padding', 'right' ), 208 'padding-bottom' => array( 'spacing', 'padding', 'bottom' ), 209 'padding-left' => array( 'spacing', 'padding', 'left' ), 210 '--wp--style--block-gap' => array( 'spacing', 'blockGap' ), 211 'text-decoration' => array( 'typography', 'textDecoration' ), 212 'text-transform' => array( 'typography', 'textTransform' ), 213 'filter' => array( 'filter', 'duotone' ), 186 'background' => array( 'color', 'gradient' ), 187 'background-color' => array( 'color', 'background' ), 188 'border-radius' => array( 'border', 'radius' ), 189 'border-top-left-radius' => array( 'border', 'radius', 'topLeft' ), 190 'border-top-right-radius' => array( 'border', 'radius', 'topRight' ), 191 'border-bottom-left-radius' => array( 'border', 'radius', 'bottomLeft' ), 192 'border-bottom-right-radius' => array( 'border', 'radius', 'bottomRight' ), 193 'border-color' => array( 'border', 'color' ), 194 'border-width' => array( 'border', 'width' ), 195 'border-style' => array( 'border', 'style' ), 196 'border-top-color' => array( 'border', 'top', 'color' ), 197 'border-top-width' => array( 'border', 'top', 'width' ), 198 'border-top-style' => array( 'border', 'top', 'style' ), 199 'border-right-color' => array( 'border', 'right', 'color' ), 200 'border-right-width' => array( 'border', 'right', 'width' ), 201 'border-right-style' => array( 'border', 'right', 'style' ), 202 'border-bottom-color' => array( 'border', 'bottom', 'color' ), 203 'border-bottom-width' => array( 'border', 'bottom', 'width' ), 204 'border-bottom-style' => array( 'border', 'bottom', 'style' ), 205 'border-left-color' => array( 'border', 'left', 'color' ), 206 'border-left-width' => array( 'border', 'left', 'width' ), 207 'border-left-style' => array( 'border', 'left', 'style' ), 208 'color' => array( 'color', 'text' ), 209 'font-family' => array( 'typography', 'fontFamily' ), 210 'font-size' => array( 'typography', 'fontSize' ), 211 'font-style' => array( 'typography', 'fontStyle' ), 212 'font-weight' => array( 'typography', 'fontWeight' ), 213 'letter-spacing' => array( 'typography', 'letterSpacing' ), 214 'line-height' => array( 'typography', 'lineHeight' ), 215 'margin' => array( 'spacing', 'margin' ), 216 'margin-top' => array( 'spacing', 'margin', 'top' ), 217 'margin-right' => array( 'spacing', 'margin', 'right' ), 218 'margin-bottom' => array( 'spacing', 'margin', 'bottom' ), 219 'margin-left' => array( 'spacing', 'margin', 'left' ), 220 'padding' => array( 'spacing', 'padding' ), 221 'padding-top' => array( 'spacing', 'padding', 'top' ), 222 'padding-right' => array( 'spacing', 'padding', 'right' ), 223 'padding-bottom' => array( 'spacing', 'padding', 'bottom' ), 224 'padding-left' => array( 'spacing', 'padding', 'left' ), 225 '--wp--style--root--padding' => array( 'spacing', 'padding' ), 226 '--wp--style--root--padding-top' => array( 'spacing', 'padding', 'top' ), 227 '--wp--style--root--padding-right' => array( 'spacing', 'padding', 'right' ), 228 '--wp--style--root--padding-bottom' => array( 'spacing', 'padding', 'bottom' ), 229 '--wp--style--root--padding-left' => array( 'spacing', 'padding', 'left' ), 230 'text-decoration' => array( 'typography', 'textDecoration' ), 231 'text-transform' => array( 'typography', 'textTransform' ), 232 'filter' => array( 'filter', 'duotone' ), 233 'box-shadow' => array( 'shadow' ), 214 234 ); 215 235 … … 255 275 * and `typography`, and renamed others according to the new schema. 256 276 * @since 6.0.0 Added `color.defaultDuotone`. 277 * @since 6.1.0 Added `layout.definitions` and `useRootPaddingAwareAlignments`. 257 278 * @var array 258 279 */ 259 280 const VALID_SETTINGS = array( 260 'appearanceTools' => null, 261 'border' => array( 281 'appearanceTools' => null, 282 'useRootPaddingAwareAlignments' => null, 283 'border' => array( 262 284 'color' => null, 263 285 'radius' => null, … … 265 287 'width' => null, 266 288 ), 267 'color' => array(289 'color' => array( 268 290 'background' => null, 269 291 'custom' => null, … … 279 301 'text' => null, 280 302 ), 281 'custom' => null,282 'layout' => array(303 'custom' => null, 304 'layout' => array( 283 305 'contentSize' => null, 306 'definitions' => null, 284 307 'wideSize' => null, 285 308 ), 286 'spacing' => array(309 'spacing' => array( 287 310 'blockGap' => null, 288 311 'margin' => null, … … 290 313 'units' => null, 291 314 ), 292 'typography' => array(315 'typography' => array( 293 316 'customFontSize' => null, 294 317 'dropCap' => null, … … 311 334 * added new properties for `border`, `filter`, `spacing`, 312 335 * and `typography`. 336 * @since 6.1.0 Added new side properties for `border`, 337 * updated `blockGap` to be allowed at any level. 313 338 * @var array 314 339 */ … … 319 344 'style' => null, 320 345 'width' => null, 346 'top' => null, 347 'right' => null, 348 'bottom' => null, 349 'left' => null, 321 350 ), 322 351 'color' => array( … … 331 360 'margin' => null, 332 361 'padding' => null, 333 'blockGap' => 'top',362 'blockGap' => null, 334 363 ), 335 364 'typography' => array( … … 382 411 'button' => 'wp-element-button', 383 412 'caption' => 'wp-element-caption', 413 ); 414 415 /** 416 * List of block support features that can have their related styles 417 * generated under their own feature level selector rather than the block's. 418 * 419 * @since 6.1.0 420 * @var string[] 421 */ 422 const BLOCK_SUPPORT_FEATURE_LEVEL_SELECTORS = array( 423 '__experimentalBorder' => 'border', 424 'color' => 'color', 425 'spacing' => 'spacing', 426 'typography' => 'typography', 384 427 ); 385 428 … … 657 700 * @since 5.8.0 658 701 * @since 5.9.0 Added `duotone` key with CSS selector. 702 * @since 6.1.0 Added `features` key with block support feature level selectors. 659 703 * 660 704 * @return array Block metadata. … … 684 728 ) { 685 729 static::$blocks_metadata[ $block_name ]['duotone'] = $block_type->supports['color']['__experimentalDuotone']; 730 } 731 732 // Generate block support feature level selectors if opted into 733 // for the current block. 734 $features = array(); 735 foreach ( static::BLOCK_SUPPORT_FEATURE_LEVEL_SELECTORS as $key => $feature ) { 736 if ( 737 isset( $block_type->supports[ $key ]['__experimentalSelector'] ) && 738 $block_type->supports[ $key ]['__experimentalSelector'] 739 ) { 740 $features[ $feature ] = static::scope_selector( 741 static::$blocks_metadata[ $block_name ]['selector'], 742 $block_type->supports[ $key ]['__experimentalSelector'] 743 ); 744 } 745 } 746 747 if ( ! empty( $features ) ) { 748 static::$blocks_metadata[ $block_name ]['features'] = $features; 686 749 } 687 750 … … 811 874 812 875 if ( in_array( 'styles', $types, true ) ) { 876 $root_block_key = array_search( static::ROOT_BLOCK_SELECTOR, array_column( $style_nodes, 'selector' ), true ); 877 878 if ( false !== $root_block_key ) { 879 $stylesheet .= $this->get_root_layout_rules( static::ROOT_BLOCK_SELECTOR, $style_nodes[ $root_block_key ] ); 880 } 813 881 $stylesheet .= $this->get_block_classes( $style_nodes ); 882 } elseif ( in_array( 'base-layout-styles', $types, true ) ) { 883 // Base layout styles are provided as part of `styles`, so only output separately if explicitly requested. 884 // For backwards compatibility, the Columns block is explicitly included, to support a different default gap value. 885 $base_styles_nodes = array( 886 array( 887 'path' => array( 'styles' ), 888 'selector' => static::ROOT_BLOCK_SELECTOR, 889 ), 890 array( 891 'path' => array( 'styles', 'blocks', 'core/columns' ), 892 'selector' => '.wp-block-columns', 893 'name' => 'core/columns', 894 ), 895 ); 896 897 foreach ( $base_styles_nodes as $base_style_node ) { 898 $stylesheet .= $this->get_layout_styles( $base_style_node ); 899 } 814 900 } 815 901 … … 885 971 * and no longer returns preset classes. 886 972 * Removed the `$setting_nodes` parameter. 973 * @since 6.1.0 Moved most internal logic to `get_styles_for_block()`. 887 974 * 888 975 * @param array $style_nodes Nodes with styles. … … 899 986 } 900 987 988 return $block_rules; 989 } 990 991 /** 992 * Get the CSS layout rules for a particular block from theme.json layout definitions. 993 * 994 * @since 6.1.0 995 * 996 * @param array $block_metadata Metadata about the block to get styles for. 997 * 998 * @return string Layout styles for the block. 999 */ 1000 protected function get_layout_styles( $block_metadata ) { 1001 $block_rules = ''; 1002 $block_type = null; 1003 1004 // Skip outputting layout styles if explicitly disabled. 1005 if ( current_theme_supports( 'disable-layout-styles' ) ) { 1006 return $block_rules; 1007 } 1008 1009 if ( isset( $block_metadata['name'] ) ) { 1010 $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block_metadata['name'] ); 1011 if ( ! block_has_support( $block_type, array( '__experimentalLayout' ), false ) ) { 1012 return $block_rules; 1013 } 1014 } 1015 1016 $selector = isset( $block_metadata['selector'] ) ? $block_metadata['selector'] : ''; 1017 $has_block_gap_support = _wp_array_get( $this->theme_json, array( 'settings', 'spacing', 'blockGap' ) ) !== null; 1018 $has_fallback_gap_support = ! $has_block_gap_support; // This setting isn't useful yet: it exists as a placeholder for a future explicit fallback gap styles support. 1019 $node = _wp_array_get( $this->theme_json, $block_metadata['path'], array() ); 1020 $layout_definitions = _wp_array_get( $this->theme_json, array( 'settings', 'layout', 'definitions' ), array() ); 1021 $layout_selector_pattern = '/^[a-zA-Z0-9\-\.\ *+>:\(\)]*$/'; // Allow alphanumeric classnames, spaces, wildcard, sibling, child combinator and pseudo class selectors. 1022 1023 // Gap styles will only be output if the theme has block gap support, or supports a fallback gap. 1024 // Default layout gap styles will be skipped for themes that do not explicitly opt-in to blockGap with a `true` or `false` value. 1025 if ( $has_block_gap_support || $has_fallback_gap_support ) { 1026 $block_gap_value = null; 1027 // Use a fallback gap value if block gap support is not available. 1028 if ( ! $has_block_gap_support ) { 1029 $block_gap_value = static::ROOT_BLOCK_SELECTOR === $selector ? '0.5em' : null; 1030 if ( ! empty( $block_type ) ) { 1031 $block_gap_value = _wp_array_get( $block_type->supports, array( 'spacing', 'blockGap', '__experimentalDefault' ), null ); 1032 } 1033 } else { 1034 $block_gap_value = static::get_property_value( $node, array( 'spacing', 'blockGap' ) ); 1035 } 1036 1037 // Support split row / column values and concatenate to a shorthand value. 1038 if ( is_array( $block_gap_value ) ) { 1039 if ( isset( $block_gap_value['top'] ) && isset( $block_gap_value['left'] ) ) { 1040 $gap_row = static::get_property_value( $node, array( 'spacing', 'blockGap', 'top' ) ); 1041 $gap_column = static::get_property_value( $node, array( 'spacing', 'blockGap', 'left' ) ); 1042 $block_gap_value = $gap_row === $gap_column ? $gap_row : $gap_row . ' ' . $gap_column; 1043 } else { 1044 // Skip outputting gap value if not all sides are provided. 1045 $block_gap_value = null; 1046 } 1047 } 1048 1049 // If the block should have custom gap, add the gap styles. 1050 if ( null !== $block_gap_value && false !== $block_gap_value && '' !== $block_gap_value ) { 1051 foreach ( $layout_definitions as $layout_definition_key => $layout_definition ) { 1052 // Allow outputting fallback gap styles for flex layout type when block gap support isn't available. 1053 if ( ! $has_block_gap_support && 'flex' !== $layout_definition_key ) { 1054 continue; 1055 } 1056 1057 $class_name = sanitize_title( _wp_array_get( $layout_definition, array( 'className' ), false ) ); 1058 $spacing_rules = _wp_array_get( $layout_definition, array( 'spacingStyles' ), array() ); 1059 1060 if ( 1061 ! empty( $class_name ) && 1062 ! empty( $spacing_rules ) 1063 ) { 1064 foreach ( $spacing_rules as $spacing_rule ) { 1065 $declarations = array(); 1066 if ( 1067 isset( $spacing_rule['selector'] ) && 1068 preg_match( $layout_selector_pattern, $spacing_rule['selector'] ) && 1069 ! empty( $spacing_rule['rules'] ) 1070 ) { 1071 // Iterate over each of the styling rules and substitute non-string values such as `null` with the real `blockGap` value. 1072 foreach ( $spacing_rule['rules'] as $css_property => $css_value ) { 1073 $current_css_value = is_string( $css_value ) ? $css_value : $block_gap_value; 1074 if ( static::is_safe_css_declaration( $css_property, $current_css_value ) ) { 1075 $declarations[] = array( 1076 'name' => $css_property, 1077 'value' => $current_css_value, 1078 ); 1079 } 1080 } 1081 1082 if ( ! $has_block_gap_support ) { 1083 // For fallback gap styles, use lower specificity, to ensure styles do not unintentionally override theme styles. 1084 $format = static::ROOT_BLOCK_SELECTOR === $selector ? ':where(.%2$s%3$s)' : ':where(%1$s.%2$s%3$s)'; 1085 $layout_selector = sprintf( 1086 $format, 1087 $selector, 1088 $class_name, 1089 $spacing_rule['selector'] 1090 ); 1091 } else { 1092 $format = static::ROOT_BLOCK_SELECTOR === $selector ? '%s .%s%s' : '%s.%s%s'; 1093 $layout_selector = sprintf( 1094 $format, 1095 $selector, 1096 $class_name, 1097 $spacing_rule['selector'] 1098 ); 1099 } 1100 $block_rules .= static::to_ruleset( $layout_selector, $declarations ); 1101 } 1102 } 1103 } 1104 } 1105 } 1106 } 1107 1108 // Output base styles. 1109 if ( 1110 static::ROOT_BLOCK_SELECTOR === $selector 1111 ) { 1112 $valid_display_modes = array( 'block', 'flex', 'grid' ); 1113 foreach ( $layout_definitions as $layout_definition ) { 1114 $class_name = sanitize_title( _wp_array_get( $layout_definition, array( 'className' ), false ) ); 1115 $base_style_rules = _wp_array_get( $layout_definition, array( 'baseStyles' ), array() ); 1116 1117 if ( 1118 ! empty( $class_name ) && 1119 ! empty( $base_style_rules ) 1120 ) { 1121 // Output display mode. This requires special handling as `display` is not exposed in `safe_style_css_filter`. 1122 if ( 1123 ! empty( $layout_definition['displayMode'] ) && 1124 is_string( $layout_definition['displayMode'] ) && 1125 in_array( $layout_definition['displayMode'], $valid_display_modes, true ) 1126 ) { 1127 $layout_selector = sprintf( 1128 '%s .%s', 1129 $selector, 1130 $class_name 1131 ); 1132 $block_rules .= static::to_ruleset( 1133 $layout_selector, 1134 array( 1135 array( 1136 'name' => 'display', 1137 'value' => $layout_definition['displayMode'], 1138 ), 1139 ) 1140 ); 1141 } 1142 1143 foreach ( $base_style_rules as $base_style_rule ) { 1144 $declarations = array(); 1145 1146 if ( 1147 isset( $base_style_rule['selector'] ) && 1148 preg_match( $layout_selector_pattern, $base_style_rule['selector'] ) && 1149 ! empty( $base_style_rule['rules'] ) 1150 ) { 1151 foreach ( $base_style_rule['rules'] as $css_property => $css_value ) { 1152 if ( static::is_safe_css_declaration( $css_property, $css_value ) ) { 1153 $declarations[] = array( 1154 'name' => $css_property, 1155 'value' => $css_value, 1156 ); 1157 } 1158 } 1159 1160 $layout_selector = sprintf( 1161 '%s .%s%s', 1162 $selector, 1163 $class_name, 1164 $base_style_rule['selector'] 1165 ); 1166 $block_rules .= static::to_ruleset( $layout_selector, $declarations ); 1167 } 1168 } 1169 } 1170 } 1171 } 901 1172 return $block_rules; 902 1173 } … … 1328 1599 * @since 5.8.0 1329 1600 * @since 5.9.0 Added the `$settings` and `$properties` parameters. 1330 * @since 6.1.0 Added the `$theme_json` parameter. 1331 * 1332 * @param array $styles Styles to process. 1333 * @param array $settings Theme settings. 1334 * @param array $properties Properties metadata. 1335 * @param array $theme_json Theme JSON array. 1336 * @return array Returns the modified $declarations. 1337 */ 1338 protected static function compute_style_properties( $styles, $settings = array(), $properties = null, $theme_json = null ) { 1601 * @since 6.1.0 Added `$theme_json`, `$selector`, and `$use_root_padding` parameters. 1602 * 1603 * @param array $styles Styles to process. 1604 * @param array $settings Theme settings. 1605 * @param array $properties Properties metadata. 1606 * @param array $theme_json Theme JSON array. 1607 * @param string $selector The style block selector. 1608 * @param boolean $use_root_padding Whether to add custom properties at root level. 1609 * @return array Returns the modified $declarations. 1610 */ 1611 protected static function compute_style_properties( $styles, $settings = array(), $properties = null, $theme_json = null, $selector = null, $use_root_padding = null ) { 1339 1612 if ( null === $properties ) { 1340 1613 $properties = static::PROPERTIES_METADATA; … … 1346 1619 } 1347 1620 1621 $root_variable_duplicates = array(); 1622 1348 1623 foreach ( $properties as $css_property => $value_path ) { 1349 1624 $value = static::get_property_value( $styles, $value_path, $theme_json ); 1625 1626 if ( str_starts_with( $css_property, '--wp--style--root--' ) && ( static::ROOT_BLOCK_SELECTOR !== $selector || ! $use_root_padding ) ) { 1627 continue; 1628 } 1629 // Root-level padding styles don't currently support strings with CSS shorthand values. 1630 // This may change: https://github.com/WordPress/gutenberg/issues/40132. 1631 if ( '--wp--style--root--padding' === $css_property && is_string( $value ) ) { 1632 continue; 1633 } 1634 1635 if ( str_starts_with( $css_property, '--wp--style--root--' ) && $use_root_padding ) { 1636 $root_variable_duplicates[] = substr( $css_property, strlen( '--wp--style--root--' ) ); 1637 } 1350 1638 1351 1639 // Look up protected properties, keyed by value path. … … 1373 1661 } 1374 1662 1663 // If a variable value is added to the root, the corresponding property should be removed. 1664 foreach ( $root_variable_duplicates as $duplicate ) { 1665 $discard = array_search( $duplicate, array_column( $declarations, 'name' ), true ); 1666 if ( is_numeric( $discard ) ) { 1667 array_splice( $declarations, $discard, 1 ); 1668 } 1669 } 1670 1375 1671 return $declarations; 1376 1672 } … … 1397 1693 */ 1398 1694 protected static function get_property_value( $styles, $path, $theme_json = null ) { 1399 $value = _wp_array_get( $styles, $path , '');1695 $value = _wp_array_get( $styles, $path ); 1400 1696 1401 1697 /* … … 1430 1726 } 1431 1727 1432 if ( '' === $value ||is_array( $value ) ) {1728 if ( is_array( $value ) ) { 1433 1729 return $value; 1434 1730 } … … 1623 1919 } 1624 1920 1921 $feature_selectors = null; 1922 if ( isset( $selectors[ $name ]['features'] ) ) { 1923 $feature_selectors = $selectors[ $name ]['features']; 1924 } 1925 1625 1926 $nodes[] = array( 1626 1927 'name' => $name, … … 1628 1929 'selector' => $selector, 1629 1930 'duotone' => $duotone_selector, 1931 'features' => $feature_selectors, 1630 1932 ); 1631 1933 … … 1660 1962 * @since 6.1.0 1661 1963 * 1662 * @param array $block_metadata Meta data about the block to get styles for. 1663 * @return array Styles for the block. 1964 * @param array $block_metadata Metadata about the block to get styles for. 1965 * 1966 * @return string Styles for the block. 1664 1967 */ 1665 1968 public function get_styles_for_block( $block_metadata ) { 1666 1667 $node = _wp_array_get( $this->theme_json, $block_metadata['path'], array() ); 1668 1669 $selector = $block_metadata['selector']; 1670 $settings = _wp_array_get( $this->theme_json, array( 'settings' ) ); 1969 $node = _wp_array_get( $this->theme_json, $block_metadata['path'], array() ); 1970 $use_root_padding = isset( $this->theme_json['settings']['useRootPaddingAwareAlignments'] ) && true === $this->theme_json['settings']['useRootPaddingAwareAlignments']; 1971 $selector = $block_metadata['selector']; 1972 $settings = _wp_array_get( $this->theme_json, array( 'settings' ) ); 1973 1974 /* 1975 * Process style declarations for block support features the current 1976 * block contains selectors for. Values for a feature with a custom 1977 * selector are filtered from the theme.json node before it is 1978 * processed as normal. 1979 */ 1980 $feature_declarations = array(); 1981 1982 if ( ! empty( $block_metadata['features'] ) ) { 1983 foreach ( $block_metadata['features'] as $feature_name => $feature_selector ) { 1984 if ( ! empty( $node[ $feature_name ] ) ) { 1985 // Create temporary node containing only the feature data 1986 // to leverage existing `compute_style_properties` function. 1987 $feature = array( $feature_name => $node[ $feature_name ] ); 1988 // Generate the feature's declarations only. 1989 $new_feature_declarations = static::compute_style_properties( $feature, $settings, null, $this->theme_json ); 1990 1991 // Merge new declarations with any that already exist for 1992 // the feature selector. This may occur when multiple block 1993 // support features use the same custom selector. 1994 if ( isset( $feature_declarations[ $feature_selector ] ) ) { 1995 $feature_declarations[ $feature_selector ] = array_merge( $feature_declarations[ $feature_selector ], $new_feature_declarations ); 1996 } else { 1997 $feature_declarations[ $feature_selector ] = $new_feature_declarations; 1998 } 1999 2000 // Remove the feature from the block's node now the 2001 // styles will be included under the feature level selector. 2002 unset( $node[ $feature_name ] ); 2003 } 2004 } 2005 } 1671 2006 1672 2007 /* … … 1710 2045 && in_array( $pseudo_selector, static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ], true ) 1711 2046 ) { 1712 $declarations = static::compute_style_properties( $node[ $pseudo_selector ], $settings, null, $this->theme_json );2047 $declarations = static::compute_style_properties( $node[ $pseudo_selector ], $settings, null, $this->theme_json, $selector, $use_root_padding ); 1713 2048 } else { 1714 $declarations = static::compute_style_properties( $node, $settings, null, $this->theme_json );2049 $declarations = static::compute_style_properties( $node, $settings, null, $this->theme_json, $selector, $use_root_padding ); 1715 2050 } 1716 2051 … … 1729 2064 } 1730 2065 1731 /*1732 * Reset default browser margin on the root body element.1733 * This is set on the root selector **before** generating the ruleset1734 * from the `theme.json`. This is to ensure that if the `theme.json` declares1735 * `margin` in its `spacing` declaration for the `body` element then these1736 * user-generated values take precedence in the CSS cascade.1737 * @link https://github.com/WordPress/gutenberg/issues/36147.1738 */1739 if ( static::ROOT_BLOCK_SELECTOR === $selector ) {1740 $block_rules .= 'body { margin: 0; }';1741 }1742 1743 2066 // 2. Generate and append the rules that use the general selector. 1744 2067 $block_rules .= static::to_ruleset( $selector, $declarations ); … … 1750 2073 } 1751 2074 1752 if ( static::ROOT_BLOCK_SELECTOR === $selector ) { 1753 $block_rules .= '.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }'; 1754 $block_rules .= '.wp-site-blocks > .alignright { float: right; margin-left: 2em; }'; 1755 $block_rules .= '.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; 1756 1757 $has_block_gap_support = _wp_array_get( $this->theme_json, array( 'settings', 'spacing', 'blockGap' ) ) !== null; 1758 if ( $has_block_gap_support ) { 1759 $block_rules .= '.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }'; 1760 $block_rules .= '.wp-site-blocks > * + * { margin-block-start: var( --wp--style--block-gap ); }'; 1761 } 2075 // 4. Generate Layout block gap styles. 2076 if ( 2077 static::ROOT_BLOCK_SELECTOR !== $selector && 2078 ! empty( $block_metadata['name'] ) 2079 ) { 2080 $block_rules .= $this->get_layout_styles( $block_metadata ); 2081 } 2082 2083 // 5. Generate and append the feature level rulesets. 2084 foreach ( $feature_declarations as $feature_selector => $individual_feature_declarations ) { 2085 $block_rules .= static::to_ruleset( $feature_selector, $individual_feature_declarations ); 1762 2086 } 1763 2087 1764 2088 return $block_rules; 2089 } 2090 2091 /** 2092 * Outputs the CSS for layout rules on the root. 2093 * 2094 * @since 6.1.0 2095 * 2096 * @param string $selector The root node selector. 2097 * @param array $block_metadata The metadata for the root block. 2098 * @return string The additional root rules CSS. 2099 */ 2100 public function get_root_layout_rules( $selector, $block_metadata ) { 2101 $css = ''; 2102 $settings = _wp_array_get( $this->theme_json, array( 'settings' ) ); 2103 $use_root_padding = isset( $this->theme_json['settings']['useRootPaddingAwareAlignments'] ) && true === $this->theme_json['settings']['useRootPaddingAwareAlignments']; 2104 2105 /* 2106 * Reset default browser margin on the root body element. 2107 * This is set on the root selector **before** generating the ruleset 2108 * from the `theme.json`. This is to ensure that if the `theme.json` declares 2109 * `margin` in its `spacing` declaration for the `body` element then these 2110 * user-generated values take precedence in the CSS cascade. 2111 * @link https://github.com/WordPress/gutenberg/issues/36147. 2112 */ 2113 $css .= 'body { margin: 0;'; 2114 2115 /* 2116 * If there are content and wide widths in theme.json, output them 2117 * as custom properties on the body element so all blocks can use them. 2118 */ 2119 if ( isset( $settings['layout']['contentSize'] ) || isset( $settings['layout']['wideSize'] ) ) { 2120 $content_size = isset( $settings['layout']['contentSize'] ) ? $settings['layout']['contentSize'] : $settings['layout']['wideSize']; 2121 $content_size = static::is_safe_css_declaration( 'max-width', $content_size ) ? $content_size : 'initial'; 2122 $wide_size = isset( $settings['layout']['wideSize'] ) ? $settings['layout']['wideSize'] : $settings['layout']['contentSize']; 2123 $wide_size = static::is_safe_css_declaration( 'max-width', $wide_size ) ? $wide_size : 'initial'; 2124 $css .= '--wp--style--global--content-size: ' . $content_size . ';'; 2125 $css .= '--wp--style--global--wide-size: ' . $wide_size . ';'; 2126 } 2127 2128 $css .= ' }'; 2129 2130 if ( $use_root_padding ) { 2131 // Top and bottom padding are applied to the outer block container. 2132 $css .= '.wp-site-blocks { padding-top: var(--wp--style--root--padding-top); padding-bottom: var(--wp--style--root--padding-bottom); }'; 2133 // Right and left padding are applied to the first container with `.has-global-padding` class. 2134 $css .= '.has-global-padding { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); }'; 2135 // Nested containers with `.has-global-padding` class do not get padding. 2136 $css .= '.has-global-padding :where(.has-global-padding) { padding-right: 0; padding-left: 0; }'; 2137 // Alignfull children of the container with left and right padding have negative margins so they can still be full width. 2138 $css .= '.has-global-padding > .alignfull { margin-right: calc(var(--wp--style--root--padding-right) * -1); margin-left: calc(var(--wp--style--root--padding-left) * -1); }'; 2139 // The above rule is negated for alignfull children of nested containers. 2140 $css .= '.has-global-padding :where(.has-global-padding) > .alignfull { margin-right: 0; margin-left: 0; }'; 2141 // Some of the children of alignfull blocks without content width should also get padding: text blocks and non-alignfull container blocks. 2142 $css .= '.has-global-padding > .alignfull:where(:not(.has-global-padding)) > :where([class*="wp-block-"]:not(.alignfull):not([class*="__"]),p,h1,h2,h3,h4,h5,h6,ul,ol) { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); }'; 2143 // The above rule also has to be negated for blocks inside nested `.has-global-padding` blocks. 2144 $css .= '.has-global-padding :where(.has-global-padding) > .alignfull:where(:not(.has-global-padding)) > :where([class*="wp-block-"]:not(.alignfull):not([class*="__"]),p,h1,h2,h3,h4,h5,h6,ul,ol) { padding-right: 0; padding-left: 0; }'; 2145 } 2146 2147 $css .= '.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }'; 2148 $css .= '.wp-site-blocks > .alignright { float: right; margin-left: 2em; }'; 2149 $css .= '.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; 2150 2151 $block_gap_value = _wp_array_get( $this->theme_json, array( 'styles', 'spacing', 'blockGap' ), '0.5em' ); 2152 $has_block_gap_support = _wp_array_get( $this->theme_json, array( 'settings', 'spacing', 'blockGap' ) ) !== null; 2153 if ( $has_block_gap_support ) { 2154 $block_gap_value = static::get_property_value( $this->theme_json, array( 'styles', 'spacing', 'blockGap' ) ); 2155 $css .= '.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }'; 2156 $css .= ".wp-site-blocks > * + * { margin-block-start: $block_gap_value; }"; 2157 2158 // For backwards compatibility, ensure the legacy block gap CSS variable is still available. 2159 $css .= "$selector { --wp--style--block-gap: $block_gap_value; }"; 2160 } 2161 $css .= $this->get_layout_styles( $block_metadata ); 2162 2163 return $css; 1765 2164 } 1766 2165 -
trunk/src/wp-includes/global-styles-and-settings.php
r54160 r54162 108 108 $supports_theme_json = WP_Theme_JSON_Resolver::theme_has_support(); 109 109 if ( empty( $types ) && ! $supports_theme_json ) { 110 $types = array( 'variables', 'presets' );110 $types = array( 'variables', 'presets', 'base-layout-styles' ); 111 111 } elseif ( empty( $types ) ) { 112 112 $types = array( 'variables', 'styles', 'presets' ); -
trunk/src/wp-includes/theme.json
r54160 r54162 3 3 "settings": { 4 4 "appearanceTools": false, 5 "useRootPaddingAwareAlignments": false, 5 6 "border": { 6 7 "color": false, … … 13 14 "custom": true, 14 15 "customDuotone": true, 15 16 16 "customGradient": true, 17 "defaultDuotone": true, 17 18 "defaultGradients": true, 18 19 "defaultPalette": true, … … 185 186 ], 186 187 "text": true 188 }, 189 "layout": { 190 "definitions": { 191 "default": { 192 "name": "default", 193 "slug": "flow", 194 "className": "is-layout-flow", 195 "baseStyles": [ 196 { 197 "selector": " > .alignleft", 198 "rules": { 199 "float": "left", 200 "margin-inline-start": "0", 201 "margin-inline-end": "2em" 202 } 203 }, 204 { 205 "selector": " > .alignright", 206 "rules": { 207 "float": "right", 208 "margin-inline-start": "2em", 209 "margin-inline-end": "0" 210 } 211 }, 212 { 213 "selector": " > .aligncenter", 214 "rules": { 215 "margin-left": "auto !important", 216 "margin-right": "auto !important" 217 } 218 } 219 ], 220 "spacingStyles": [ 221 { 222 "selector": " > *", 223 "rules": { 224 "margin-block-start": "0", 225 "margin-block-end": "0" 226 } 227 }, 228 { 229 "selector": " > * + *", 230 "rules": { 231 "margin-block-start": null, 232 "margin-block-end": "0" 233 } 234 } 235 ] 236 }, 237 "constrained": { 238 "name": "constrained", 239 "slug": "constrained", 240 "className": "is-layout-constrained", 241 "baseStyles": [ 242 { 243 "selector": " > .alignleft", 244 "rules": { 245 "float": "left", 246 "margin-inline-start": "0", 247 "margin-inline-end": "2em" 248 } 249 }, 250 { 251 "selector": " > .alignright", 252 "rules": { 253 "float": "right", 254 "margin-inline-start": "2em", 255 "margin-inline-end": "0" 256 } 257 }, 258 { 259 "selector": " > .aligncenter", 260 "rules": { 261 "margin-left": "auto !important", 262 "margin-right": "auto !important" 263 } 264 }, 265 { 266 "selector": " > :where(:not(.alignleft):not(.alignright):not(.alignfull))", 267 "rules": { 268 "max-width": "var(--wp--style--global--content-size)", 269 "margin-left": "auto !important", 270 "margin-right": "auto !important" 271 } 272 }, 273 { 274 "selector": " > .alignwide", 275 "rules": { 276 "max-width": "var(--wp--style--global--wide-size)" 277 } 278 } 279 ], 280 "spacingStyles": [ 281 { 282 "selector": " > *", 283 "rules": { 284 "margin-block-start": "0", 285 "margin-block-end": "0" 286 } 287 }, 288 { 289 "selector": " > * + *", 290 "rules": { 291 "margin-block-start": null, 292 "margin-block-end": "0" 293 } 294 } 295 ] 296 }, 297 "flex": { 298 "name": "flex", 299 "slug": "flex", 300 "className": "is-layout-flex", 301 "displayMode": "flex", 302 "baseStyles": [ 303 { 304 "selector": "", 305 "rules": { 306 "flex-wrap": "wrap", 307 "align-items": "center" 308 } 309 }, 310 { 311 "selector": " > *", 312 "rules": { 313 "margin": "0" 314 } 315 } 316 ], 317 "spacingStyles": [ 318 { 319 "selector": "", 320 "rules": { 321 "gap": null 322 } 323 } 324 ] 325 } 326 } 187 327 }, 188 328 "spacing": { … … 190 330 "margin": false, 191 331 "padding": false, 192 "units": [ "px", "em", "rem", "vh", "vw", "%" ] 332 "customSpacingSize": true, 333 "units": [ "px", "em", "rem", "vh", "vw", "%" ], 334 "spacingScale": { 335 "operator": "*", 336 "increment": 1.5, 337 "steps": 7, 338 "mediumStep": 1.5, 339 "unit": "rem" 340 } 193 341 }, 194 342 "typography": { … … 241 389 }, 242 390 "styles": { 243 "spacing": { "blockGap": "24px" } 391 "elements": { 392 "button": { 393 "color": { 394 "text": "#fff", 395 "background": "#32373c" 396 }, 397 "spacing": { 398 "padding": "calc(0.667em + 2px) calc(1.333em + 2px)" 399 }, 400 "typography": { 401 "fontSize": "inherit", 402 "fontFamily": "inherit", 403 "lineHeight": "inherit", 404 "textDecoration": "none" 405 }, 406 "border": { 407 "width": "0" 408 } 409 }, 410 "link": { 411 "typography": { 412 "textDecoration": "underline" 413 } 414 } 415 }, 416 "spacing": { 417 "blockGap": "24px", 418 "padding": { 419 "top": "0px", 420 "right": "0px", 421 "bottom": "0px", 422 "left": "0px" 423 } 424 } 244 425 } 245 426 } -
trunk/src/wp-includes/theme.php
r54160 r54162 4028 4028 ); 4029 4029 register_theme_feature( 4030 'disable-layout-styles', 4031 array( 4032 'description' => __( 'Whether the theme disables generated layout styles.' ), 4033 'show_in_rest' => true, 4034 ) 4035 ); 4036 register_theme_feature( 4030 4037 'editor-color-palette', 4031 4038 array( -
trunk/tests/phpunit/tests/blocks/editor.php
r54160 r54162 203 203 $settings = get_default_block_editor_settings(); 204 204 205 $this->assertCount( 1 8, $settings );205 $this->assertCount( 19, $settings ); 206 206 $this->assertFalse( $settings['alignWide'] ); 207 207 $this->assertIsArray( $settings['allowedMimeTypes'] ); … … 250 250 $this->assertFalse( $settings['disableCustomFontSizes'] ); 251 251 $this->assertFalse( $settings['disableCustomGradients'] ); 252 $this->assertFalse( $settings['disableLayoutStyles'] ); 252 253 $this->assertFalse( $settings['enableCustomLineHeight'] ); 253 254 $this->assertFalse( $settings['enableCustomSpacing'] ); -
trunk/tests/phpunit/tests/rest-api/rest-themes-controller.php
r54160 r54162 397 397 $this->assertArrayHasKey( 'disable-custom-font-sizes', $theme_supports ); 398 398 $this->assertArrayHasKey( 'disable-custom-gradients', $theme_supports ); 399 $this->assertArrayHasKey( 'disable-layout-styles', $theme_supports ); 399 400 $this->assertArrayHasKey( 'editor-color-palette', $theme_supports ); 400 401 $this->assertArrayHasKey( 'editor-font-sizes', $theme_supports ); … … 407 408 $this->assertArrayHasKey( 'title-tag', $theme_supports ); 408 409 $this->assertArrayHasKey( 'wp-block-styles', $theme_supports ); 409 $this->assertCount( 2 1, $theme_supports );410 $this->assertCount( 22, $theme_supports ); 410 411 } 411 412 -
trunk/tests/phpunit/tests/theme/wpThemeJson.php
r54160 r54162 424 424 ); 425 425 426 $expected = 'body { margin: 0; } body{--wp--style--block-gap: 1em;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }.wp-site-blocks > * + * { margin-block-start: var( --wp--style--block-gap ); }';426 $expected = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }.wp-site-blocks > * + * { margin-block-start: 1em; }body { --wp--style--block-gap: 1em; }'; 427 427 $this->assertSame( $expected, $theme_json->get_stylesheet() ); 428 428 $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) ); … … 545 545 ), 546 546 ), 547 'spacing' => array( 548 'blockGap' => '24px', 549 ), 547 550 ), 548 551 'misc' => 'value', … … 551 554 552 555 $variables = 'body{--wp--preset--color--grey: grey;--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}.wp-block-group{--wp--custom--base-font: 16;--wp--custom--line-height--small: 1.2;--wp--custom--line-height--medium: 1.4;--wp--custom--line-height--large: 1.8;}'; 553 $styles = 'body { margin: 0; } body{color: var(--wp--preset--color--grey);}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto;}a:where(:not(.wp-element-button)){background-color: #333;color: #111;}.wp-block-group{border-radius: 10px;padding: 24px;}.wp-block-group a:where(:not(.wp-element-button)){color: #111;}h1,h2,h3,h4,h5,h6{color: #123456;}h1 a:where(:not(.wp-element-button)),h2 a:where(:not(.wp-element-button)),h3 a:where(:not(.wp-element-button)),h4 a:where(:not(.wp-element-button)),h5 a:where(:not(.wp-element-button)),h6 a:where(:not(.wp-element-button)){background-color: #333;color: #111;font-size: 60px;}.wp-block-post-date{color: #123456;}.wp-block-post-date a:where(:not(.wp-element-button)){background-color: #777;color: #555;}.wp-block-image{border-top-left-radius: 10px;border-bottom-right-radius: 1em;margin-bottom: 30px;}';556 $styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }body{color: var(--wp--preset--color--grey);}a:where(:not(.wp-element-button)){background-color: #333;color: #111;}.wp-block-group{border-radius: 10px;padding: 24px;}.wp-block-group a:where(:not(.wp-element-button)){color: #111;}h1,h2,h3,h4,h5,h6{color: #123456;}h1 a:where(:not(.wp-element-button)),h2 a:where(:not(.wp-element-button)),h3 a:where(:not(.wp-element-button)),h4 a:where(:not(.wp-element-button)),h5 a:where(:not(.wp-element-button)),h6 a:where(:not(.wp-element-button)){background-color: #333;color: #111;font-size: 60px;}.wp-block-post-date{color: #123456;}.wp-block-post-date a:where(:not(.wp-element-button)){background-color: #777;color: #555;}.wp-block-image{border-top-left-radius: 10px;border-bottom-right-radius: 1em;margin-bottom: 30px;}'; 554 557 $presets = '.has-grey-color{color: var(--wp--preset--color--grey) !important;}.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}.has-small-font-family{font-family: var(--wp--preset--font-family--small) !important;}.has-big-font-family{font-family: var(--wp--preset--font-family--big) !important;}'; 555 558 $all = $variables . $styles . $presets; … … 2676 2679 'core/group' => array( 2677 2680 'spacing' => array( 2678 'margin' 2679 ' blockGap' => 'invalid value',2681 'margin' => 'valid value', 2682 'display' => 'none', 2680 2683 ), 2681 2684 ), … … 2990 2993 ); 2991 2994 2992 $expected = 'body { margin: 0; } body{background-color: #ffffff;color: #000000;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto;}.wp-element-button, .wp-block-button__link{background-color: #000000;color: #ffffff;}';2995 $expected = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }body{background-color: #ffffff;color: #000000;}.wp-element-button, .wp-block-button__link{background-color: #000000;color: #ffffff;}'; 2993 2996 $this->assertSame( $expected, $theme_json->get_stylesheet() ); 2994 2997 } … … 3022 3025 ); 3023 3026 3024 $expected = 'body { margin: 0; } body{background-color: #ffffff;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto;}.wp-element-button, .wp-block-button__link{color: #ffffff;}';3027 $expected = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }body{background-color: #ffffff;}.wp-element-button, .wp-block-button__link{color: #ffffff;}'; 3025 3028 $this->assertSame( $expected, $theme_json->get_stylesheet() ); 3026 3029 } … … 3054 3057 ); 3055 3058 3056 $expected = 'body { margin: 0; } body{background-color: #ffffff;color: #ffffff;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto;}.wp-element-button, .wp-block-button__link{color: #ffffff;}';3059 $expected = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }body{background-color: #ffffff;color: #ffffff;}.wp-element-button, .wp-block-button__link{color: #ffffff;}'; 3057 3060 $this->assertSame( $expected, $theme_json->get_stylesheet() ); 3058 3061 } … … 3078 3081 ); 3079 3082 3080 $expected = 'body { margin: 0; } body{background-color: #ffffff;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto;}';3083 $expected = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }body{background-color: #ffffff;}'; 3081 3084 $this->assertSame( $expected, $theme_json->get_stylesheet() ); 3082 3085 } 3083 3086 3087 3088 /** 3089 * @dataProvider data_get_layout_definitions 3090 * 3091 * @ticket 56467 3092 * 3093 * @param array $layout_definitions Layout definitions as stored in core theme.json. 3094 */ 3095 public function test_get_stylesheet_generates_layout_styles( $layout_definitions ) { 3096 $theme_json = new WP_Theme_JSON( 3097 array( 3098 'version' => WP_Theme_JSON::LATEST_SCHEMA, 3099 'settings' => array( 3100 'layout' => array( 3101 'definitions' => $layout_definitions, 3102 ), 3103 'spacing' => array( 3104 'blockGap' => true, 3105 ), 3106 ), 3107 'styles' => array( 3108 'spacing' => array( 3109 'blockGap' => '1em', 3110 ), 3111 ), 3112 ), 3113 'default' 3114 ); 3115 3116 // Results also include root site blocks styles. 3117 $this->assertSame( 3118 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }.wp-site-blocks > * + * { margin-block-start: 1em; }body { --wp--style--block-gap: 1em; }body .is-layout-flow > *{margin-block-start: 0;margin-block-end: 0;}body .is-layout-flow > * + *{margin-block-start: 1em;margin-block-end: 0;}body .is-layout-flex{gap: 1em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}', 3119 $theme_json->get_stylesheet( array( 'styles' ) ) 3120 ); 3121 } 3122 3123 /** 3124 * @dataProvider data_get_layout_definitions 3125 * 3126 * @ticket 56467 3127 * 3128 * @param array $layout_definitions Layout definitions as stored in core theme.json. 3129 */ 3130 public function test_get_stylesheet_generates_layout_styles_with_spacing_presets( $layout_definitions ) { 3131 $theme_json = new WP_Theme_JSON( 3132 array( 3133 'version' => WP_Theme_JSON::LATEST_SCHEMA, 3134 'settings' => array( 3135 'layout' => array( 3136 'definitions' => $layout_definitions, 3137 ), 3138 'spacing' => array( 3139 'blockGap' => true, 3140 ), 3141 ), 3142 'styles' => array( 3143 'spacing' => array( 3144 'blockGap' => 'var:preset|spacing|60', 3145 ), 3146 ), 3147 ), 3148 'default' 3149 ); 3150 3151 // Results also include root site blocks styles. 3152 $this->assertSame( 3153 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }.wp-site-blocks > * + * { margin-block-start: var(--wp--preset--spacing--60); }body { --wp--style--block-gap: var(--wp--preset--spacing--60); }body .is-layout-flow > *{margin-block-start: 0;margin-block-end: 0;}body .is-layout-flow > * + *{margin-block-start: var(--wp--preset--spacing--60);margin-block-end: 0;}body .is-layout-flex{gap: var(--wp--preset--spacing--60);}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}', 3154 $theme_json->get_stylesheet( array( 'styles' ) ) 3155 ); 3156 } 3157 3158 /** 3159 * @dataProvider data_get_layout_definitions 3160 * 3161 * @ticket 56467 3162 * 3163 * @param array $layout_definitions Layout definitions as stored in core theme.json. 3164 */ 3165 public function test_get_stylesheet_generates_fallback_gap_layout_styles( $layout_definitions ) { 3166 $theme_json = new WP_Theme_JSON( 3167 array( 3168 'version' => WP_Theme_JSON::LATEST_SCHEMA, 3169 'settings' => array( 3170 'layout' => array( 3171 'definitions' => $layout_definitions, 3172 ), 3173 'spacing' => array( 3174 'blockGap' => null, 3175 ), 3176 ), 3177 'styles' => array( 3178 'spacing' => array( 3179 'blockGap' => '1em', 3180 ), 3181 ), 3182 ), 3183 'default' 3184 ); 3185 $stylesheet = $theme_json->get_stylesheet( array( 'styles' ) ); 3186 3187 // Results also include root site blocks styles. 3188 $this->assertSame( 3189 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}', 3190 $stylesheet 3191 ); 3192 } 3193 3194 /** 3195 * @dataProvider data_get_layout_definitions 3196 * 3197 * @ticket 56467 3198 * 3199 * @param array $layout_definitions Layout definitions as stored in core theme.json. 3200 */ 3201 public function test_get_stylesheet_generates_base_fallback_gap_layout_styles( $layout_definitions ) { 3202 $theme_json = new WP_Theme_JSON( 3203 array( 3204 'version' => WP_Theme_JSON::LATEST_SCHEMA, 3205 'settings' => array( 3206 'layout' => array( 3207 'definitions' => $layout_definitions, 3208 ), 3209 'spacing' => array( 3210 'blockGap' => null, 3211 ), 3212 ), 3213 ), 3214 'default' 3215 ); 3216 $stylesheet = $theme_json->get_stylesheet( array( 'base-layout-styles' ) ); 3217 3218 // Note the `base-layout-styles` includes a fallback gap for the Columns block for backwards compatibility. 3219 $this->assertSame( 3220 ':where(.is-layout-flex){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}:where(.wp-block-columns.is-layout-flex){gap: 2em;}', 3221 $stylesheet 3222 ); 3223 } 3224 3225 /** 3226 * @dataProvider data_get_layout_definitions 3227 * 3228 * @ticket 56467 3229 * 3230 * @param array $layout_definitions Layout definitions as stored in core theme.json. 3231 */ 3232 public function test_get_stylesheet_skips_layout_styles( $layout_definitions ) { 3233 add_theme_support( 'disable-layout-styles' ); 3234 $theme_json = new WP_Theme_JSON( 3235 array( 3236 'version' => WP_Theme_JSON::LATEST_SCHEMA, 3237 'settings' => array( 3238 'layout' => array( 3239 'definitions' => $layout_definitions, 3240 ), 3241 'spacing' => array( 3242 'blockGap' => null, 3243 ), 3244 ), 3245 ), 3246 'default' 3247 ); 3248 $stylesheet = $theme_json->get_stylesheet( array( 'base-layout-styles' ) ); 3249 remove_theme_support( 'disable-layout-styles' ); 3250 3251 // All Layout styles should be skipped. 3252 $this->assertSame( 3253 '', 3254 $stylesheet 3255 ); 3256 } 3257 3258 /** 3259 * @dataProvider data_get_layout_definitions 3260 * 3261 * @ticket 56467 3262 * 3263 * @param array $layout_definitions Layout definitions as stored in core theme.json. 3264 */ 3265 public function test_get_stylesheet_generates_valid_block_gap_values_and_skips_null_or_false_values( $layout_definitions ) { 3266 $theme_json = new WP_Theme_JSON( 3267 array( 3268 'version' => WP_Theme_JSON::LATEST_SCHEMA, 3269 'settings' => array( 3270 'layout' => array( 3271 'definitions' => $layout_definitions, 3272 ), 3273 'spacing' => array( 3274 'blockGap' => true, 3275 ), 3276 ), 3277 'styles' => array( 3278 'spacing' => array( 3279 'blockGap' => '1rem', 3280 ), 3281 'blocks' => array( 3282 'core/post-content' => array( 3283 'color' => array( 3284 'text' => 'gray', // This value should not render block layout styles. 3285 ), 3286 ), 3287 'core/social-links' => array( 3288 'spacing' => array( 3289 'blockGap' => '0', // This value should render block layout gap as zero. 3290 ), 3291 ), 3292 'core/buttons' => array( 3293 'spacing' => array( 3294 'blockGap' => 0, // This value should render block layout gap as zero. 3295 ), 3296 ), 3297 'core/columns' => array( 3298 'spacing' => array( 3299 'blockGap' => false, // This value should be ignored. The block will use the global layout value. 3300 ), 3301 ), 3302 ), 3303 ), 3304 ), 3305 'default' 3306 ); 3307 3308 $this->assertEquals( 3309 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }.wp-site-blocks > * + * { margin-block-start: 1rem; }body { --wp--style--block-gap: 1rem; }body .is-layout-flow > *{margin-block-start: 0;margin-block-end: 0;}body .is-layout-flow > * + *{margin-block-start: 1rem;margin-block-end: 0;}body .is-layout-flex{gap: 1rem;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}.wp-block-post-content{color: gray;}.wp-block-social-links.is-layout-flow > *{margin-block-start: 0;margin-block-end: 0;}.wp-block-social-links.is-layout-flow > * + *{margin-block-start: 0;margin-block-end: 0;}.wp-block-social-links.is-layout-flex{gap: 0;}.wp-block-buttons.is-layout-flow > *{margin-block-start: 0;margin-block-end: 0;}.wp-block-buttons.is-layout-flow > * + *{margin-block-start: 0;margin-block-end: 0;}.wp-block-buttons.is-layout-flex{gap: 0;}', 3310 $theme_json->get_stylesheet() 3311 ); 3312 } 3313 3314 /** 3315 * Data provider for layout tests. 3316 * 3317 * @ticket 56467 3318 * 3319 * @return array 3320 */ 3321 public function data_get_layout_definitions() { 3322 return array( 3323 'layout definitions' => array( 3324 array( 3325 'default' => array( 3326 'name' => 'default', 3327 'slug' => 'flow', 3328 'className' => 'is-layout-flow', 3329 'baseStyles' => array( 3330 array( 3331 'selector' => ' > .alignleft', 3332 'rules' => array( 3333 'float' => 'left', 3334 'margin-inline-start' => '0', 3335 'margin-inline-end' => '2em', 3336 ), 3337 ), 3338 array( 3339 'selector' => ' > .alignright', 3340 'rules' => array( 3341 'float' => 'right', 3342 'margin-inline-start' => '2em', 3343 'margin-inline-end' => '0', 3344 ), 3345 ), 3346 array( 3347 'selector' => ' > .aligncenter', 3348 'rules' => array( 3349 'margin-left' => 'auto !important', 3350 'margin-right' => 'auto !important', 3351 ), 3352 ), 3353 ), 3354 'spacingStyles' => array( 3355 array( 3356 'selector' => ' > *', 3357 'rules' => array( 3358 'margin-block-start' => '0', 3359 'margin-block-end' => '0', 3360 ), 3361 ), 3362 array( 3363 'selector' => ' > * + *', 3364 'rules' => array( 3365 'margin-block-start' => null, 3366 'margin-block-end' => '0', 3367 ), 3368 ), 3369 ), 3370 ), 3371 'flex' => array( 3372 'name' => 'flex', 3373 'slug' => 'flex', 3374 'className' => 'is-layout-flex', 3375 'displayMode' => 'flex', 3376 'baseStyles' => array( 3377 array( 3378 'selector' => '', 3379 'rules' => array( 3380 'flex-wrap' => 'wrap', 3381 'align-items' => 'center', 3382 ), 3383 ), 3384 ), 3385 'spacingStyles' => array( 3386 array( 3387 'selector' => '', 3388 'rules' => array( 3389 'gap' => null, 3390 ), 3391 ), 3392 ), 3393 ), 3394 ), 3395 ), 3396 ); 3397 } 3398 3399 /** 3400 * @ticket 56467 3401 */ 3402 function test_get_styles_for_block_with_padding_aware_alignments() { 3403 $theme_json = new WP_Theme_JSON( 3404 array( 3405 'version' => 2, 3406 'styles' => array( 3407 'spacing' => array( 3408 'padding' => array( 3409 'top' => '10px', 3410 'right' => '12px', 3411 'bottom' => '10px', 3412 'left' => '12px', 3413 ), 3414 ), 3415 ), 3416 'settings' => array( 3417 'useRootPaddingAwareAlignments' => true, 3418 ), 3419 ) 3420 ); 3421 3422 $metadata = array( 3423 'path' => array( 3424 '0' => 'styles', 3425 ), 3426 'selector' => 'body', 3427 ); 3428 3429 $expected = 'body { margin: 0; }.wp-site-blocks { padding-top: var(--wp--style--root--padding-top); padding-bottom: var(--wp--style--root--padding-bottom); }.has-global-padding { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); }.has-global-padding :where(.has-global-padding) { padding-right: 0; padding-left: 0; }.has-global-padding > .alignfull { margin-right: calc(var(--wp--style--root--padding-right) * -1); margin-left: calc(var(--wp--style--root--padding-left) * -1); }.has-global-padding :where(.has-global-padding) > .alignfull { margin-right: 0; margin-left: 0; }.has-global-padding > .alignfull:where(:not(.has-global-padding)) > :where([class*="wp-block-"]:not(.alignfull):not([class*="__"]),p,h1,h2,h3,h4,h5,h6,ul,ol) { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); }.has-global-padding :where(.has-global-padding) > .alignfull:where(:not(.has-global-padding)) > :where([class*="wp-block-"]:not(.alignfull):not([class*="__"]),p,h1,h2,h3,h4,h5,h6,ul,ol) { padding-right: 0; padding-left: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }body{--wp--style--root--padding-top: 10px;--wp--style--root--padding-right: 12px;--wp--style--root--padding-bottom: 10px;--wp--style--root--padding-left: 12px;}'; 3430 $root_rules = $theme_json->get_root_layout_rules( WP_Theme_JSON::ROOT_BLOCK_SELECTOR, $metadata ); 3431 $style_rules = $theme_json->get_styles_for_block( $metadata ); 3432 $this->assertSame( $expected, $root_rules . $style_rules ); 3433 } 3434 3435 /** 3436 * @ticket 56467 3437 */ 3438 function test_get_styles_for_block_without_padding_aware_alignments() { 3439 $theme_json = new WP_Theme_JSON( 3440 array( 3441 'version' => 2, 3442 'styles' => array( 3443 'spacing' => array( 3444 'padding' => array( 3445 'top' => '10px', 3446 'right' => '12px', 3447 'bottom' => '10px', 3448 'left' => '12px', 3449 ), 3450 ), 3451 ), 3452 ) 3453 ); 3454 3455 $metadata = array( 3456 'path' => array( 3457 '0' => 'styles', 3458 ), 3459 'selector' => 'body', 3460 ); 3461 3462 $expected = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }body{padding-top: 10px;padding-right: 12px;padding-bottom: 10px;padding-left: 12px;}'; 3463 $root_rules = $theme_json->get_root_layout_rules( WP_Theme_JSON::ROOT_BLOCK_SELECTOR, $metadata ); 3464 $style_rules = $theme_json->get_styles_for_block( $metadata ); 3465 $this->assertSame( $expected, $root_rules . $style_rules ); 3466 } 3467 3468 /** 3469 * @ticket 56467 3470 */ 3471 function test_get_styles_for_block_with_content_width() { 3472 $theme_json = new WP_Theme_JSON( 3473 array( 3474 'version' => 2, 3475 'settings' => array( 3476 'layout' => array( 3477 'contentSize' => '800px', 3478 'wideSize' => '1000px', 3479 ), 3480 ), 3481 ) 3482 ); 3483 3484 $metadata = array( 3485 'path' => array( 3486 '0' => 'settings', 3487 ), 3488 'selector' => 'body', 3489 ); 3490 3491 $expected = 'body { margin: 0;--wp--style--global--content-size: 800px;--wp--style--global--wide-size: 1000px; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }'; 3492 $root_rules = $theme_json->get_root_layout_rules( WP_Theme_JSON::ROOT_BLOCK_SELECTOR, $metadata ); 3493 $style_rules = $theme_json->get_styles_for_block( $metadata ); 3494 $this->assertSame( $expected, $root_rules . $style_rules ); 3495 } 3084 3496 }
Note: See TracChangeset
for help on using the changeset viewer.