PluginProbe
Gutenberg / 24.1.0
Gutenberg v24.1.0
24.1.0 24.0.0 23.9.1 23.9.0 23.8.0 23.7.2 23.7.1 23.7.0 23.6.1 23.6.2 23.6.0 23.5.3 23.5.2 23.5.1 23.5.0 23.4.0 23.3.2 23.3.1 23.3.0 23.2.0 23.2.1 23.2.2 23.1.1 23.1.0 23.0.1 All 404 releases
← All changes | lib/block-supports/layout.php +152 -69 23.7.2 → 24.1.0 View file →
@@ -283,19 +283,39 @@
283 283 *
284 284 * Regex for CSS value borrowed from `safecss_filter_attr`, used here to only match
285 285 * against the value, not the CSS attribute.
286 286 *
287 - * @param string|array|null $gap_value Block gap value.
288 - * @return string|array|null Sanitized block gap value.
287 + * Numeric zero is converted to a string because it is valid CSS without a unit.
288 + * Other non-string values are rejected.
289 + *
290 + * @param mixed $gap_value Block gap value.
291 + * @return string|string[]|null Sanitized block gap value.
289 292 */
290 293 function gutenberg_sanitize_block_gap_value( $gap_value ) {
291 294 if ( is_array( $gap_value ) ) {
292 295 foreach ( $gap_value as $key => $value ) {
293 - $gap_value[ $key ] = ! is_scalar( $value ) || ( $value && preg_match( '%[\\\(&=}]|/\*%', (string) $value ) ) ? null : $value;
296 + $sanitized_value = gutenberg_sanitize_block_gap_value( $value );
297 + if ( ! is_string( $sanitized_value ) ) {
298 + unset( $gap_value[ $key ] );
299 + continue;
300 + }
301 + $gap_value[ $key ] = $sanitized_value;
294 302 }
295 - return $gap_value;
303 + return empty( $gap_value ) ? null : $gap_value;
296 304 }
297 305
306 + if ( ( is_int( $gap_value ) || is_float( $gap_value ) ) && 0.0 === (float) $gap_value ) {
307 + return '0';
308 + }
309 +
310 + if ( ! is_string( $gap_value ) ) {
311 + return null;
312 + }
313 +
314 + if ( '' === trim( $gap_value ) ) {
315 + return null;
316 + }
317 +
298 318 return $gap_value && preg_match( '%[\\\(&=}]|/\*%', $gap_value ) ? null : $gap_value;
299 319 }
300 320
301 321 /**
@@ -300,11 +320,11 @@
300 320
301 321 /**
302 322 * Returns child layout styles for a block affected by its parent's layout.
303 323 *
304 - * @param string $selector CSS selector.
305 - * @param array $child_layout Child layout values.
306 - * @param array $parent_layout Parent layout values.
324 + * @param string $selector CSS selector.
325 + * @param array $child_layout Child layout values.
326 + * @param array $parent_layout Parent layout values.
307 327 * @param array|null $viewport_overrides Optional. Child viewport layout overrides to emit.
308 328 * @return array Child layout style rules.
309 329 */
310 330 function gutenberg_get_child_layout_style_rules( $selector, $child_layout, $parent_layout = array(), $viewport_overrides = null ) {
@@ -359,10 +379,19 @@
359 379 $child_layout_declarations['flex-grow'] = '1';
360 380 }
361 381 }
362 382
363 - $column_start = $child_layout['columnStart'] ?? null;
364 - $column_span = $child_layout['columnSpan'] ?? null;
383 + /*
384 + * Grid line numbers and spans are whole numbers. The editor stores them as numbers, but
385 + * content saved by WordPress 6.3 to 6.6 stored them as numeric strings, and that
386 + * migration only runs when a block is parsed in JavaScript, so the front end still sees
387 + * strings. Accept any numeric value and cast it, and treat anything else as absent
388 + * because it can't render as valid CSS.
389 + */
390 + $column_start_attr = $child_layout['columnStart'] ?? null;
391 + $column_start = is_numeric( $column_start_attr ) ? (int) $column_start_attr : null;
392 + $column_span_attr = $child_layout['columnSpan'] ?? null;
393 + $column_span = is_numeric( $column_span_attr ) ? (int) $column_span_attr : null;
365 394 if ( null === $viewport_overrides || $has_viewport_property_override( 'columnStart' ) || $has_viewport_property_override( 'columnSpan' ) ) {
366 395 if ( $column_start && $column_span ) {
367 396 $child_layout_declarations['grid-column'] = "$column_start / span $column_span";
368 397 } elseif ( $column_start ) {
@@ -371,10 +400,12 @@
371 400 $child_layout_declarations['grid-column'] = "span $column_span";
372 401 }
373 402 }
374 403
375 - $row_start = $child_layout['rowStart'] ?? null;
376 - $row_span = $child_layout['rowSpan'] ?? null;
404 + $row_start_attr = $child_layout['rowStart'] ?? null;
405 + $row_start = is_numeric( $row_start_attr ) ? (int) $row_start_attr : null;
406 + $row_span_attr = $child_layout['rowSpan'] ?? null;
407 + $row_span = is_numeric( $row_span_attr ) ? (int) $row_span_attr : null;
377 408 if ( null === $viewport_overrides || $has_viewport_property_override( 'rowStart' ) || $has_viewport_property_override( 'rowSpan' ) ) {
378 409 if ( $row_start && $row_span ) {
379 410 $child_layout_declarations['grid-row'] = "$row_start / span $row_span";
380 411 } elseif ( $row_start ) {
@@ -390,10 +421,11 @@
390 421 'declarations' => $child_layout_declarations,
391 422 );
392 423 }
393 424
394 - $minimum_column_width = $parent_layout['minimumColumnWidth'] ?? null;
395 - $column_count = $parent_layout['columnCount'] ?? null;
425 + $minimum_column_width_attr = $parent_layout['minimumColumnWidth'] ?? null;
426 + $minimum_column_width = is_string( $minimum_column_width_attr ) ? $minimum_column_width_attr : null;
427 + $column_count = $parent_layout['columnCount'] ?? null;
396 428
397 429 /*
398 430 * If columnSpan or columnStart is set, and the parent grid is responsive, i.e. if it has a minimumColumnWidth set,
399 431 * the columnSpan should be removed once the grid is smaller than the span, and columnStart should be removed
@@ -459,20 +491,27 @@
459 491
460 492 /**
461 493 * Generates the CSS corresponding to the provided layout.
462 494 *
463 - * @param string $selector CSS selector.
464 - * @param array $layout Layout object. The one that is passed has already checked
465 - * the existence of default block layout.
466 - * @param bool $has_block_gap_support Optional. Whether the theme has support for the block gap. Default false.
467 - * @param string|string[]|null $gap_value Optional. The block gap value to apply. Default null.
468 - * @param bool $should_skip_gap_serialization Optional. Whether to skip applying the user-defined value set in the editor. Default false.
469 - * @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'.
470 - * @param array|null $block_spacing Optional. Custom spacing set on the block. Default null.
471 - * @param array $options Optional. Extra options for internal callers. Default empty array.
495 + * @param string $selector CSS selector.
496 + * @param array $layout Layout object. The one that is passed has already checked
497 + * the existence of default block layout.
498 + * @param bool $has_block_gap_support Optional. Whether the theme has support for the block gap. Default false.
499 + * @param string|string[]|int|float|null $gap_value Optional. The block gap value to apply. Only zero is accepted as a
500 + * numeric value. Default null.
501 + * @param bool $should_skip_gap_serialization Optional. Whether to skip applying the user-defined value set in the
502 + * editor. Default false.
503 + * @param string|string[]|int|float|null $fallback_gap_value Optional. The fallback block gap value to apply. Only zero is accepted
504 + * as a numeric value. Default '0.5em'.
505 + * @param array|null $block_spacing Optional. Custom spacing set on the block. Default null.
506 + * @param array $options Optional. Extra options for internal callers. Default empty array.
472 507 * @return string CSS styles, or empty string.
473 508 */
474 509 function gutenberg_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() ) {
510 + // Normalize here as well as at external data boundaries because this function has direct callers.
511 + $gap_value = gutenberg_sanitize_block_gap_value( $gap_value );
512 + $fallback_gap_value = gutenberg_sanitize_block_gap_value( $fallback_gap_value ) ?? '0.5em';
513 +
475 514 $base_layout = is_array( $layout ) ? $layout : array();
476 515 $viewport_overrides = $options['viewport_overrides'] ?? null;
477 516 $layout_for_styles = null === $viewport_overrides ? $base_layout : array_replace( $base_layout, $viewport_overrides );
478 517 $layout_type = $base_layout['type'] ?? 'default';
@@ -519,11 +558,16 @@
519 558 );
520 559 }
521 560 }
522 561 } elseif ( 'constrained' === $layout_type ) {
523 - $content_size = $layout_for_styles['contentSize'] ?? '';
524 - $wide_size = $layout_for_styles['wideSize'] ?? '';
525 - $justify_content = $layout_for_styles['justifyContent'] ?? 'center';
562 + // The schemas and editor UI only produce strings here, so treat a non-string
563 + // value as absent rather than casting it — it couldn't render as valid CSS anyway.
564 + $content_size_attr = $layout_for_styles['contentSize'] ?? null;
565 + $content_size = is_string( $content_size_attr ) ? $content_size_attr : '';
566 + $wide_size_attr = $layout_for_styles['wideSize'] ?? null;
567 + $wide_size = is_string( $wide_size_attr ) ? $wide_size_attr : '';
568 + $justify_content_attr = $layout_for_styles['justifyContent'] ?? null;
569 + $justify_content = is_string( $justify_content_attr ) ? $justify_content_attr : 'center';
526 570
527 571 // Check if viewport-specific ("override") values exist. Null values are valid and mean the user cleared a value inherited from the default viewport.
528 572 $has_justify_content_override = null !== $viewport_overrides && $has_viewport_property_override( 'justifyContent' );
529 573 $has_content_size_override = null !== $viewport_overrides && $has_viewport_property_override( 'contentSize' );
@@ -732,9 +776,9 @@
732 776 $combined_gap_value .= "$process_value ";
733 777 }
734 778 $gap_value = trim( $combined_gap_value );
735 779
736 - if ( null !== $gap_value && ! $should_skip_gap_serialization ) {
780 + if ( '' !== $gap_value && ! $should_skip_gap_serialization ) {
737 781 $layout_styles[] = array(
738 782 'selector' => $selector,
739 783 'declarations' => array( 'gap' => $gap_value ),
740 784 );
@@ -740,25 +784,39 @@
740 784 );
741 785 }
742 786 }
743 787
788 + $flex_justify_content = $layout_for_styles['justifyContent'] ?? null;
789 + $flex_vertical_alignment = $layout_for_styles['verticalAlignment'] ?? null;
790 +
744 791 if ( 'horizontal' === $layout_orientation ) {
745 792 /*
793 + * `row` is the flex default, so the base layout never declares it. A viewport
794 + * override that switches a vertical base layout to horizontal has to declare
795 + * it explicitly, otherwise the base `flex-direction: column` keeps applying.
796 + */
797 + if ( null !== $viewport_overrides && $has_viewport_property_override( 'orientation' ) ) {
798 + $layout_styles[] = array(
799 + 'selector' => $selector,
800 + 'declarations' => array( 'flex-direction' => 'row' ),
801 + );
802 + }
803 + /*
746 804 * Add this style only if is not empty for backwards compatibility,
747 805 * since we intend to convert blocks that had flex layout implemented
748 806 * by custom css.
749 807 */
750 - if ( $should_output_flex_justification && ! empty( $layout_for_styles['justifyContent'] ) && array_key_exists( $layout_for_styles['justifyContent'], $justify_content_options ) ) {
808 + if ( $should_output_flex_justification && ! empty( $flex_justify_content ) && is_string( $flex_justify_content ) && array_key_exists( $flex_justify_content, $justify_content_options ) ) {
751 809 $layout_styles[] = array(
752 810 'selector' => $selector,
753 - 'declarations' => array( 'justify-content' => $justify_content_options[ $layout_for_styles['justifyContent'] ] ),
811 + 'declarations' => array( 'justify-content' => $justify_content_options[ $flex_justify_content ] ),
754 812 );
755 813 }
756 814
757 - if ( $should_output_flex_alignment && ! empty( $layout_for_styles['verticalAlignment'] ) && array_key_exists( $layout_for_styles['verticalAlignment'], $vertical_alignment_options ) ) {
815 + if ( $should_output_flex_alignment && ! empty( $flex_vertical_alignment ) && is_string( $flex_vertical_alignment ) && array_key_exists( $flex_vertical_alignment, $vertical_alignment_options ) ) {
758 816 $layout_styles[] = array(
759 817 'selector' => $selector,
760 - 'declarations' => array( 'align-items' => $vertical_alignment_options[ $layout_for_styles['verticalAlignment'] ] ),
818 + 'declarations' => array( 'align-items' => $vertical_alignment_options[ $flex_vertical_alignment ] ),
761 819 );
762 820 }
763 821 } else {
764 822 if ( $should_output_flex_orientation ) {
@@ -766,12 +824,12 @@
766 824 'selector' => $selector,
767 825 'declarations' => array( 'flex-direction' => 'column' ),
768 826 );
769 827 }
770 - if ( $should_output_flex_justification && ! empty( $layout_for_styles['justifyContent'] ) && array_key_exists( $layout_for_styles['justifyContent'], $justify_content_options ) ) {
828 + if ( $should_output_flex_justification && ! empty( $flex_justify_content ) && is_string( $flex_justify_content ) && array_key_exists( $flex_justify_content, $justify_content_options ) ) {
771 829 $layout_styles[] = array(
772 830 'selector' => $selector,
773 - 'declarations' => array( 'align-items' => $justify_content_options[ $layout_for_styles['justifyContent'] ] ),
831 + 'declarations' => array( 'align-items' => $justify_content_options[ $flex_justify_content ] ),
774 832 );
775 833 } elseif ( $should_output_flex_justification ) {
776 834 $layout_styles[] = array(
777 835 'selector' => $selector,
@@ -777,18 +835,27 @@
777 835 'selector' => $selector,
778 836 'declarations' => array( 'align-items' => 'flex-start' ),
779 837 );
780 838 }
781 - if ( $should_output_flex_alignment && ! empty( $layout_for_styles['verticalAlignment'] ) && array_key_exists( $layout_for_styles['verticalAlignment'], $vertical_alignment_options ) ) {
839 + if ( $should_output_flex_alignment && ! empty( $flex_vertical_alignment ) && is_string( $flex_vertical_alignment ) && array_key_exists( $flex_vertical_alignment, $vertical_alignment_options ) ) {
782 840 $layout_styles[] = array(
783 841 'selector' => $selector,
784 - 'declarations' => array( 'justify-content' => $vertical_alignment_options[ $layout_for_styles['verticalAlignment'] ] ),
842 + 'declarations' => array( 'justify-content' => $vertical_alignment_options[ $flex_vertical_alignment ] ),
785 843 );
786 844 }
787 845 }
788 846 } elseif ( 'grid' === $layout_type ) {
789 847 /*
790 - * If the gap value is an array, we use the "left" value because it represents the vertical gap, which
848 + * Column and row counts are whole numbers, for the same reason as the grid line
849 + * numbers in gutenberg_get_child_layout_style_rules().
850 + */
851 + $column_count_attr = $layout_for_styles['columnCount'] ?? null;
852 + $column_count = is_numeric( $column_count_attr ) ? (int) $column_count_attr : null;
853 + $row_count_attr = $layout_for_styles['rowCount'] ?? null;
854 + $row_count = is_numeric( $row_count_attr ) ? (int) $row_count_attr : null;
855 +
856 + /*
857 + * If the gap value is an array, we use the "left" value because it represents the horizontal gap, which
791 858 * is the relevant one for computation of responsive grid columns.
792 859 */
793 860 if ( is_array( $fallback_gap_value ) ) {
794 861 $responsive_gap_value = $fallback_gap_value['left'] ?? reset( $fallback_gap_value );
@@ -815,12 +882,14 @@
815 882 $index_to_splice = strrpos( $process_value, '|' ) + 1;
816 883 $slug = _wp_to_kebab_case( substr( $process_value, $index_to_splice ) );
817 884 $process_value = "var(--wp--preset--spacing--$slug)";
818 885 }
886 + if ( ! is_array( $gap_value ) || 'left' === $gap_side ) {
887 + $responsive_gap_value = $process_value;
888 + }
819 889 $combined_gap_value .= "$process_value ";
820 890 }
821 - $gap_value = trim( $combined_gap_value );
822 - $responsive_gap_value = $gap_value;
891 + $gap_value = trim( $combined_gap_value );
823 892 }
824 893
825 894 // Ensure 0 values have a unit so they work in calc().
826 895 if ( '0' === $responsive_gap_value || 0 === $responsive_gap_value ) {
@@ -830,14 +899,14 @@
830 899 /* Styles should be output either if there are no viewport overrides (this is the default case), or if the user has set a new viewport-specific
831 900 * value for any of the grid properties.
832 901 */
833 902 $should_output_grid_columns = null === $viewport_overrides || $has_viewport_property_override( 'minimumColumnWidth' ) || $has_viewport_property_override( 'columnCount' ) || $has_viewport_property_override( 'autoFit' );
834 - $uses_gap_in_grid_columns = ! empty( $layout_for_styles['columnCount'] ) && ! empty( $layout_for_styles['minimumColumnWidth'] );
903 + $uses_gap_in_grid_columns = ! empty( $column_count ) && ! empty( $layout_for_styles['minimumColumnWidth'] );
835 904 if ( $has_block_gap_override && $uses_gap_in_grid_columns ) {
836 905 $should_output_grid_columns = true;
837 906 }
838 907
839 - $should_output_grid_rows = ( null === $viewport_overrides || $has_viewport_property_override( 'rowCount' ) ) && ! empty( $layout_for_styles['columnCount'] ) && ! empty( $layout_for_styles['rowCount'] );
908 + $should_output_grid_rows = ( null === $viewport_overrides || $has_viewport_property_override( 'rowCount' ) ) && ! empty( $column_count ) && ! empty( $row_count );
840 909 $grid_declarations = array();
841 910
842 911 /* When enabled, columns stretch to fill the available space using
843 912 * `auto-fit`; otherwise empty tracks are preserved with `auto-fill`.
@@ -843,13 +912,13 @@
843 912 * `auto-fit`; otherwise empty tracks are preserved with `auto-fill`.
844 913 */
845 914 $auto_placement = ! empty( $layout_for_styles['autoFit'] ) ? 'auto-fit' : 'auto-fill';
846 915
847 - if ( $should_output_grid_columns && ! empty( $layout_for_styles['columnCount'] ) && ! empty( $layout_for_styles['minimumColumnWidth'] ) ) {
848 - $max_value = 'max(min(' . $layout_for_styles['minimumColumnWidth'] . ', 100%), (100% - (' . $responsive_gap_value . ' * (' . $layout_for_styles['columnCount'] . ' - 1))) /' . $layout_for_styles['columnCount'] . ')';
916 + if ( $should_output_grid_columns && ! empty( $column_count ) && ! empty( $layout_for_styles['minimumColumnWidth'] ) ) {
917 + $max_value = 'max(min(' . $layout_for_styles['minimumColumnWidth'] . ', 100%), (100% - (' . $responsive_gap_value . ' * (' . $column_count . ' - 1))) /' . $column_count . ')';
849 918 $grid_declarations['grid-template-columns'] = 'repeat(' . $auto_placement . ', minmax(' . $max_value . ', 1fr))';
850 - } elseif ( $should_output_grid_columns && ! empty( $layout_for_styles['columnCount'] ) ) {
851 - $grid_declarations['grid-template-columns'] = 'repeat(' . $layout_for_styles['columnCount'] . ', minmax(0, 1fr))';
919 + } elseif ( $should_output_grid_columns && ! empty( $column_count ) ) {
920 + $grid_declarations['grid-template-columns'] = 'repeat(' . $column_count . ', minmax(0, 1fr))';
852 921 } elseif ( $should_output_grid_columns ) {
853 922 $minimum_column_width = ! empty( $layout_for_styles['minimumColumnWidth'] ) ? $layout_for_styles['minimumColumnWidth'] : '12rem';
854 923 $grid_declarations['grid-template-columns'] = 'repeat(' . $auto_placement . ', minmax(min(' . $minimum_column_width . ', 100%), 1fr))';
855 924 }
@@ -855,9 +924,9 @@
855 924 }
856 925
857 926 if ( ! empty( $grid_declarations ) ) {
858 927 $base_has_container_type = empty( $base_layout['columnCount'] ) || ( ! empty( $base_layout['columnCount'] ) && ! empty( $base_layout['minimumColumnWidth'] ) );
859 - if ( empty( $layout_for_styles['columnCount'] ) || ! empty( $layout_for_styles['minimumColumnWidth'] ) ) {
928 + if ( empty( $column_count ) || ! empty( $layout_for_styles['minimumColumnWidth'] ) ) {
860 929 if ( null === $viewport_overrides || ! $base_has_container_type ) {
861 930 $grid_declarations['container-type'] = 'inline-size';
862 931 }
863 932 }
@@ -869,9 +938,9 @@
869 938
870 939 if ( $should_output_grid_rows ) {
871 940 $layout_styles[] = array(
872 941 'selector' => $selector,
873 - 'declarations' => array( 'grid-template-rows' => 'repeat(' . $layout_for_styles['rowCount'] . ', minmax(1rem, auto))' ),
942 + 'declarations' => array( 'grid-template-rows' => 'repeat(' . $row_count . ', minmax(1rem, auto))' ),
874 943 );
875 944 }
876 945
877 946 if ( $has_block_gap_support && $should_output_block_gap && null !== $gap_value && ! $should_skip_gap_serialization ) {
@@ -915,10 +984,10 @@
915 984 * and increments on each call. The returned value is not universally unique,
916 985 * but it is unique across the life of the PHP process and it's stable per
917 986 * prefix.
918 987 *
919 - * @param string $prefix Prefix for the returned ID.
920 - * @return string Incremental ID per prefix.
988 + * @param string $prefix Prefix for the returned ID.
989 + * @return string Incremental ID per prefix.
921 990 */
922 991 function gutenberg_incremental_id_per_prefix( $prefix = '' ) {
923 992 static $id_counters = array();
924 993 if ( ! array_key_exists( $prefix, $id_counters ) ) {
@@ -947,15 +1016,13 @@
947 1016
948 1017 /**
949 1018 * Renders the layout config to the block wrapper.
950 1019 *
951 - * @param string $block_content Rendered block content.
952 - * @param array $block Block object.
953 - * @return string Filtered block content.
1020 + * @param string $block_content Rendered block content.
1021 + * @param array $block Block object.
1022 + * @return string Filtered block content.
954 1023 */
955 1024 function gutenberg_render_layout_support_flag( $block_content, $block ) {
956 - static $global_styles = null;
957 -
958 1025 $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] );
959 1026 $block_supports_layout = block_has_support( $block_type, array( 'layout' ), false ) || block_has_support( $block_type, array( '__experimentalLayout' ), false );
960 1027 $style_attr = gutenberg_resolve_style_state_aliases(
961 1028 $block['attrs']['style'] ?? array(),
@@ -1120,22 +1187,25 @@
1120 1187 * removed in the 5.9 release (https://github.com/WordPress/gutenberg/issues/38719). It is
1121 1188 * not intended to provide an extended set of classes to match all block layout attributes
1122 1189 * here.
1123 1190 */
1124 - if ( ! empty( $block['attrs']['layout']['orientation'] ) ) {
1125 - $class_names[] = 'is-' . sanitize_title( $block['attrs']['layout']['orientation'] );
1191 + $orientation = $block['attrs']['layout']['orientation'] ?? null;
1192 + if ( ! empty( $orientation ) && is_string( $orientation ) ) {
1193 + $class_names[] = 'is-' . sanitize_title( $orientation );
1126 1194 }
1127 1195
1128 - if ( ! empty( $block['attrs']['layout']['justifyContent'] ) ) {
1129 - $class_names[] = 'is-content-justification-' . sanitize_title( $block['attrs']['layout']['justifyContent'] );
1196 + $justify_content = $block['attrs']['layout']['justifyContent'] ?? null;
1197 + if ( ! empty( $justify_content ) && is_string( $justify_content ) ) {
1198 + $class_names[] = 'is-content-justification-' . sanitize_title( $justify_content );
1130 1199 }
1131 1200
1132 - if ( ! empty( $block['attrs']['layout']['flexWrap'] ) && 'nowrap' === $block['attrs']['layout']['flexWrap'] ) {
1201 + $flex_wrap = $block['attrs']['layout']['flexWrap'] ?? null;
1202 + if ( ! empty( $flex_wrap ) && 'nowrap' === $flex_wrap ) {
1133 1203 $class_names[] = 'is-nowrap';
1134 1204 }
1135 1205
1136 1206 // Get classname for layout type.
1137 - if ( isset( $used_layout['type'] ) ) {
1207 + if ( isset( $used_layout['type'] ) && is_string( $used_layout['type'] ) ) {
1138 1208 $layout_classname = $layout_definitions[ $used_layout['type'] ]['className'] ?? '';
1139 1209 } else {
1140 1210 $layout_classname = $layout_definitions['default']['className'] ?? '';
1141 1211 }
@@ -1151,9 +1221,11 @@
1151 1221 if ( ! current_theme_supports( 'disable-layout-styles' ) ) {
1152 1222
1153 1223 $gap_value = gutenberg_sanitize_block_gap_value( $block['attrs']['style']['spacing']['blockGap'] ?? null );
1154 1224
1155 - $fallback_gap_value = $block_type->supports['spacing']['blockGap']['__experimentalDefault'] ?? '0.5em';
1225 + $fallback_gap_value = gutenberg_sanitize_block_gap_value(
1226 + $block_type->supports['spacing']['blockGap']['__experimentalDefault'] ?? null
1227 + ) ?? '0.5em';
1156 1228 $block_spacing = $block['attrs']['style']['spacing'] ?? null;
1157 1229
1158 1230 /*
1159 1231 * If a block's block.json skips serialization for spacing or spacing.blockGap,
@@ -1165,12 +1237,10 @@
1165 1237 $has_block_gap_support = isset( $block_gap );
1166 1238
1167 1239 // Get default blockGap value from global styles for use in layouts like grid.
1168 1240 // Check style variation first, then block-specific styles, then fall back to root styles.
1169 - $block_name = $block['blockName'] ?? '';
1170 - if ( null === $global_styles ) {
1171 - $global_styles = gutenberg_get_global_styles();
1172 - }
1241 + $block_name = $block['blockName'] ?? '';
1242 + $global_styles = gutenberg_get_global_styles();
1173 1243
1174 1244 // Check if the block has an active style variation with a blockGap value.
1175 1245 // Only check the registry if the className contains a variation class to avoid unnecessary lookups.
1176 1246 $variation_block_gap_value = null;
@@ -1185,9 +1255,21 @@
1185 1255 $variation_block_gap_value = $global_styles['blocks'][ $block_name ]['variations'][ $variation_name ]['spacing']['blockGap'] ?? null;
1186 1256 }
1187 1257 }
1188 1258
1189 - $global_block_gap_value = $variation_block_gap_value ?? $global_styles['blocks'][ $block_name ]['spacing']['blockGap'] ?? $global_styles['spacing']['blockGap'] ?? null;
1259 + $global_block_gap_candidates = array(
1260 + $variation_block_gap_value,
1261 + $global_styles['blocks'][ $block_name ]['spacing']['blockGap'] ?? null,
1262 + $global_styles['spacing']['blockGap'] ?? null,
1263 + );
1264 + $global_block_gap_value = null;
1265 + foreach ( $global_block_gap_candidates as $candidate_gap_value ) {
1266 + $candidate_gap_value = gutenberg_sanitize_block_gap_value( $candidate_gap_value );
1267 + if ( null !== $candidate_gap_value ) {
1268 + $global_block_gap_value = $candidate_gap_value;
1269 + break;
1270 + }
1271 + }
1190 1272
1191 1273 if ( null !== $global_block_gap_value ) {
1192 1274 $fallback_gap_value = $global_block_gap_value;
1193 1275 }
@@ -1453,14 +1535,15 @@
1453 1535 * For themes without theme.json file, make sure
1454 1536 * to restore the inner div for the group block
1455 1537 * to avoid breaking styles relying on that div.
1456 1538 *
1457 - * @param string $block_content Rendered block content.
1458 - * @param array $block Block object.
1459 - * @return string Filtered block content.
1539 + * @param string $block_content Rendered block content.
1540 + * @param array $block Block object.
1541 + * @return string Filtered block content.
1460 1542 */
1461 1543 function gutenberg_restore_group_inner_container( $block_content, $block ) {
1462 - $tag_name = $block['attrs']['tagName'] ?? 'div';
1544 + $tag_name_attr = $block['attrs']['tagName'] ?? null;
1545 + $tag_name = is_string( $tag_name_attr ) ? $tag_name_attr : 'div';
1463 1546 $group_with_inner_container_regex = sprintf(
1464 1547 '/(^\s*<%1$s\b[^>]*wp-block-group(\s|")[^>]*>)(\s*<div\b[^>]*wp-block-group__inner-container(\s|")[^>]*>)((.|\S|\s)*)/U',
1465 1548 preg_quote( $tag_name, '/' )
1466 1549 );
@@ -1526,9 +1609,9 @@
1526 1609 * to restore the outer div for the aligned image block
1527 1610 * to avoid breaking styles relying on that div.
1528 1611 *
1529 1612 * @param string $block_content Rendered block content.
1530 - * @param array $block Block object.
1613 + * @param array $block Block object.
1531 1614 * @return string Filtered block content.
1532 1615 */
1533 1616 function gutenberg_restore_image_outer_container( $block_content, $block ) {
1534 1617 if ( wp_theme_has_theme_json() ) {