PluginProbe
Gutenberg / 14.5.2
Gutenberg v14.5.2
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 12.6.0 All 403 releases
← All changes | lib/block-supports/layout.php +414 -82 12.6.0 → 14.5.2 View file →
@@ -10,9 +10,9 @@
10 10 *
11 11 * @param WP_Block_Type $block_type Block Type.
12 12 */
13 13 function gutenberg_register_layout_support( $block_type ) {
14 - $support_layout = gutenberg_block_has_support( $block_type, array( '__experimentalLayout' ), false );
14 + $support_layout = block_has_support( $block_type, array( '__experimentalLayout' ), false );
15 15 if ( $support_layout ) {
16 16 if ( ! $block_type->attributes ) {
17 17 $block_type->attributes = array();
18 18 }
@@ -27,23 +27,59 @@
27 27
28 28 /**
29 29 * Generates the CSS corresponding to the provided layout.
30 30 *
31 - * @param string $selector CSS selector.
32 - * @param array $layout Layout object. The one that is passed has already checked the existence of default block layout.
33 - * @param boolean $has_block_gap_support Whether the theme has support for the block gap.
34 - * @param string $gap_value The block gap value to apply.
35 - *
36 - * @return string CSS style.
31 + * @param string $selector CSS selector.
32 + * @param array $layout Layout object. The one that is passed has already checked
33 + * the existence of default block layout.
34 + * @param bool $has_block_gap_support Optional. Whether the theme has support for the block gap. Default false.
35 + * @param string|string[]|null $gap_value Optional. The block gap value to apply. Default null.
36 + * @param bool $should_skip_gap_serialization Optional. Whether to skip applying the user-defined value set in the editor. Default false.
37 + * @param string $fallback_gap_value Optional. The block gap value to apply. Default '0.5em'.
38 + * @param array|null $block_spacing Optional. Custom spacing set on the block. Default null.
39 + * @return string CSS styles on success. Else, empty string.
37 40 */
38 -function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support = false, $gap_value = null ) {
39 - $layout_type = isset( $layout['type'] ) ? $layout['type'] : 'default';
41 +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 ) {
42 + $layout_type = isset( $layout['type'] ) ? $layout['type'] : 'default';
43 + $layout_styles = array();
40 44
41 - $style = '';
42 45 if ( 'default' === $layout_type ) {
43 - $content_size = isset( $layout['contentSize'] ) ? $layout['contentSize'] : '';
44 - $wide_size = isset( $layout['wideSize'] ) ? $layout['wideSize'] : '';
46 + if ( $has_block_gap_support ) {
47 + if ( is_array( $gap_value ) ) {
48 + $gap_value = isset( $gap_value['top'] ) ? $gap_value['top'] : null;
49 + }
50 + if ( null !== $gap_value && ! $should_skip_gap_serialization ) {
51 + // Get spacing CSS variable from preset value if provided.
52 + if ( is_string( $gap_value ) && str_contains( $gap_value, 'var:preset|spacing|' ) ) {
53 + $index_to_splice = strrpos( $gap_value, '|' ) + 1;
54 + $slug = _wp_to_kebab_case( substr( $gap_value, $index_to_splice ) );
55 + $gap_value = "var(--wp--preset--spacing--$slug)";
56 + }
45 57
58 + array_push(
59 + $layout_styles,
60 + array(
61 + 'selector' => "$selector > *",
62 + 'declarations' => array(
63 + 'margin-block-start' => '0',
64 + 'margin-block-end' => '0',
65 + ),
66 + ),
67 + array(
68 + 'selector' => "$selector$selector > * + *",
69 + 'declarations' => array(
70 + 'margin-block-start' => $gap_value,
71 + 'margin-block-end' => '0',
72 + ),
73 + )
74 + );
75 + }
76 + }
77 + } elseif ( 'constrained' === $layout_type ) {
78 + $content_size = isset( $layout['contentSize'] ) ? $layout['contentSize'] : '';
79 + $wide_size = isset( $layout['wideSize'] ) ? $layout['wideSize'] : '';
80 + $justify_content = isset( $layout['justifyContent'] ) ? $layout['justifyContent'] : 'center';
81 +
46 82 $all_max_width_value = $content_size ? $content_size : $wide_size;
47 83 $wide_max_width_value = $wide_size ? $wide_size : $content_size;
48 84
49 85 // Make sure there is a single CSS rule, and all tags are stripped for security.
@@ -50,26 +86,104 @@
50 86 // TODO: Use `safecss_filter_attr` instead - once https://core.trac.wordpress.org/ticket/46197 is patched.
51 87 $all_max_width_value = wp_strip_all_tags( explode( ';', $all_max_width_value )[0] );
52 88 $wide_max_width_value = wp_strip_all_tags( explode( ';', $wide_max_width_value )[0] );
53 89
54 - $style = '';
90 + $margin_left = 'left' === $justify_content ? '0 !important' : 'auto !important';
91 + $margin_right = 'right' === $justify_content ? '0 !important' : 'auto !important';
92 +
55 93 if ( $content_size || $wide_size ) {
56 - $style = "$selector > * {";
57 - $style .= 'max-width: ' . esc_html( $all_max_width_value ) . ';';
58 - $style .= 'margin-left: auto !important;';
59 - $style .= 'margin-right: auto !important;';
60 - $style .= '}';
94 + array_push(
95 + $layout_styles,
96 + array(
97 + 'selector' => "$selector > :where(:not(.alignleft):not(.alignright):not(.alignfull))",
98 + 'declarations' => array(
99 + 'max-width' => $all_max_width_value,
100 + 'margin-left' => $margin_left,
101 + 'margin-right' => $margin_right,
102 + ),
103 + ),
104 + array(
105 + 'selector' => "$selector > .alignwide",
106 + 'declarations' => array( 'max-width' => $wide_max_width_value ),
107 + ),
108 + array(
109 + 'selector' => "$selector .alignfull",
110 + 'declarations' => array( 'max-width' => 'none' ),
111 + )
112 + );
61 113
62 - $style .= "$selector > .alignwide { max-width: " . esc_html( $wide_max_width_value ) . ';}';
63 - $style .= "$selector .alignfull { max-width: none; }";
114 + if ( isset( $block_spacing ) ) {
115 + $block_spacing_values = gutenberg_style_engine_get_styles(
116 + array(
117 + 'spacing' => $block_spacing,
118 + )
119 + );
120 +
121 + /*
122 + * Handle negative margins for alignfull children of blocks with custom padding set.
123 + * They're added separately because padding might only be set on one side.
124 + */
125 + if ( isset( $block_spacing_values['declarations']['padding-right'] ) ) {
126 + $padding_right = $block_spacing_values['declarations']['padding-right'];
127 + $layout_styles[] = array(
128 + 'selector' => "$selector > .alignfull",
129 + 'declarations' => array( 'margin-right' => "calc($padding_right * -1)" ),
130 + );
131 + }
132 + if ( isset( $block_spacing_values['declarations']['padding-left'] ) ) {
133 + $padding_left = $block_spacing_values['declarations']['padding-left'];
134 + $layout_styles[] = array(
135 + 'selector' => "$selector > .alignfull",
136 + 'declarations' => array( 'margin-left' => "calc($padding_left * -1)" ),
137 + );
138 + }
139 + }
64 140 }
65 141
66 - $style .= "$selector .alignleft { float: left; margin-right: 2em; }";
67 - $style .= "$selector .alignright { float: right; margin-left: 2em; }";
142 + if ( 'left' === $justify_content ) {
143 + $layout_styles[] = array(
144 + 'selector' => "$selector > :where(:not(.alignleft):not(.alignright):not(.alignfull))",
145 + 'declarations' => array( 'margin-left' => '0 !important' ),
146 + );
147 + }
148 +
149 + if ( 'right' === $justify_content ) {
150 + $layout_styles[] = array(
151 + 'selector' => "$selector > :where(:not(.alignleft):not(.alignright):not(.alignfull))",
152 + 'declarations' => array( 'margin-right' => '0 !important' ),
153 + );
154 + }
155 +
68 156 if ( $has_block_gap_support ) {
69 - $gap_style = $gap_value ? $gap_value : 'var( --wp--style--block-gap )';
70 - $style .= "$selector > * { margin-top: 0; margin-bottom: 0; }";
71 - $style .= "$selector > * + * { margin-top: $gap_style; margin-bottom: 0; }";
157 + if ( is_array( $gap_value ) ) {
158 + $gap_value = isset( $gap_value['top'] ) ? $gap_value['top'] : null;
159 + }
160 + if ( null !== $gap_value && ! $should_skip_gap_serialization ) {
161 + // Get spacing CSS variable from preset value if provided.
162 + if ( is_string( $gap_value ) && str_contains( $gap_value, 'var:preset|spacing|' ) ) {
163 + $index_to_splice = strrpos( $gap_value, '|' ) + 1;
164 + $slug = _wp_to_kebab_case( substr( $gap_value, $index_to_splice ) );
165 + $gap_value = "var(--wp--preset--spacing--$slug)";
166 + }
167 +
168 + array_push(
169 + $layout_styles,
170 + array(
171 + 'selector' => "$selector > *",
172 + 'declarations' => array(
173 + 'margin-block-start' => '0',
174 + 'margin-block-end' => '0',
175 + ),
176 + ),
177 + array(
178 + 'selector' => "$selector$selector > * + *",
179 + 'declarations' => array(
180 + 'margin-block-start' => $gap_value,
181 + 'margin-block-end' => '0',
182 + ),
183 + )
184 + );
185 + }
72 186 }
73 187 } elseif ( 'flex' === $layout_type ) {
74 188 $layout_orientation = isset( $layout['orientation'] ) ? $layout['orientation'] : 'horizontal';
75 189
@@ -78,53 +192,124 @@
78 192 'right' => 'flex-end',
79 193 'center' => 'center',
80 194 );
81 195
196 + $vertical_alignment_options = array(
197 + 'top' => 'flex-start',
198 + 'center' => 'center',
199 + 'bottom' => 'flex-end',
200 + );
201 +
82 202 if ( 'horizontal' === $layout_orientation ) {
83 203 $justify_content_options += array( 'space-between' => 'space-between' );
84 204 }
85 205
86 - $flex_wrap_options = array( 'wrap', 'nowrap' );
87 - $flex_wrap = ! empty( $layout['flexWrap'] ) && in_array( $layout['flexWrap'], $flex_wrap_options, true ) ?
88 - $layout['flexWrap'] :
89 - 'wrap';
206 + if ( ! empty( $layout['flexWrap'] ) && 'nowrap' === $layout['flexWrap'] ) {
207 + $layout_styles[] = array(
208 + 'selector' => $selector,
209 + 'declarations' => array( 'flex-wrap' => 'nowrap' ),
210 + );
211 + }
90 212
91 - $style = "$selector {";
92 - $style .= 'display: flex;';
93 - if ( $has_block_gap_support ) {
94 - $gap_style = $gap_value ? $gap_value : 'var( --wp--style--block-gap, 0.5em )';
95 - $style .= "gap: $gap_style;";
96 - } else {
97 - $style .= 'gap: 0.5em;';
213 + if ( $has_block_gap_support && isset( $gap_value ) ) {
214 + $combined_gap_value = '';
215 + $gap_sides = is_array( $gap_value ) ? array( 'top', 'left' ) : array( 'top' );
216 +
217 + foreach ( $gap_sides as $gap_side ) {
218 + $process_value = is_string( $gap_value ) ? $gap_value : _wp_array_get( $gap_value, array( $gap_side ), $fallback_gap_value );
219 + // Get spacing CSS variable from preset value if provided.
220 + if ( is_string( $process_value ) && str_contains( $process_value, 'var:preset|spacing|' ) ) {
221 + $index_to_splice = strrpos( $process_value, '|' ) + 1;
222 + $slug = _wp_to_kebab_case( substr( $process_value, $index_to_splice ) );
223 + $process_value = "var(--wp--preset--spacing--$slug)";
224 + }
225 + $combined_gap_value .= "$process_value ";
226 + }
227 + $gap_value = trim( $combined_gap_value );
228 +
229 + if ( null !== $gap_value && ! $should_skip_gap_serialization ) {
230 + $layout_styles[] = array(
231 + 'selector' => $selector,
232 + 'declarations' => array( 'gap' => $gap_value ),
233 + );
234 + }
98 235 }
99 - $style .= "flex-wrap: $flex_wrap;";
236 +
100 237 if ( 'horizontal' === $layout_orientation ) {
101 - $style .= 'align-items: center;';
102 - /**
238 + /*
103 239 * Add this style only if is not empty for backwards compatibility,
104 240 * since we intend to convert blocks that had flex layout implemented
105 241 * by custom css.
106 242 */
107 243 if ( ! empty( $layout['justifyContent'] ) && array_key_exists( $layout['justifyContent'], $justify_content_options ) ) {
108 - $style .= "justify-content: {$justify_content_options[ $layout['justifyContent'] ]};";
244 + $layout_styles[] = array(
245 + 'selector' => $selector,
246 + 'declarations' => array( 'justify-content' => $justify_content_options[ $layout['justifyContent'] ] ),
247 + );
109 248 }
249 +
250 + if ( ! empty( $layout['verticalAlignment'] ) && array_key_exists( $layout['verticalAlignment'], $vertical_alignment_options ) ) {
251 + $layout_styles[] = array(
252 + 'selector' => $selector,
253 + 'declarations' => array( 'align-items' => $vertical_alignment_options[ $layout['verticalAlignment'] ] ),
254 + );
255 + }
110 256 } else {
111 - $style .= 'flex-direction: column;';
257 + $layout_styles[] = array(
258 + 'selector' => $selector,
259 + 'declarations' => array( 'flex-direction' => 'column' ),
260 + );
112 261 if ( ! empty( $layout['justifyContent'] ) && array_key_exists( $layout['justifyContent'], $justify_content_options ) ) {
113 - $style .= "align-items: {$justify_content_options[ $layout['justifyContent'] ]};";
262 + $layout_styles[] = array(
263 + 'selector' => $selector,
264 + 'declarations' => array( 'align-items' => $justify_content_options[ $layout['justifyContent'] ] ),
265 + );
114 266 } else {
115 - $style .= 'align-items: flex-start;';
267 + $layout_styles[] = array(
268 + 'selector' => $selector,
269 + 'declarations' => array( 'align-items' => 'flex-start' ),
270 + );
116 271 }
117 272 }
118 - $style .= '}';
273 + }
119 274
120 - $style .= "$selector > * { margin: 0; }";
275 + if ( ! empty( $layout_styles ) ) {
276 + /*
277 + * Add to the style engine store to enqueue and render layout styles.
278 + * Return compiled layout styles to retain backwards compatibility.
279 + * Since https://github.com/WordPress/gutenberg/pull/42452,
280 + * wp_enqueue_block_support_styles is no longer called in this block supports file.
281 + */
282 + return gutenberg_style_engine_get_stylesheet_from_css_rules(
283 + $layout_styles,
284 + array(
285 + 'context' => 'block-supports',
286 + 'prettify' => false,
287 + )
288 + );
121 289 }
122 290
123 - return $style;
291 + return '';
124 292 }
125 293
126 294 /**
295 + * Gets classname from last tag in a string of HTML.
296 + *
297 + * @param string $html markup to be processed.
298 + * @return string String of inner wrapper classnames.
299 + */
300 +function gutenberg_get_classnames_from_last_tag( $html ) {
301 + $tags = new WP_HTML_Tag_Processor( $html );
302 + $last_classnames = '';
303 +
304 + while ( $tags->next_tag() ) {
305 + $last_classnames = $tags->get_attribute( 'class' );
306 + }
307 +
308 + return (string) $last_classnames;
309 +}
310 +
311 +/**
127 312 * Renders the layout config to the block wrapper.
128 313 *
129 314 * @param string $block_content Rendered block content.
130 315 * @param array $block Block object.
@@ -131,53 +316,137 @@
131 316 * @return string Filtered block content.
132 317 */
133 318 function gutenberg_render_layout_support_flag( $block_content, $block ) {
134 319 $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] );
135 - $support_layout = gutenberg_block_has_support( $block_type, array( '__experimentalLayout' ), false );
320 + $support_layout = block_has_support( $block_type, array( '__experimentalLayout' ), false );
136 321
137 322 if ( ! $support_layout ) {
138 323 return $block_content;
139 324 }
140 325
141 - $block_gap = wp_get_global_settings( array( 'spacing', 'blockGap' ) );
142 - $default_layout = wp_get_global_settings( array( 'layout' ) );
143 - $has_block_gap_support = isset( $block_gap ) ? null !== $block_gap : false;
144 - $default_block_layout = _wp_array_get( $block_type->supports, array( '__experimentalLayout', 'default' ), array() );
145 - $used_layout = isset( $block['attrs']['layout'] ) ? $block['attrs']['layout'] : $default_block_layout;
326 + $block_gap = gutenberg_get_global_settings( array( 'spacing', 'blockGap' ) );
327 + $global_layout_settings = gutenberg_get_global_settings( array( 'layout' ) );
328 + $has_block_gap_support = isset( $block_gap ) ? null !== $block_gap : false;
329 + $default_block_layout = _wp_array_get( $block_type->supports, array( '__experimentalLayout', 'default' ), array() );
330 + $used_layout = isset( $block['attrs']['layout'] ) ? $block['attrs']['layout'] : $default_block_layout;
331 +
146 332 if ( isset( $used_layout['inherit'] ) && $used_layout['inherit'] ) {
147 - if ( ! $default_layout ) {
333 + if ( ! $global_layout_settings ) {
148 334 return $block_content;
149 335 }
150 - $used_layout = $default_layout;
151 336 }
152 337
153 - $id = uniqid();
154 - $gap_value = _wp_array_get( $block, array( 'attrs', 'style', 'spacing', 'blockGap' ) );
155 - // Skip if gap value contains unsupported characters.
156 - // Regex for CSS value borrowed from `safecss_filter_attr`, and used here
157 - // because we only want to match against the value, not the CSS attribute.
158 - $gap_value = preg_match( '%[\\\(&=}]|/\*%', $gap_value ) ? null : $gap_value;
159 - $style = gutenberg_get_layout_style( ".wp-container-$id", $used_layout, $has_block_gap_support, $gap_value );
160 - // This assumes the hook only applies to blocks with a single wrapper.
161 - // I think this is a reasonable limitation for that particular hook.
162 - $content = preg_replace(
163 - '/' . preg_quote( 'class="', '/' ) . '/',
164 - 'class="wp-container-' . $id . ' ',
165 - $block_content,
166 - 1
167 - );
338 + $class_names = array();
339 + $layout_definitions = _wp_array_get( $global_layout_settings, array( 'definitions' ), array() );
340 + $container_class = wp_unique_id( 'wp-container-' );
341 + $layout_classname = '';
168 342
169 - // Ideally styles should be loaded in the head, but blocks may be parsed
170 - // after that, so loading in the footer for now.
171 - // See https://core.trac.wordpress.org/ticket/53494.
172 - add_action(
173 - 'wp_footer',
174 - function () use ( $style ) {
175 - echo '<style>' . $style . '</style>';
343 + // Set the correct layout type for blocks using legacy content width.
344 + if ( isset( $used_layout['inherit'] ) && $used_layout['inherit'] || isset( $used_layout['contentSize'] ) && $used_layout['contentSize'] ) {
345 + $used_layout['type'] = 'constrained';
346 + }
347 +
348 + if (
349 + gutenberg_get_global_settings( array( 'useRootPaddingAwareAlignments' ) ) &&
350 + isset( $used_layout['type'] ) &&
351 + 'constrained' === $used_layout['type']
352 + ) {
353 + $class_names[] = 'has-global-padding';
354 + }
355 +
356 + /*
357 + * The following section was added to reintroduce a small set of layout classnames that were
358 + * removed in the 5.9 release (https://github.com/WordPress/gutenberg/issues/38719). It is
359 + * not intended to provide an extended set of classes to match all block layout attributes
360 + * here.
361 + */
362 + if ( ! empty( $block['attrs']['layout']['orientation'] ) ) {
363 + $class_names[] = 'is-' . sanitize_title( $block['attrs']['layout']['orientation'] );
364 + }
365 +
366 + if ( ! empty( $block['attrs']['layout']['justifyContent'] ) ) {
367 + $class_names[] = 'is-content-justification-' . sanitize_title( $block['attrs']['layout']['justifyContent'] );
368 + }
369 +
370 + if ( ! empty( $block['attrs']['layout']['flexWrap'] ) && 'nowrap' === $block['attrs']['layout']['flexWrap'] ) {
371 + $class_names[] = 'is-nowrap';
372 + }
373 +
374 + // Get classname for layout type.
375 + if ( isset( $used_layout['type'] ) ) {
376 + $layout_classname = _wp_array_get( $layout_definitions, array( $used_layout['type'], 'className' ), '' );
377 + } else {
378 + $layout_classname = _wp_array_get( $layout_definitions, array( 'default', 'className' ), '' );
379 + }
380 +
381 + if ( $layout_classname && is_string( $layout_classname ) ) {
382 + $class_names[] = sanitize_title( $layout_classname );
383 + }
384 +
385 + /*
386 + * Only generate Layout styles if the theme has not opted-out.
387 + * Attribute-based Layout classnames are output in all cases.
388 + */
389 + if ( ! current_theme_supports( 'disable-layout-styles' ) ) {
390 +
391 + $gap_value = _wp_array_get( $block, array( 'attrs', 'style', 'spacing', 'blockGap' ) );
392 +
393 + /*
394 + * Skip if gap value contains unsupported characters.
395 + * Regex for CSS value borrowed from `safecss_filter_attr`, and used here
396 + * to only match against the value, not the CSS attribute.
397 + */
398 + if ( is_array( $gap_value ) ) {
399 + foreach ( $gap_value as $key => $value ) {
400 + $gap_value[ $key ] = $value && preg_match( '%[\\\(&=}]|/\*%', $value ) ? null : $value;
401 + }
402 + } else {
403 + $gap_value = $gap_value && preg_match( '%[\\\(&=}]|/\*%', $gap_value ) ? null : $gap_value;
176 404 }
177 - );
178 405
179 - return $content;
406 + $fallback_gap_value = _wp_array_get( $block_type->supports, array( 'spacing', 'blockGap', '__experimentalDefault' ), '0.5em' );
407 + $block_spacing = _wp_array_get( $block, array( 'attrs', 'style', 'spacing' ), null );
408 +
409 + /*
410 + * If a block's block.json skips serialization for spacing or spacing.blockGap,
411 + * don't apply the user-defined value to the styles.
412 + */
413 + $should_skip_gap_serialization = gutenberg_should_skip_block_supports_serialization( $block_type, 'spacing', 'blockGap' );
414 +
415 + $style = gutenberg_get_layout_style(
416 + ".$container_class.$container_class",
417 + $used_layout,
418 + $has_block_gap_support,
419 + $gap_value,
420 + $should_skip_gap_serialization,
421 + $fallback_gap_value,
422 + $block_spacing
423 + );
424 +
425 + // Only add container class and enqueue block support styles if unique styles were generated.
426 + if ( ! empty( $style ) ) {
427 + $class_names[] = $container_class;
428 + }
429 + }
430 +
431 + /**
432 + * The first chunk of innerContent contains the block markup up until the inner blocks start.
433 + * We want to target the opening tag of the inner blocks wrapper, which is the last tag in that chunk.
434 + */
435 + $inner_content_classnames = isset( $block['innerContent'][0] ) && 'string' === gettype( $block['innerContent'][0] ) ? gutenberg_get_classnames_from_last_tag( $block['innerContent'][0] ) : '';
436 +
437 + $content = new WP_HTML_Tag_Processor( $block_content );
438 + if ( $inner_content_classnames ) {
439 + $content->next_tag( array( 'class_name' => $inner_content_classnames ) );
440 + foreach ( $class_names as $class_name ) {
441 + $content->add_class( $class_name );
442 + }
443 + } else {
444 + $content->next_tag();
445 + $content->add_class( implode( ' ', $class_names ) );
446 + }
447 +
448 + return (string) $content;
180 449 }
181 450
182 451 // Register the block support. (overrides core one).
183 452 WP_Block_Supports::get_instance()->register(
@@ -185,8 +454,9 @@
185 454 array(
186 455 'register_attribute' => 'gutenberg_register_layout_support',
187 456 )
188 457 );
458 +
189 459 if ( function_exists( 'wp_render_layout_support_flag' ) ) {
190 460 remove_filter( 'render_block', 'wp_render_layout_support_flag' );
191 461 }
192 462 add_filter( 'render_block', 'gutenberg_render_layout_support_flag', 10, 2 );
@@ -206,12 +476,11 @@
206 476 '/(^\s*<%1$s\b[^>]*wp-block-group(\s|")[^>]*>)(\s*<div\b[^>]*wp-block-group__inner-container(\s|")[^>]*>)((.|\S|\s)*)/U',
207 477 preg_quote( $tag_name, '/' )
208 478 );
209 479 if (
210 - 'core/group' !== $block['blockName'] ||
211 - WP_Theme_JSON_Resolver_Gutenberg::theme_has_support() ||
480 + wp_theme_has_theme_json() ||
212 481 1 === preg_match( $group_with_inner_container_regex, $block_content ) ||
213 - ( isset( $block['attrs']['layout']['type'] ) && 'default' !== $block['attrs']['layout']['type'] )
482 + ( isset( $block['attrs']['layout']['type'] ) && 'flex' === $block['attrs']['layout']['type'] )
214 483 ) {
215 484 return $block_content;
216 485 }
217 486
@@ -230,6 +499,69 @@
230 499 }
231 500
232 501 if ( function_exists( 'wp_restore_group_inner_container' ) ) {
233 502 remove_filter( 'render_block', 'wp_restore_group_inner_container', 10, 2 );
503 + remove_filter( 'render_block_core/group', 'wp_restore_group_inner_container', 10, 2 );
234 504 }
235 -add_filter( 'render_block', 'gutenberg_restore_group_inner_container', 10, 2 );
505 +add_filter( 'render_block_core/group', 'gutenberg_restore_group_inner_container', 10, 2 );
506 +
507 +
508 +/**
509 + * For themes without theme.json file, make sure
510 + * to restore the outer div for the aligned image block
511 + * to avoid breaking styles relying on that div.
512 + *
513 + * @param string $block_content Rendered block content.
514 + * @param array $block Block object.
515 + * @return string Filtered block content.
516 + */
517 +function gutenberg_restore_image_outer_container( $block_content, $block ) {
518 + $image_with_align = "
519 +/# 1) everything up to the class attribute contents
520 +(
521 + ^\s*
522 + <figure\b
523 + [^>]*
524 + \bclass=
525 + [\"']
526 +)
527 +# 2) the class attribute contents
528 +(
529 + [^\"']*
530 + \bwp-block-image\b
531 + [^\"']*
532 + \b(?:alignleft|alignright|aligncenter)\b
533 + [^\"']*
534 +)
535 +# 3) everything after the class attribute contents
536 +(
537 + [\"']
538 + [^>]*
539 + >
540 + .*
541 + <\/figure>
542 +)/iUx";
543 +
544 + if (
545 + wp_theme_has_theme_json() ||
546 + 0 === preg_match( $image_with_align, $block_content, $matches )
547 + ) {
548 + return $block_content;
549 + }
550 +
551 + $wrapper_classnames = array( 'wp-block-image' );
552 +
553 + // If the block has a classNames attribute these classnames need to be removed from the content and added back
554 + // to the new wrapper div also.
555 + if ( ! empty( $block['attrs']['className'] ) ) {
556 + $wrapper_classnames = array_merge( $wrapper_classnames, explode( ' ', $block['attrs']['className'] ) );
557 + }
558 + $content_classnames = explode( ' ', $matches[2] );
559 + $filtered_content_classnames = array_diff( $content_classnames, $wrapper_classnames );
560 +
561 + return '<div class="' . implode( ' ', $wrapper_classnames ) . '">' . $matches[1] . implode( ' ', $filtered_content_classnames ) . $matches[3] . '</div>';
562 +}
563 +
564 +if ( function_exists( 'wp_restore_image_outer_container' ) ) {
565 + remove_filter( 'render_block_core/image', 'wp_restore_image_outer_container', 10, 2 );
566 +}
567 +add_filter( 'render_block_core/image', 'gutenberg_restore_image_outer_container', 10, 2 );