Changeset 62478 for trunk/src/wp-includes/block-supports/layout.php
- Timestamp:
- 06/09/2026 04:25:45 AM (3 months ago)
- File:
-
- 1 edited
-
trunk/src/wp-includes/block-supports/layout.php (modified) (21 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/block-supports/layout.php
r61655 r62478 36 36 37 37 return null; 38 } 39 40 /** 41 * Returns the child-layout-only subset of a layout object. 42 * 43 * @since 7.1.0 44 * 45 * @param mixed $layout Layout object. 46 * @return array Child layout values, or an empty array. 47 */ 48 function wp_get_layout_child_values( $layout ) { 49 if ( ! is_array( $layout ) ) { 50 return array(); 51 } 52 53 return array_intersect_key( 54 $layout, 55 array_flip( array( 'selfStretch', 'flexSize', 'columnStart', 'columnSpan', 'rowStart', 'rowSpan' ) ) 56 ); 57 } 58 59 /** 60 * Returns the container-layout subset of a layout object. 61 * 62 * @since 7.1.0 63 * 64 * @param mixed $layout Layout object. 65 * @return array Container layout values, or an empty array. 66 */ 67 function wp_get_layout_container_values( $layout ) { 68 if ( ! is_array( $layout ) ) { 69 return array(); 70 } 71 72 return array_diff_key( 73 $layout, 74 array_flip( array( 'selfStretch', 'flexSize', 'columnStart', 'columnSpan', 'rowStart', 'rowSpan' ) ) 75 ); 76 } 77 78 /** 79 * Sanitizes a block gap value before layout style generation. 80 * 81 * @since 7.1.0 82 * 83 * @param string|array|null $gap_value Block gap value. 84 * @return string|array|null Sanitized block gap value. 85 */ 86 function wp_sanitize_block_gap_value( $gap_value ) { 87 if ( is_array( $gap_value ) ) { 88 foreach ( $gap_value as $key => $value ) { 89 $gap_value[ $key ] = $value && preg_match( '%[\\\(&=}]|/\*%', $value ) ? null : $value; 90 } 91 92 return $gap_value; 93 } 94 95 return $gap_value && preg_match( '%[\\\(&=}]|/\*%', $gap_value ) ? null : $gap_value; 96 } 97 98 /** 99 * Returns child layout styles for a block affected by its parent's layout. 100 * 101 * @since 7.1.0 102 * 103 * @param string $selector CSS selector. 104 * @param array $child_layout Child layout values. 105 * @param array $parent_layout Parent layout values. 106 * @param array|null $viewport_overrides Optional. Child viewport layout overrides to emit. 107 * @return array Child layout style rules. 108 */ 109 function wp_get_child_layout_style_rules( $selector, $child_layout, $parent_layout = array(), $viewport_overrides = null ) { 110 $base_child_layout = is_array( $child_layout ) ? $child_layout : array(); 111 $viewport_overrides = is_array( $viewport_overrides ) ? $viewport_overrides : null; 112 $child_layout = null === $viewport_overrides ? $base_child_layout : array_replace( $base_child_layout, $viewport_overrides ); 113 $child_layout_declarations = array(); 114 $child_layout_styles = array(); 115 $has_viewport_property_override = static function ( $property ) use ( $viewport_overrides ) { 116 return array_key_exists( $property, $viewport_overrides ); 117 }; 118 119 $self_stretch = $child_layout['selfStretch'] ?? null; 120 121 if ( null === $viewport_overrides || $has_viewport_property_override( 'selfStretch' ) || $has_viewport_property_override( 'flexSize' ) ) { 122 if ( 'fixed' === $self_stretch && isset( $child_layout['flexSize'] ) ) { 123 $child_layout_declarations['flex-basis'] = $child_layout['flexSize']; 124 $child_layout_declarations['box-sizing'] = 'border-box'; 125 } elseif ( 'fill' === $self_stretch ) { 126 $child_layout_declarations['flex-grow'] = '1'; 127 } 128 } 129 130 $column_start = $child_layout['columnStart'] ?? null; 131 $column_span = $child_layout['columnSpan'] ?? null; 132 if ( null === $viewport_overrides || $has_viewport_property_override( 'columnStart' ) || $has_viewport_property_override( 'columnSpan' ) ) { 133 if ( $column_start && $column_span ) { 134 $child_layout_declarations['grid-column'] = "$column_start / span $column_span"; 135 } elseif ( $column_start ) { 136 $child_layout_declarations['grid-column'] = "$column_start"; 137 } elseif ( $column_span ) { 138 $child_layout_declarations['grid-column'] = "span $column_span"; 139 } 140 } 141 142 $row_start = $child_layout['rowStart'] ?? null; 143 $row_span = $child_layout['rowSpan'] ?? null; 144 if ( null === $viewport_overrides || $has_viewport_property_override( 'rowStart' ) || $has_viewport_property_override( 'rowSpan' ) ) { 145 if ( $row_start && $row_span ) { 146 $child_layout_declarations['grid-row'] = "$row_start / span $row_span"; 147 } elseif ( $row_start ) { 148 $child_layout_declarations['grid-row'] = "$row_start"; 149 } elseif ( $row_span ) { 150 $child_layout_declarations['grid-row'] = "span $row_span"; 151 } 152 } 153 154 if ( ! empty( $child_layout_declarations ) ) { 155 $child_layout_styles[] = array( 156 'selector' => $selector, 157 'declarations' => $child_layout_declarations, 158 ); 159 } 160 161 $minimum_column_width = $parent_layout['minimumColumnWidth'] ?? null; 162 $column_count = $parent_layout['columnCount'] ?? null; 163 164 /* 165 * If columnSpan or columnStart is set, and the parent grid is responsive, i.e. if it has a minimumColumnWidth set, 166 * the columnSpan should be removed once the grid is smaller than the span, and columnStart should be removed 167 * once the grid has less columns than the start. 168 * If there's a minimumColumnWidth, the grid is responsive. But if the minimumColumnWidth value wasn't changed, it won't be set. 169 * In that case, if columnCount doesn't exist, we can assume that the grid is responsive. 170 */ 171 if ( null === $viewport_overrides && ( $column_span || $column_start ) && ( $minimum_column_width || ! $column_count ) ) { 172 $column_span_number = floatval( $column_span ); 173 $column_start_number = floatval( $column_start ); 174 $parent_column_width = $minimum_column_width ? $minimum_column_width : '12rem'; 175 $parent_column_value = floatval( $parent_column_width ); 176 $parent_column_unit = explode( $parent_column_value, $parent_column_width ); 177 178 $num_cols_to_break_at = 2; 179 if ( $column_span_number && $column_start_number ) { 180 $num_cols_to_break_at = $column_start_number + $column_span_number - 1; 181 } elseif ( $column_span_number ) { 182 $num_cols_to_break_at = $column_span_number; 183 } else { 184 $num_cols_to_break_at = $column_start_number; 185 } 186 187 /* 188 * If there is no unit, the width has somehow been mangled so we reset both unit and value 189 * to defaults. 190 * Additionally, the unit should be one of px, rem or em, so that also needs to be checked. 191 */ 192 if ( count( $parent_column_unit ) <= 1 ) { 193 $parent_column_unit = 'rem'; 194 $parent_column_value = 12; 195 } else { 196 $parent_column_unit = $parent_column_unit[1]; 197 198 if ( ! in_array( $parent_column_unit, array( 'px', 'rem', 'em' ), true ) ) { 199 $parent_column_unit = 'rem'; 200 } 201 } 202 203 /* 204 * A default gap value is used for this computation because custom gap values may not be 205 * viable to use in the computation of the container query value. 206 */ 207 $default_gap_value = 'px' === $parent_column_unit ? 24 : 1.5; 208 $container_query_value = $num_cols_to_break_at * $parent_column_value + ( $num_cols_to_break_at - 1 ) * $default_gap_value; 209 $minimum_container_query_value = $parent_column_value * 2 + $default_gap_value - 1; 210 $container_query_value = max( $container_query_value, $minimum_container_query_value ) . $parent_column_unit; 211 // If a span is set we want to preserve it as long as possible, otherwise we just reset the value. 212 $grid_column_value = $column_span && $column_span > 1 ? '1/-1' : 'auto'; 213 214 $child_layout_styles[] = array( 215 'rules_group' => "@container (max-width: $container_query_value )", 216 'selector' => $selector, 217 'declarations' => array( 218 'grid-column' => $grid_column_value, 219 'grid-row' => 'auto', 220 ), 221 ); 222 } 223 224 return $child_layout_styles; 38 225 } 39 226 … … 257 444 * @since 6.6.0 Removed duplicated selector from layout styles. 258 445 * Enabled negative margins for alignfull children of blocks with custom padding. 446 * @since 7.1.0 Added options array with options to process responsive styles. 259 447 * @access private 260 448 * … … 267 455 * @param string|array $fallback_gap_value Optional. The block gap value to apply. If it's an array expected properties are "top" and/or "left". Default '0.5em'. 268 456 * @param array|null $block_spacing Optional. Custom spacing set on the block. Default null. 457 * @param array $options { 458 * Optional. Extra options for internal callers. Default empty array. 459 * 460 * @type array $viewport_overrides An array of layout property overrides for the sake of style generation, 461 * keyed by property name. 462 * @type string|null $rules_group Optional group name for the rules. Default null. 463 * @type bool $has_block_gap_override Whether the block gap has been overridden. Default false. 464 * } 269 465 * @return string CSS styles on success. Else, empty string. 270 466 */ 271 function wp_get_layout_style( $selector, $layout, $has_block_gap_support = false, $gap_value = null, $should_skip_gap_serialization = false, $fallback_gap_value = '0.5em', $block_spacing = null ) { 272 $layout_type = $layout['type'] ?? 'default'; 273 $layout_styles = array(); 467 function wp_get_layout_style( $selector, $layout, $has_block_gap_support = false, $gap_value = null, $should_skip_gap_serialization = false, $fallback_gap_value = '0.5em', $block_spacing = null, $options = array() ) { 468 $base_layout = is_array( $layout ) ? $layout : array(); 469 $viewport_overrides = $options['viewport_overrides'] ?? null; 470 $layout_for_styles = null === $viewport_overrides ? $base_layout : array_replace( $base_layout, $viewport_overrides ); 471 $layout_type = $base_layout['type'] ?? 'default'; 472 $rules_group = $options['rules_group'] ?? null; 473 $has_block_gap_override = ! empty( $options['has_block_gap_override'] ); 474 $should_output_block_gap = null === $viewport_overrides || $has_block_gap_override; 475 $has_viewport_property_override = static function ( $property ) use ( $viewport_overrides ) { 476 return array_key_exists( $property, $viewport_overrides ); 477 }; 478 $layout_styles = array(); 274 479 275 480 if ( 'default' === $layout_type ) { 276 if ( $has_block_gap_support ) {481 if ( $has_block_gap_support && $should_output_block_gap ) { 277 482 if ( is_array( $gap_value ) ) { 278 483 $gap_value = $gap_value['top'] ?? null; … … 306 511 } 307 512 } elseif ( 'constrained' === $layout_type ) { 308 $content_size = $layout ['contentSize'] ?? '';309 $wide_size = $layout ['wideSize'] ?? '';310 $justify_content = $layout ['justifyContent'] ?? 'center';513 $content_size = $layout_for_styles['contentSize'] ?? ''; 514 $wide_size = $layout_for_styles['wideSize'] ?? ''; 515 $justify_content = $layout_for_styles['justifyContent'] ?? 'center'; 311 516 312 517 $all_max_width_value = $content_size ? $content_size : $wide_size; … … 320 525 $margin_right = 'right' === $justify_content ? '0 !important' : 'auto !important'; 321 526 322 if ( $content_size || $wide_size ) { 527 $has_justify_content_override = null !== $viewport_overrides && $has_viewport_property_override( 'justifyContent' ); 528 $should_output_constrained_sizes = null === $viewport_overrides || $has_viewport_property_override( 'contentSize' ) || $has_viewport_property_override( 'wideSize' ); 529 if ( $should_output_constrained_sizes && ( $content_size || $wide_size ) ) { 530 $content_size_declarations = array( 531 'max-width' => $all_max_width_value, 532 ); 533 534 if ( null === $viewport_overrides || $has_justify_content_override ) { 535 $content_size_declarations['margin-left'] = $margin_left; 536 $content_size_declarations['margin-right'] = $margin_right; 537 } 538 323 539 array_push( 324 540 $layout_styles, 325 541 array( 326 542 'selector' => "$selector > :where(:not(.alignleft):not(.alignright):not(.alignfull))", 327 'declarations' => array( 328 'max-width' => $all_max_width_value, 329 'margin-left' => $margin_left, 330 'margin-right' => $margin_right, 331 ), 543 'declarations' => $content_size_declarations, 332 544 ), 333 545 array( … … 342 554 } 343 555 344 if ( isset( $block_spacing ) ) {556 if ( null === $viewport_overrides && isset( $block_spacing ) ) { 345 557 $block_spacing_values = wp_style_engine_get_styles( 346 558 array( … … 377 589 } 378 590 379 if ( 'left' === $justify_content) {591 if ( $has_justify_content_override && ! $should_output_constrained_sizes ) { 380 592 $layout_styles[] = array( 381 593 'selector' => "$selector > :where(:not(.alignleft):not(.alignright):not(.alignfull))", 382 'declarations' => array( 'margin-left' => '0 !important' ), 594 'declarations' => array( 595 'margin-left' => $margin_left, 596 'margin-right' => $margin_right, 597 ), 383 598 ); 384 } 385 386 if ( 'right' === $justify_content ) { 387 $layout_styles[] = array( 388 'selector' => "$selector > :where(:not(.alignleft):not(.alignright):not(.alignfull))", 389 'declarations' => array( 'margin-right' => '0 !important' ), 390 ); 391 } 392 393 if ( $has_block_gap_support ) { 599 } elseif ( null === $viewport_overrides ) { 600 if ( 'left' === $justify_content ) { 601 $layout_styles[] = array( 602 'selector' => "$selector > :where(:not(.alignleft):not(.alignright):not(.alignfull))", 603 'declarations' => array( 'margin-left' => '0 !important' ), 604 ); 605 } 606 607 if ( 'right' === $justify_content ) { 608 $layout_styles[] = array( 609 'selector' => "$selector > :where(:not(.alignleft):not(.alignright):not(.alignfull))", 610 'declarations' => array( 'margin-right' => '0 !important' ), 611 ); 612 } 613 } 614 615 if ( $has_block_gap_support && $should_output_block_gap ) { 394 616 if ( is_array( $gap_value ) ) { 395 617 $gap_value = $gap_value['top'] ?? null; … … 423 645 } 424 646 } elseif ( 'flex' === $layout_type ) { 425 $layout_orientation = $layout ['orientation'] ?? 'horizontal';647 $layout_orientation = $layout_for_styles['orientation'] ?? 'horizontal'; 426 648 427 649 $justify_content_options = array( … … 445 667 } 446 668 447 if ( ! empty( $layout['flexWrap'] ) && 'nowrap' === $layout['flexWrap'] ) { 669 $should_output_flex_wrap = null === $viewport_overrides || $has_viewport_property_override( 'flexWrap' ); 670 $should_output_flex_orientation = null === $viewport_overrides || $has_viewport_property_override( 'orientation' ); 671 $should_output_flex_justification = null === $viewport_overrides || $has_viewport_property_override( 'justifyContent' ) || $has_viewport_property_override( 'orientation' ); 672 $should_output_flex_alignment = null === $viewport_overrides || $has_viewport_property_override( 'verticalAlignment' ) || $has_viewport_property_override( 'orientation' ); 673 674 if ( $should_output_flex_wrap && ! empty( $layout_for_styles['flexWrap'] ) && 'nowrap' === $layout_for_styles['flexWrap'] ) { 448 675 $layout_styles[] = array( 449 676 'selector' => $selector, … … 452 679 } 453 680 454 if ( $has_block_gap_support && isset( $gap_value ) ) {681 if ( $has_block_gap_support && $should_output_block_gap && isset( $gap_value ) ) { 455 682 $combined_gap_value = ''; 456 683 $gap_sides = is_array( $gap_value ) ? array( 'top', 'left' ) : array( 'top' ); … … 490 717 * by custom css. 491 718 */ 492 if ( ! empty( $layout['justifyContent'] ) && array_key_exists( $layout['justifyContent'], $justify_content_options ) ) {719 if ( $should_output_flex_justification && ! empty( $layout_for_styles['justifyContent'] ) && array_key_exists( $layout_for_styles['justifyContent'], $justify_content_options ) ) { 493 720 $layout_styles[] = array( 494 721 'selector' => $selector, 495 'declarations' => array( 'justify-content' => $justify_content_options[ $layout ['justifyContent'] ] ),722 'declarations' => array( 'justify-content' => $justify_content_options[ $layout_for_styles['justifyContent'] ] ), 496 723 ); 497 724 } 498 725 499 if ( ! empty( $layout['verticalAlignment'] ) && array_key_exists( $layout['verticalAlignment'], $vertical_alignment_options ) ) {726 if ( $should_output_flex_alignment && ! empty( $layout_for_styles['verticalAlignment'] ) && array_key_exists( $layout_for_styles['verticalAlignment'], $vertical_alignment_options ) ) { 500 727 $layout_styles[] = array( 501 728 'selector' => $selector, 502 'declarations' => array( 'align-items' => $vertical_alignment_options[ $layout ['verticalAlignment'] ] ),729 'declarations' => array( 'align-items' => $vertical_alignment_options[ $layout_for_styles['verticalAlignment'] ] ), 503 730 ); 504 731 } 505 732 } else { 506 $layout_styles[] = array( 507 'selector' => $selector, 508 'declarations' => array( 'flex-direction' => 'column' ), 509 ); 510 if ( ! empty( $layout['justifyContent'] ) && array_key_exists( $layout['justifyContent'], $justify_content_options ) ) { 733 if ( $should_output_flex_orientation ) { 511 734 $layout_styles[] = array( 512 735 'selector' => $selector, 513 'declarations' => array( ' align-items' => $justify_content_options[ $layout['justifyContent'] ]),736 'declarations' => array( 'flex-direction' => 'column' ), 514 737 ); 515 } else { 738 } 739 if ( $should_output_flex_justification && ! empty( $layout_for_styles['justifyContent'] ) && array_key_exists( $layout_for_styles['justifyContent'], $justify_content_options ) ) { 740 $layout_styles[] = array( 741 'selector' => $selector, 742 'declarations' => array( 'align-items' => $justify_content_options[ $layout_for_styles['justifyContent'] ] ), 743 ); 744 } elseif ( $should_output_flex_justification ) { 516 745 $layout_styles[] = array( 517 746 'selector' => $selector, … … 519 748 ); 520 749 } 521 if ( ! empty( $layout['verticalAlignment'] ) && array_key_exists( $layout['verticalAlignment'], $vertical_alignment_options ) ) {750 if ( $should_output_flex_alignment && ! empty( $layout_for_styles['verticalAlignment'] ) && array_key_exists( $layout_for_styles['verticalAlignment'], $vertical_alignment_options ) ) { 522 751 $layout_styles[] = array( 523 752 'selector' => $selector, 524 'declarations' => array( 'justify-content' => $vertical_alignment_options[ $layout ['verticalAlignment'] ] ),753 'declarations' => array( 'justify-content' => $vertical_alignment_options[ $layout_for_styles['verticalAlignment'] ] ), 525 754 ); 526 755 } … … 568 797 } 569 798 570 if ( ! empty( $layout['columnCount'] ) && ! empty( $layout['minimumColumnWidth'] ) ) { 571 $max_value = 'max(min(' . $layout['minimumColumnWidth'] . ', 100%), (100% - (' . $responsive_gap_value . ' * (' . $layout['columnCount'] . ' - 1))) /' . $layout['columnCount'] . ')'; 799 $should_output_grid_columns = null === $viewport_overrides || $has_viewport_property_override( 'minimumColumnWidth' ) || $has_viewport_property_override( 'columnCount' ); 800 $uses_gap_in_grid_columns = ! empty( $layout_for_styles['columnCount'] ) && ! empty( $layout_for_styles['minimumColumnWidth'] ); 801 if ( $has_block_gap_override && $uses_gap_in_grid_columns ) { 802 $should_output_grid_columns = true; 803 } 804 805 $should_output_grid_rows = ( null === $viewport_overrides || $has_viewport_property_override( 'rowCount' ) ) && ! empty( $layout_for_styles['columnCount'] ) && ! empty( $layout_for_styles['rowCount'] ); 806 $grid_declarations = array(); 807 808 if ( $should_output_grid_columns && ! empty( $layout_for_styles['columnCount'] ) && ! empty( $layout_for_styles['minimumColumnWidth'] ) ) { 809 $max_value = 'max(min(' . $layout_for_styles['minimumColumnWidth'] . ', 100%), (100% - (' . $responsive_gap_value . ' * (' . $layout_for_styles['columnCount'] . ' - 1))) /' . $layout_for_styles['columnCount'] . ')'; 810 $grid_declarations['grid-template-columns'] = 'repeat(auto-fill, minmax(' . $max_value . ', 1fr))'; 811 } elseif ( $should_output_grid_columns && ! empty( $layout_for_styles['columnCount'] ) ) { 812 $grid_declarations['grid-template-columns'] = 'repeat(' . $layout_for_styles['columnCount'] . ', minmax(0, 1fr))'; 813 } elseif ( $should_output_grid_columns ) { 814 $minimum_column_width = ! empty( $layout_for_styles['minimumColumnWidth'] ) ? $layout_for_styles['minimumColumnWidth'] : '12rem'; 815 $grid_declarations['grid-template-columns'] = 'repeat(auto-fill, minmax(min(' . $minimum_column_width . ', 100%), 1fr))'; 816 } 817 818 if ( ! empty( $grid_declarations ) ) { 819 $base_has_container_type = empty( $base_layout['columnCount'] ) || ( ! empty( $base_layout['columnCount'] ) && ! empty( $base_layout['minimumColumnWidth'] ) ); 820 if ( empty( $layout_for_styles['columnCount'] ) || ! empty( $layout_for_styles['minimumColumnWidth'] ) ) { 821 if ( null === $viewport_overrides || ! $base_has_container_type ) { 822 $grid_declarations['container-type'] = 'inline-size'; 823 } 824 } 572 825 $layout_styles[] = array( 573 826 'selector' => $selector, 574 'declarations' => array( 575 'grid-template-columns' => 'repeat(auto-fill, minmax(' . $max_value . ', 1fr))', 576 'container-type' => 'inline-size', 577 ), 827 'declarations' => $grid_declarations, 578 828 ); 579 if ( ! empty( $layout['rowCount'] ) ) { 580 $layout_styles[] = array( 581 'selector' => $selector, 582 'declarations' => array( 'grid-template-rows' => 'repeat(' . $layout['rowCount'] . ', minmax(1rem, auto))' ), 583 ); 584 } 585 } elseif ( ! empty( $layout['columnCount'] ) ) { 829 } 830 831 if ( $should_output_grid_rows ) { 586 832 $layout_styles[] = array( 587 833 'selector' => $selector, 588 'declarations' => array( 'grid-template- columns' => 'repeat(' . $layout['columnCount'] . ', minmax(0, 1fr))' ),834 'declarations' => array( 'grid-template-rows' => 'repeat(' . $layout_for_styles['rowCount'] . ', minmax(1rem, auto))' ), 589 835 ); 590 if ( ! empty( $layout['rowCount'] ) ) { 591 $layout_styles[] = array( 592 'selector' => $selector, 593 'declarations' => array( 'grid-template-rows' => 'repeat(' . $layout['rowCount'] . ', minmax(1rem, auto))' ), 594 ); 595 } 596 } else { 597 $minimum_column_width = ! empty( $layout['minimumColumnWidth'] ) ? $layout['minimumColumnWidth'] : '12rem'; 598 599 $layout_styles[] = array( 600 'selector' => $selector, 601 'declarations' => array( 602 'grid-template-columns' => 'repeat(auto-fill, minmax(min(' . $minimum_column_width . ', 100%), 1fr))', 603 'container-type' => 'inline-size', 604 ), 605 ); 606 } 607 608 if ( $has_block_gap_support && null !== $gap_value && ! $should_skip_gap_serialization ) { 836 } 837 838 if ( $has_block_gap_support && $should_output_block_gap && null !== $gap_value && ! $should_skip_gap_serialization ) { 609 839 $layout_styles[] = array( 610 840 'selector' => $selector, … … 615 845 616 846 if ( ! empty( $layout_styles ) ) { 847 if ( ! empty( $rules_group ) ) { 848 foreach ( $layout_styles as $index => $layout_style ) { 849 $layout_styles[ $index ]['rules_group'] = $rules_group; 850 } 851 } 852 617 853 /* 618 854 * Add to the style engine store to enqueue and render layout styles. … … 651 887 $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] ); 652 888 $block_supports_layout = block_has_support( $block_type, 'layout', false ) || block_has_support( $block_type, '__experimentalLayout', false ); 653 $child_layout = $block['attrs']['style']['layout'] ?? null; 654 655 if ( ! $block_supports_layout && ! $child_layout ) { 889 $style_attr = $block['attrs']['style'] ?? array(); 890 $child_layout = $style_attr['layout'] ?? null; 891 892 /* 893 * Collect responsive viewport child layout overrides so that a block with 894 * only responsive child layout (no base child layout) is still processed. 895 */ 896 $viewport_child_layouts = array(); 897 foreach ( WP_Theme_JSON::RESPONSIVE_BREAKPOINTS as $breakpoint => $media_query ) { 898 $viewport_child = wp_get_layout_child_values( $style_attr[ $breakpoint ]['layout'] ?? null ); 899 900 if ( ! empty( $viewport_child ) ) { 901 $viewport_child_layouts[ $breakpoint ] = array( 902 'media_query' => $media_query, 903 'child_layout' => $viewport_child, 904 ); 905 } 906 } 907 908 if ( ! $block_supports_layout && ! $child_layout && empty( $viewport_child_layouts ) ) { 656 909 return $block_content; 657 910 } … … 660 913 661 914 // Child layout specific logic. 662 if ( $child_layout ) { 915 if ( $child_layout || ! empty( $viewport_child_layouts ) ) { 916 $base_child_layout = wp_get_layout_child_values( $child_layout ); 917 $parent_layout = $block['parentLayout'] ?? array(); 663 918 /* 664 919 * Generates a unique class for child block layout styles. … … 666 921 * To ensure consistent class generation across different page renders, 667 922 * only properties that affect layout styling are used. These properties 668 * come from `$block['attrs']['style']['layout']` and `$block['parentLayout']`. 923 * come from `$block['attrs']['style']['layout']`, viewport overrides in 924 * `$block['attrs']['style'][$breakpoint]['layout']`, and `$block['parentLayout']`. 669 925 * 670 926 * As long as these properties coincide, the generated class will be the same. 671 927 */ 928 $container_content_hash_input = array( 929 'layout' => $base_child_layout, 930 'parentLayout' => array_intersect_key( 931 $parent_layout, 932 array_flip( array( 'minimumColumnWidth', 'columnCount' ) ) 933 ), 934 ); 935 936 foreach ( $viewport_child_layouts as $breakpoint => $viewport_data ) { 937 $container_content_hash_input[ $breakpoint ] = $viewport_data['child_layout']; 938 } 939 672 940 $container_content_class = wp_unique_id_from_values( 673 array( 674 'layout' => array_intersect_key( 675 $block['attrs']['style']['layout'] ?? array(), 676 array_flip( 677 array( 'selfStretch', 'flexSize', 'columnStart', 'columnSpan', 'rowStart', 'rowSpan' ) 678 ) 679 ), 680 'parentLayout' => array_intersect_key( 681 $block['parentLayout'] ?? array(), 682 array_flip( 683 array( 'minimumColumnWidth', 'columnCount' ) 684 ) 685 ), 686 ), 941 $container_content_hash_input, 687 942 'wp-container-content-' 688 943 ); 689 944 690 $child_layout_declarations = array(); 691 $child_layout_styles = array(); 692 693 $self_stretch = $child_layout['selfStretch'] ?? null; 694 695 if ( 'fixed' === $self_stretch && isset( $child_layout['flexSize'] ) ) { 696 $child_layout_declarations['flex-basis'] = $child_layout['flexSize']; 697 $child_layout_declarations['box-sizing'] = 'border-box'; 698 } elseif ( 'fill' === $self_stretch ) { 699 $child_layout_declarations['flex-grow'] = '1'; 700 } 701 702 if ( isset( $child_layout['columnSpan'] ) ) { 703 $column_span = $child_layout['columnSpan']; 704 $child_layout_declarations['grid-column'] = "span $column_span"; 705 } 706 if ( isset( $child_layout['rowSpan'] ) ) { 707 $row_span = $child_layout['rowSpan']; 708 $child_layout_declarations['grid-row'] = "span $row_span"; 709 } 710 $child_layout_styles[] = array( 711 'selector' => ".$container_content_class", 712 'declarations' => $child_layout_declarations, 713 ); 945 $child_layout_styles = wp_get_child_layout_style_rules( ".$container_content_class", $base_child_layout, $parent_layout ); 714 946 715 947 /* 716 * If columnSpan is set, and the parent grid is responsive, i.e. if it has a minimumColumnWidth set, 717 * the columnSpan should be removed on small grids. If there's a minimumColumnWidth, the grid is responsive. 718 * But if the minimumColumnWidth value wasn't changed, it won't be set. In that case, if columnCount doesn't 719 * exist, we can assume that the grid is responsive. 948 * Emit responsive child layout CSS using the same container-content class 949 * so that base and responsive child layout share the exact same selector. 720 950 */ 721 if ( isset( $child_layout['columnSpan'] ) && ( isset( $block['parentLayout']['minimumColumnWidth'] ) || ! isset( $block['parentLayout']['columnCount'] ) ) ) { 722 $column_span_number = floatval( $child_layout['columnSpan'] ); 723 $parent_column_width = $block['parentLayout']['minimumColumnWidth'] ?? '12rem'; 724 $parent_column_value = floatval( $parent_column_width ); 725 $parent_column_unit = explode( $parent_column_value, $parent_column_width ); 726 727 /* 728 * If there is no unit, the width has somehow been mangled so we reset both unit and value 729 * to defaults. 730 * Additionally, the unit should be one of px, rem or em, so that also needs to be checked. 731 */ 732 if ( count( $parent_column_unit ) <= 1 ) { 733 $parent_column_unit = 'rem'; 734 $parent_column_value = 12; 735 } else { 736 $parent_column_unit = $parent_column_unit[1]; 737 738 if ( ! in_array( $parent_column_unit, array( 'px', 'rem', 'em' ), true ) ) { 739 $parent_column_unit = 'rem'; 740 } 741 } 742 743 /* 744 * A default gap value is used for this computation because custom gap values may not be 745 * viable to use in the computation of the container query value. 746 */ 747 $default_gap_value = 'px' === $parent_column_unit ? 24 : 1.5; 748 $container_query_value = $column_span_number * $parent_column_value + ( $column_span_number - 1 ) * $default_gap_value; 749 $container_query_value = $container_query_value . $parent_column_unit; 750 751 $child_layout_styles[] = array( 752 'rules_group' => "@container (max-width: $container_query_value )", 753 'selector' => ".$container_content_class", 754 'declarations' => array( 755 'grid-column' => '1/-1', 756 ), 951 foreach ( $viewport_child_layouts as $viewport_data ) { 952 $viewport_child_styles = wp_get_child_layout_style_rules( 953 ".$container_content_class", 954 $base_child_layout, 955 $parent_layout, 956 $viewport_data['child_layout'] 757 957 ); 958 959 foreach ( $viewport_child_styles as $index => $rule ) { 960 $viewport_child_styles[ $index ]['rules_group'] = $viewport_data['media_query']; 961 } 962 963 $child_layout_styles = array_merge( $child_layout_styles, $viewport_child_styles ); 758 964 } 759 965 … … 859 1065 if ( ! current_theme_supports( 'disable-layout-styles' ) ) { 860 1066 861 $gap_value = $block['attrs']['style']['spacing']['blockGap'] ?? null; 862 /* 863 * Skip if gap value contains unsupported characters. 864 * Regex for CSS value borrowed from `safecss_filter_attr`, and used here 865 * to only match against the value, not the CSS attribute. 866 */ 867 if ( is_array( $gap_value ) ) { 868 foreach ( $gap_value as $key => $value ) { 869 $gap_value[ $key ] = $value && preg_match( '%[\\\(&=}]|/\*%', $value ) ? null : $value; 870 } 871 } else { 872 $gap_value = $gap_value && preg_match( '%[\\\(&=}]|/\*%', $gap_value ) ? null : $gap_value; 873 } 874 1067 $gap_value = wp_sanitize_block_gap_value( $style_attr['spacing']['blockGap'] ?? null ); 875 1068 $fallback_gap_value = $block_type->supports['spacing']['blockGap']['__experimentalDefault'] ?? '0.5em'; 876 $block_spacing = $ block['attrs']['style']['spacing'] ?? null;1069 $block_spacing = $style_attr['spacing'] ?? null; 877 1070 878 1071 /* … … 911 1104 } 912 1105 1106 $container_class_hash_input = array( 1107 $used_layout, 1108 $has_block_gap_support, 1109 $gap_value, 1110 $should_skip_gap_serialization, 1111 $fallback_gap_value, 1112 $block_spacing, 1113 ); 1114 1115 foreach ( array_keys( WP_Theme_JSON::RESPONSIVE_BREAKPOINTS ) as $breakpoint ) { 1116 $viewport_style = $style_attr[ $breakpoint ] ?? null; 1117 if ( ! is_array( $viewport_style ) ) { 1118 continue; 1119 } 1120 1121 $viewport_container_layout = wp_get_layout_container_values( $viewport_style['layout'] ?? null ); 1122 if ( ! empty( $viewport_container_layout ) ) { 1123 $container_class_hash_input[] = array( 1124 'breakpoint' => $breakpoint, 1125 'layout' => $viewport_container_layout, 1126 ); 1127 } 1128 1129 if ( isset( $viewport_style['spacing']['blockGap'] ) ) { 1130 $container_class_hash_input[] = array( 1131 'breakpoint' => $breakpoint, 1132 'blockGap' => wp_sanitize_block_gap_value( $viewport_style['spacing']['blockGap'] ), 1133 ); 1134 } 1135 } 1136 913 1137 /* 914 1138 * Generates a unique ID based on all the data required to obtain the … … 919 1143 */ 920 1144 $container_class = wp_unique_id_from_values( 921 array( 922 $used_layout, 923 $has_block_gap_support, 924 $gap_value, 925 $should_skip_gap_serialization, 926 $fallback_gap_value, 927 $block_spacing, 928 ), 1145 $container_class_hash_input, 929 1146 'wp-container-' . sanitize_title( $block['blockName'] ) . '-is-layout-' 930 1147 ); … … 939 1156 $block_spacing 940 1157 ); 1158 1159 /* 1160 * Emit responsive container layout styles using the same $container_class 1161 * selector as the base layout so they target the inner block wrapper. 1162 */ 1163 foreach ( WP_Theme_JSON::RESPONSIVE_BREAKPOINTS as $breakpoint => $media_query ) { 1164 $viewport_style = $style_attr[ $breakpoint ] ?? null; 1165 if ( ! is_array( $viewport_style ) ) { 1166 continue; 1167 } 1168 1169 $viewport_container_layout = wp_get_layout_container_values( $viewport_style['layout'] ?? null ); 1170 $has_viewport_layout = ! empty( $viewport_container_layout ); 1171 $has_viewport_block_gap = isset( $viewport_style['spacing']['blockGap'] ); 1172 1173 if ( ! $has_viewport_layout && ! $has_viewport_block_gap ) { 1174 continue; 1175 } 1176 1177 $viewport_gap_value = $has_viewport_block_gap 1178 ? wp_sanitize_block_gap_value( $viewport_style['spacing']['blockGap'] ) 1179 : $gap_value; 1180 1181 $viewport_block_spacing = is_array( $viewport_style['spacing'] ?? null ) 1182 ? array_replace( is_array( $block_spacing ) ? $block_spacing : array(), $viewport_style['spacing'] ) 1183 : $block_spacing; 1184 1185 $viewport_styles = wp_get_layout_style( 1186 ".$container_class", 1187 $used_layout, 1188 $has_block_gap_support, 1189 $viewport_gap_value, 1190 $should_skip_gap_serialization, 1191 $fallback_gap_value, 1192 $viewport_block_spacing, 1193 array( 1194 'rules_group' => $media_query, 1195 'viewport_overrides' => $viewport_container_layout, 1196 'has_block_gap_override' => $has_viewport_block_gap, 1197 ) 1198 ); 1199 1200 if ( ! empty( $viewport_styles ) && ! in_array( $container_class, $class_names, true ) ) { 1201 $class_names[] = $container_class; 1202 } 1203 } 941 1204 942 1205 // Only add container class and enqueue block support styles if unique styles were generated.
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)