PluginProbe
Gutenberg / 15.2.3
Gutenberg v15.2.3
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 7.4.0 All 402 releases
gutenberg / lib / block-supports / layout.php

layout.php in Gutenberg 15.2.3, at lib/block-supports/layout.php

641 lines 22.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Layout block support flag.
4 *
5 * @package gutenberg
6 */
7
8 /**
9 * Registers the layout block attribute for block types that support it.
10 *
11 * @param WP_Block_Type $block_type Block Type.
12 */
13 function gutenberg_register_layout_support( $block_type ) {
14 $support_layout = block_has_support( $block_type, array( '__experimentalLayout' ), false );
15 if ( $support_layout ) {
16 if ( ! $block_type->attributes ) {
17 $block_type->attributes = array();
18 }
19
20 if ( ! array_key_exists( 'layout', $block_type->attributes ) ) {
21 $block_type->attributes['layout'] = array(
22 'type' => 'object',
23 );
24 }
25 }
26 }
27
28 /**
29 * Generates the CSS corresponding to the provided layout.
30 *
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.
40 */
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();
44
45 if ( 'default' === $layout_type ) {
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 }
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
82 $all_max_width_value = $content_size ? $content_size : $wide_size;
83 $wide_max_width_value = $wide_size ? $wide_size : $content_size;
84
85 // Make sure there is a single CSS rule, and all tags are stripped for security.
86 // TODO: Use `safecss_filter_attr` instead when the minimum required WP version is >= 6.1.
87 $all_max_width_value = wp_strip_all_tags( explode( ';', $all_max_width_value )[0] );
88 $wide_max_width_value = wp_strip_all_tags( explode( ';', $wide_max_width_value )[0] );
89
90 $margin_left = 'left' === $justify_content ? '0 !important' : 'auto !important';
91 $margin_right = 'right' === $justify_content ? '0 !important' : 'auto !important';
92
93 if ( $content_size || $wide_size ) {
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 );
113
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 }
140 }
141
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
156 if ( $has_block_gap_support ) {
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 }
186 }
187 } elseif ( 'flex' === $layout_type ) {
188 $layout_orientation = isset( $layout['orientation'] ) ? $layout['orientation'] : 'horizontal';
189
190 $justify_content_options = array(
191 'left' => 'flex-start',
192 'right' => 'flex-end',
193 'center' => 'center',
194 );
195
196 $vertical_alignment_options = array(
197 'top' => 'flex-start',
198 'center' => 'center',
199 'bottom' => 'flex-end',
200 );
201
202 if ( 'horizontal' === $layout_orientation ) {
203 $justify_content_options += array( 'space-between' => 'space-between' );
204 $vertical_alignment_options += array( 'stretch' => 'stretch' );
205 } else {
206 $justify_content_options += array( 'stretch' => 'stretch' );
207 $vertical_alignment_options += array( 'space-between' => 'space-between' );
208 }
209
210 if ( ! empty( $layout['flexWrap'] ) && 'nowrap' === $layout['flexWrap'] ) {
211 $layout_styles[] = array(
212 'selector' => $selector,
213 'declarations' => array( 'flex-wrap' => 'nowrap' ),
214 );
215 }
216
217 if ( $has_block_gap_support && isset( $gap_value ) ) {
218 $combined_gap_value = '';
219 $gap_sides = is_array( $gap_value ) ? array( 'top', 'left' ) : array( 'top' );
220
221 foreach ( $gap_sides as $gap_side ) {
222 $process_value = is_string( $gap_value ) ? $gap_value : _wp_array_get( $gap_value, array( $gap_side ), $fallback_gap_value );
223 // Get spacing CSS variable from preset value if provided.
224 if ( is_string( $process_value ) && str_contains( $process_value, 'var:preset|spacing|' ) ) {
225 $index_to_splice = strrpos( $process_value, '|' ) + 1;
226 $slug = _wp_to_kebab_case( substr( $process_value, $index_to_splice ) );
227 $process_value = "var(--wp--preset--spacing--$slug)";
228 }
229 $combined_gap_value .= "$process_value ";
230 }
231 $gap_value = trim( $combined_gap_value );
232
233 if ( null !== $gap_value && ! $should_skip_gap_serialization ) {
234 $layout_styles[] = array(
235 'selector' => $selector,
236 'declarations' => array( 'gap' => $gap_value ),
237 );
238 }
239 }
240
241 if ( 'horizontal' === $layout_orientation ) {
242 /*
243 * Add this style only if is not empty for backwards compatibility,
244 * since we intend to convert blocks that had flex layout implemented
245 * by custom css.
246 */
247 if ( ! empty( $layout['justifyContent'] ) && array_key_exists( $layout['justifyContent'], $justify_content_options ) ) {
248 $layout_styles[] = array(
249 'selector' => $selector,
250 'declarations' => array( 'justify-content' => $justify_content_options[ $layout['justifyContent'] ] ),
251 );
252 }
253
254 if ( ! empty( $layout['verticalAlignment'] ) && array_key_exists( $layout['verticalAlignment'], $vertical_alignment_options ) ) {
255 $layout_styles[] = array(
256 'selector' => $selector,
257 'declarations' => array( 'align-items' => $vertical_alignment_options[ $layout['verticalAlignment'] ] ),
258 );
259 }
260 } else {
261 $layout_styles[] = array(
262 'selector' => $selector,
263 'declarations' => array( 'flex-direction' => 'column' ),
264 );
265 if ( ! empty( $layout['justifyContent'] ) && array_key_exists( $layout['justifyContent'], $justify_content_options ) ) {
266 $layout_styles[] = array(
267 'selector' => $selector,
268 'declarations' => array( 'align-items' => $justify_content_options[ $layout['justifyContent'] ] ),
269 );
270 } else {
271 $layout_styles[] = array(
272 'selector' => $selector,
273 'declarations' => array( 'align-items' => 'flex-start' ),
274 );
275 }
276 if ( ! empty( $layout['verticalAlignment'] ) && array_key_exists( $layout['verticalAlignment'], $vertical_alignment_options ) ) {
277 $layout_styles[] = array(
278 'selector' => $selector,
279 'declarations' => array( 'justify-content' => $vertical_alignment_options[ $layout['verticalAlignment'] ] ),
280 );
281 }
282 }
283 }
284
285 if ( ! empty( $layout_styles ) ) {
286 /*
287 * Add to the style engine store to enqueue and render layout styles.
288 * Return compiled layout styles to retain backwards compatibility.
289 * Since https://github.com/WordPress/gutenberg/pull/42452,
290 * wp_enqueue_block_support_styles is no longer called in this block supports file.
291 */
292 return gutenberg_style_engine_get_stylesheet_from_css_rules(
293 $layout_styles,
294 array(
295 'context' => 'block-supports',
296 'prettify' => false,
297 )
298 );
299 }
300
301 return '';
302 }
303
304 /**
305 * Gets classname from last tag in a string of HTML.
306 *
307 * @param string $html markup to be processed.
308 * @return string String of inner wrapper classnames.
309 */
310 function gutenberg_get_classnames_from_last_tag( $html ) {
311 $tags = new WP_HTML_Tag_Processor( $html );
312 $last_classnames = '';
313
314 while ( $tags->next_tag() ) {
315 $last_classnames = $tags->get_attribute( 'class' );
316 }
317
318 return (string) $last_classnames;
319 }
320
321 /**
322 * Renders the layout config to the block wrapper.
323 *
324 * @param string $block_content Rendered block content.
325 * @param array $block Block object.
326 * @return string Filtered block content.
327 */
328 function gutenberg_render_layout_support_flag( $block_content, $block ) {
329 $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] );
330 $support_layout = block_has_support( $block_type, array( '__experimentalLayout' ), false );
331 $has_child_layout = isset( $block['attrs']['style']['layout']['selfStretch'] );
332
333 if ( ! $support_layout
334 && ! $has_child_layout ) {
335 return $block_content;
336 }
337
338 $outer_class_names = array();
339
340 if ( $has_child_layout && ( 'fixed' === $block['attrs']['style']['layout']['selfStretch'] || 'fill' === $block['attrs']['style']['layout']['selfStretch'] ) ) {
341
342 $container_content_class = wp_unique_id( 'wp-container-content-' );
343
344 $child_layout_styles = array();
345
346 if ( 'fixed' === $block['attrs']['style']['layout']['selfStretch'] && isset( $block['attrs']['style']['layout']['flexSize'] ) ) {
347 $child_layout_styles[] = array(
348 'selector' => ".$container_content_class",
349 'declarations' => array(
350 'flex-basis' => $block['attrs']['style']['layout']['flexSize'],
351 'box-sizing' => 'border-box',
352 ),
353 );
354 } elseif ( 'fill' === $block['attrs']['style']['layout']['selfStretch'] ) {
355 $child_layout_styles[] = array(
356 'selector' => ".$container_content_class",
357 'declarations' => array(
358 'flex-grow' => '1',
359 ),
360 );
361 }
362
363 gutenberg_style_engine_get_stylesheet_from_css_rules(
364 $child_layout_styles,
365 array(
366 'context' => 'block-supports',
367 'prettify' => false,
368 )
369 );
370
371 $outer_class_names[] = $container_content_class;
372
373 }
374
375 // Return early if only child layout exists.
376 if ( ! $support_layout && ! empty( $outer_class_names ) ) {
377 $content = new WP_HTML_Tag_Processor( $block_content );
378 $content->next_tag();
379 $content->add_class( implode( ' ', $outer_class_names ) );
380 return (string) $content;
381 }
382
383 $global_settings = gutenberg_get_global_settings();
384 $global_layout_settings = _wp_array_get( $global_settings, array( 'layout' ), null );
385 $used_layout = isset( $block['attrs']['layout'] ) ? $block['attrs']['layout'] : _wp_array_get( $block_type->supports, array( '__experimentalLayout', 'default' ), array() );
386
387 if ( isset( $used_layout['inherit'] ) && $used_layout['inherit'] && ! $global_layout_settings ) {
388 return $block_content;
389 }
390
391 $class_names = array();
392 $layout_definitions = _wp_array_get( $global_layout_settings, array( 'definitions' ), array() );
393 $container_class = wp_unique_id( 'wp-container-' );
394 $layout_classname = '';
395
396 // Set the correct layout type for blocks using legacy content width.
397 if ( isset( $used_layout['inherit'] ) && $used_layout['inherit'] || isset( $used_layout['contentSize'] ) && $used_layout['contentSize'] ) {
398 $used_layout['type'] = 'constrained';
399 }
400
401 $root_padding_aware_alignments = _wp_array_get( $global_settings, array( 'useRootPaddingAwareAlignments' ), false );
402
403 if (
404 $root_padding_aware_alignments &&
405 isset( $used_layout['type'] ) &&
406 'constrained' === $used_layout['type']
407 ) {
408 $class_names[] = 'has-global-padding';
409 }
410
411 /*
412 * The following section was added to reintroduce a small set of layout classnames that were
413 * removed in the 5.9 release (https://github.com/WordPress/gutenberg/issues/38719). It is
414 * not intended to provide an extended set of classes to match all block layout attributes
415 * here.
416 */
417 if ( ! empty( $block['attrs']['layout']['orientation'] ) ) {
418 $class_names[] = 'is-' . sanitize_title( $block['attrs']['layout']['orientation'] );
419 }
420
421 if ( ! empty( $block['attrs']['layout']['justifyContent'] ) ) {
422 $class_names[] = 'is-content-justification-' . sanitize_title( $block['attrs']['layout']['justifyContent'] );
423 }
424
425 if ( ! empty( $block['attrs']['layout']['flexWrap'] ) && 'nowrap' === $block['attrs']['layout']['flexWrap'] ) {
426 $class_names[] = 'is-nowrap';
427 }
428
429 // Get classname for layout type.
430 if ( isset( $used_layout['type'] ) ) {
431 $layout_classname = _wp_array_get( $layout_definitions, array( $used_layout['type'], 'className' ), '' );
432 } else {
433 $layout_classname = _wp_array_get( $layout_definitions, array( 'default', 'className' ), '' );
434 }
435
436 if ( $layout_classname && is_string( $layout_classname ) ) {
437 $class_names[] = sanitize_title( $layout_classname );
438 }
439
440 /*
441 * Only generate Layout styles if the theme has not opted-out.
442 * Attribute-based Layout classnames are output in all cases.
443 */
444 if ( ! current_theme_supports( 'disable-layout-styles' ) ) {
445
446 $gap_value = _wp_array_get( $block, array( 'attrs', 'style', 'spacing', 'blockGap' ) );
447
448 /*
449 * Skip if gap value contains unsupported characters.
450 * Regex for CSS value borrowed from `safecss_filter_attr`, and used here
451 * to only match against the value, not the CSS attribute.
452 */
453 if ( is_array( $gap_value ) ) {
454 foreach ( $gap_value as $key => $value ) {
455 $gap_value[ $key ] = $value && preg_match( '%[\\\(&=}]|/\*%', $value ) ? null : $value;
456 }
457 } else {
458 $gap_value = $gap_value && preg_match( '%[\\\(&=}]|/\*%', $gap_value ) ? null : $gap_value;
459 }
460
461 $fallback_gap_value = _wp_array_get( $block_type->supports, array( 'spacing', 'blockGap', '__experimentalDefault' ), '0.5em' );
462 $block_spacing = _wp_array_get( $block, array( 'attrs', 'style', 'spacing' ), null );
463
464 /*
465 * If a block's block.json skips serialization for spacing or spacing.blockGap,
466 * don't apply the user-defined value to the styles.
467 */
468 $should_skip_gap_serialization = wp_should_skip_block_supports_serialization( $block_type, 'spacing', 'blockGap' );
469
470 $block_gap = _wp_array_get( $global_settings, array( 'spacing', 'blockGap' ), null );
471 $has_block_gap_support = isset( $block_gap );
472
473 $style = gutenberg_get_layout_style(
474 ".$container_class.$container_class",
475 $used_layout,
476 $has_block_gap_support,
477 $gap_value,
478 $should_skip_gap_serialization,
479 $fallback_gap_value,
480 $block_spacing
481 );
482
483 // Only add container class and enqueue block support styles if unique styles were generated.
484 if ( ! empty( $style ) ) {
485 $class_names[] = $container_class;
486 }
487 }
488
489 $content_with_outer_classnames = '';
490
491 if ( ! empty( $outer_class_names ) ) {
492 $content_with_outer_classnames = new WP_HTML_Tag_Processor( $block_content );
493 $content_with_outer_classnames->next_tag();
494 foreach ( $outer_class_names as $outer_class_name ) {
495 $content_with_outer_classnames->add_class( $outer_class_name );
496 }
497
498 $content_with_outer_classnames = (string) $content_with_outer_classnames;
499 }
500
501 /**
502 * The first chunk of innerContent contains the block markup up until the inner blocks start.
503 * We want to target the opening tag of the inner blocks wrapper, which is the last tag in that chunk.
504 */
505 $inner_content_classnames = isset( $block['innerContent'][0] ) && 'string' === gettype( $block['innerContent'][0] ) ? gutenberg_get_classnames_from_last_tag( $block['innerContent'][0] ) : '';
506
507 $content = $content_with_outer_classnames ? new WP_HTML_Tag_Processor( $content_with_outer_classnames ) : new WP_HTML_Tag_Processor( $block_content );
508
509 if ( $inner_content_classnames ) {
510 $content->next_tag( array( 'class_name' => $inner_content_classnames ) );
511 foreach ( $class_names as $class_name ) {
512 $content->add_class( $class_name );
513 }
514 } else {
515 $content->next_tag();
516 foreach ( $class_names as $class_name ) {
517 $content->add_class( $class_name );
518 }
519 }
520
521 return (string) $content;
522 }
523
524 // Register the block support. (overrides core one).
525 WP_Block_Supports::get_instance()->register(
526 'layout',
527 array(
528 'register_attribute' => 'gutenberg_register_layout_support',
529 )
530 );
531
532 if ( function_exists( 'wp_render_layout_support_flag' ) ) {
533 remove_filter( 'render_block', 'wp_render_layout_support_flag' );
534 }
535 add_filter( 'render_block', 'gutenberg_render_layout_support_flag', 10, 2 );
536
537 /**
538 * For themes without theme.json file, make sure
539 * to restore the inner div for the group block
540 * to avoid breaking styles relying on that div.
541 *
542 * @param string $block_content Rendered block content.
543 * @param array $block Block object.
544 * @return string Filtered block content.
545 */
546 function gutenberg_restore_group_inner_container( $block_content, $block ) {
547 $tag_name = isset( $block['attrs']['tagName'] ) ? $block['attrs']['tagName'] : 'div';
548 $group_with_inner_container_regex = sprintf(
549 '/(^\s*<%1$s\b[^>]*wp-block-group(\s|")[^>]*>)(\s*<div\b[^>]*wp-block-group__inner-container(\s|")[^>]*>)((.|\S|\s)*)/U',
550 preg_quote( $tag_name, '/' )
551 );
552 if (
553 wp_theme_has_theme_json() ||
554 1 === preg_match( $group_with_inner_container_regex, $block_content ) ||
555 ( isset( $block['attrs']['layout']['type'] ) && 'flex' === $block['attrs']['layout']['type'] )
556 ) {
557 return $block_content;
558 }
559
560 $replace_regex = sprintf(
561 '/(^\s*<%1$s\b[^>]*wp-block-group[^>]*>)(.*)(<\/%1$s>\s*$)/ms',
562 preg_quote( $tag_name, '/' )
563 );
564 $updated_content = preg_replace_callback(
565 $replace_regex,
566 function( $matches ) {
567 return $matches[1] . '<div class="wp-block-group__inner-container">' . $matches[2] . '</div>' . $matches[3];
568 },
569 $block_content
570 );
571 return $updated_content;
572 }
573
574 if ( function_exists( 'wp_restore_group_inner_container' ) ) {
575 remove_filter( 'render_block', 'wp_restore_group_inner_container', 10, 2 );
576 remove_filter( 'render_block_core/group', 'wp_restore_group_inner_container', 10, 2 );
577 }
578 add_filter( 'render_block_core/group', 'gutenberg_restore_group_inner_container', 10, 2 );
579
580
581 /**
582 * For themes without theme.json file, make sure
583 * to restore the outer div for the aligned image block
584 * to avoid breaking styles relying on that div.
585 *
586 * @param string $block_content Rendered block content.
587 * @param array $block Block object.
588 * @return string Filtered block content.
589 */
590 function gutenberg_restore_image_outer_container( $block_content, $block ) {
591 $image_with_align = "
592 /# 1) everything up to the class attribute contents
593 (
594 ^\s*
595 <figure\b
596 [^>]*
597 \bclass=
598 [\"']
599 )
600 # 2) the class attribute contents
601 (
602 [^\"']*
603 \bwp-block-image\b
604 [^\"']*
605 \b(?:alignleft|alignright|aligncenter)\b
606 [^\"']*
607 )
608 # 3) everything after the class attribute contents
609 (
610 [\"']
611 [^>]*
612 >
613 .*
614 <\/figure>
615 )/iUx";
616
617 if (
618 wp_theme_has_theme_json() ||
619 0 === preg_match( $image_with_align, $block_content, $matches )
620 ) {
621 return $block_content;
622 }
623
624 $wrapper_classnames = array( 'wp-block-image' );
625
626 // If the block has a classNames attribute these classnames need to be removed from the content and added back
627 // to the new wrapper div also.
628 if ( ! empty( $block['attrs']['className'] ) ) {
629 $wrapper_classnames = array_merge( $wrapper_classnames, explode( ' ', $block['attrs']['className'] ) );
630 }
631 $content_classnames = explode( ' ', $matches[2] );
632 $filtered_content_classnames = array_diff( $content_classnames, $wrapper_classnames );
633
634 return '<div class="' . implode( ' ', $wrapper_classnames ) . '">' . $matches[1] . implode( ' ', $filtered_content_classnames ) . $matches[3] . '</div>';
635 }
636
637 if ( function_exists( 'wp_restore_image_outer_container' ) ) {
638 remove_filter( 'render_block_core/image', 'wp_restore_image_outer_container', 10, 2 );
639 }
640 add_filter( 'render_block_core/image', 'gutenberg_restore_image_outer_container', 10, 2 );
641