5 * @package WordPress |
5 * @package WordPress |
6 * @since 5.8.0 |
6 * @since 5.8.0 |
7 */ |
7 */ |
8 |
8 |
9 /** |
9 /** |
|
10 * Returns layout definitions, keyed by layout type. |
|
11 * |
|
12 * Provides a common definition of slugs, classnames, base styles, and spacing styles for each layout type. |
|
13 * When making changes or additions to layout definitions, the corresponding JavaScript definitions should |
|
14 * also be updated. |
|
15 * |
|
16 * @since 6.3.0 |
|
17 * @since 6.6.0 Updated specificity for compatibility with 0-1-0 global styles specificity. |
|
18 * @access private |
|
19 * |
|
20 * @return array[] Layout definitions. |
|
21 */ |
|
22 function wp_get_layout_definitions() { |
|
23 $layout_definitions = array( |
|
24 'default' => array( |
|
25 'name' => 'default', |
|
26 'slug' => 'flow', |
|
27 'className' => 'is-layout-flow', |
|
28 'baseStyles' => array( |
|
29 array( |
|
30 'selector' => ' > .alignleft', |
|
31 'rules' => array( |
|
32 'float' => 'left', |
|
33 'margin-inline-start' => '0', |
|
34 'margin-inline-end' => '2em', |
|
35 ), |
|
36 ), |
|
37 array( |
|
38 'selector' => ' > .alignright', |
|
39 'rules' => array( |
|
40 'float' => 'right', |
|
41 'margin-inline-start' => '2em', |
|
42 'margin-inline-end' => '0', |
|
43 ), |
|
44 ), |
|
45 array( |
|
46 'selector' => ' > .aligncenter', |
|
47 'rules' => array( |
|
48 'margin-left' => 'auto !important', |
|
49 'margin-right' => 'auto !important', |
|
50 ), |
|
51 ), |
|
52 ), |
|
53 'spacingStyles' => array( |
|
54 array( |
|
55 'selector' => ' > :first-child', |
|
56 'rules' => array( |
|
57 'margin-block-start' => '0', |
|
58 ), |
|
59 ), |
|
60 array( |
|
61 'selector' => ' > :last-child', |
|
62 'rules' => array( |
|
63 'margin-block-end' => '0', |
|
64 ), |
|
65 ), |
|
66 array( |
|
67 'selector' => ' > *', |
|
68 'rules' => array( |
|
69 'margin-block-start' => null, |
|
70 'margin-block-end' => '0', |
|
71 ), |
|
72 ), |
|
73 ), |
|
74 ), |
|
75 'constrained' => array( |
|
76 'name' => 'constrained', |
|
77 'slug' => 'constrained', |
|
78 'className' => 'is-layout-constrained', |
|
79 'baseStyles' => array( |
|
80 array( |
|
81 'selector' => ' > .alignleft', |
|
82 'rules' => array( |
|
83 'float' => 'left', |
|
84 'margin-inline-start' => '0', |
|
85 'margin-inline-end' => '2em', |
|
86 ), |
|
87 ), |
|
88 array( |
|
89 'selector' => ' > .alignright', |
|
90 'rules' => array( |
|
91 'float' => 'right', |
|
92 'margin-inline-start' => '2em', |
|
93 'margin-inline-end' => '0', |
|
94 ), |
|
95 ), |
|
96 array( |
|
97 'selector' => ' > .aligncenter', |
|
98 'rules' => array( |
|
99 'margin-left' => 'auto !important', |
|
100 'margin-right' => 'auto !important', |
|
101 ), |
|
102 ), |
|
103 array( |
|
104 'selector' => ' > :where(:not(.alignleft):not(.alignright):not(.alignfull))', |
|
105 'rules' => array( |
|
106 'max-width' => 'var(--wp--style--global--content-size)', |
|
107 'margin-left' => 'auto !important', |
|
108 'margin-right' => 'auto !important', |
|
109 ), |
|
110 ), |
|
111 array( |
|
112 'selector' => ' > .alignwide', |
|
113 'rules' => array( |
|
114 'max-width' => 'var(--wp--style--global--wide-size)', |
|
115 ), |
|
116 ), |
|
117 ), |
|
118 'spacingStyles' => array( |
|
119 array( |
|
120 'selector' => ' > :first-child', |
|
121 'rules' => array( |
|
122 'margin-block-start' => '0', |
|
123 ), |
|
124 ), |
|
125 array( |
|
126 'selector' => ' > :last-child', |
|
127 'rules' => array( |
|
128 'margin-block-end' => '0', |
|
129 ), |
|
130 ), |
|
131 array( |
|
132 'selector' => ' > *', |
|
133 'rules' => array( |
|
134 'margin-block-start' => null, |
|
135 'margin-block-end' => '0', |
|
136 ), |
|
137 ), |
|
138 ), |
|
139 ), |
|
140 'flex' => array( |
|
141 'name' => 'flex', |
|
142 'slug' => 'flex', |
|
143 'className' => 'is-layout-flex', |
|
144 'displayMode' => 'flex', |
|
145 'baseStyles' => array( |
|
146 array( |
|
147 'selector' => '', |
|
148 'rules' => array( |
|
149 'flex-wrap' => 'wrap', |
|
150 'align-items' => 'center', |
|
151 ), |
|
152 ), |
|
153 array( |
|
154 'selector' => ' > :is(*, div)', // :is(*, div) instead of just * increases the specificity by 001. |
|
155 'rules' => array( |
|
156 'margin' => '0', |
|
157 ), |
|
158 ), |
|
159 ), |
|
160 'spacingStyles' => array( |
|
161 array( |
|
162 'selector' => '', |
|
163 'rules' => array( |
|
164 'gap' => null, |
|
165 ), |
|
166 ), |
|
167 ), |
|
168 ), |
|
169 'grid' => array( |
|
170 'name' => 'grid', |
|
171 'slug' => 'grid', |
|
172 'className' => 'is-layout-grid', |
|
173 'displayMode' => 'grid', |
|
174 'baseStyles' => array( |
|
175 array( |
|
176 'selector' => ' > :is(*, div)', // :is(*, div) instead of just * increases the specificity by 001. |
|
177 'rules' => array( |
|
178 'margin' => '0', |
|
179 ), |
|
180 ), |
|
181 ), |
|
182 'spacingStyles' => array( |
|
183 array( |
|
184 'selector' => '', |
|
185 'rules' => array( |
|
186 'gap' => null, |
|
187 ), |
|
188 ), |
|
189 ), |
|
190 ), |
|
191 ); |
|
192 |
|
193 return $layout_definitions; |
|
194 } |
|
195 |
|
196 /** |
10 * Registers the layout block attribute for block types that support it. |
197 * Registers the layout block attribute for block types that support it. |
11 * |
198 * |
12 * @since 5.8.0 |
199 * @since 5.8.0 |
|
200 * @since 6.3.0 Check for layout support via the `layout` key with fallback to `__experimentalLayout`. |
13 * @access private |
201 * @access private |
14 * |
202 * |
15 * @param WP_Block_Type $block_type Block Type. |
203 * @param WP_Block_Type $block_type Block Type. |
16 */ |
204 */ |
17 function wp_register_layout_support( $block_type ) { |
205 function wp_register_layout_support( $block_type ) { |
18 $support_layout = block_has_support( $block_type, array( '__experimentalLayout' ), false ); |
206 $support_layout = block_has_support( $block_type, 'layout', false ) || block_has_support( $block_type, '__experimentalLayout', false ); |
19 if ( $support_layout ) { |
207 if ( $support_layout ) { |
20 if ( ! $block_type->attributes ) { |
208 if ( ! $block_type->attributes ) { |
21 $block_type->attributes = array(); |
209 $block_type->attributes = array(); |
22 } |
210 } |
23 |
211 |
31 |
219 |
32 /** |
220 /** |
33 * Generates the CSS corresponding to the provided layout. |
221 * Generates the CSS corresponding to the provided layout. |
34 * |
222 * |
35 * @since 5.9.0 |
223 * @since 5.9.0 |
|
224 * @since 6.1.0 Added `$block_spacing` param, use style engine to enqueue styles. |
|
225 * @since 6.3.0 Added grid layout type. |
|
226 * @since 6.6.0 Removed duplicated selector from layout styles. |
|
227 * Enabled negative margins for alignfull children of blocks with custom padding. |
36 * @access private |
228 * @access private |
37 * |
229 * |
38 * @param string $selector CSS selector. |
230 * @param string $selector CSS selector. |
39 * @param array $layout Layout object. The one that is passed has already checked |
231 * @param array $layout Layout object. The one that is passed has already checked |
40 * the existence of default block layout. |
232 * the existence of default block layout. |
41 * @param boolean $has_block_gap_support Whether the theme has support for the block gap. |
233 * @param bool $has_block_gap_support Optional. Whether the theme has support for the block gap. Default false. |
42 * @param string $gap_value The block gap value to apply. |
234 * @param string|string[]|null $gap_value Optional. The block gap value to apply. Default null. |
43 * @param boolean $should_skip_gap_serialization Whether to skip applying the user-defined value set in the editor. |
235 * @param bool $should_skip_gap_serialization Optional. Whether to skip applying the user-defined value set in the editor. Default false. |
44 * @param string $fallback_gap_value The custom fallback value for block gap. |
236 * @param string $fallback_gap_value Optional. The block gap value to apply. Default '0.5em'. |
45 * @return string CSS style. |
237 * @param array|null $block_spacing Optional. Custom spacing set on the block. Default null. |
|
238 * @return string CSS styles on success. Else, empty string. |
46 */ |
239 */ |
47 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' ) { |
240 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 ) { |
48 $layout_type = isset( $layout['type'] ) ? $layout['type'] : 'default'; |
241 $layout_type = isset( $layout['type'] ) ? $layout['type'] : 'default'; |
49 |
242 $layout_styles = array(); |
50 $style = ''; |
243 |
51 if ( 'default' === $layout_type ) { |
244 if ( 'default' === $layout_type ) { |
52 $content_size = isset( $layout['contentSize'] ) ? $layout['contentSize'] : ''; |
245 if ( $has_block_gap_support ) { |
53 $wide_size = isset( $layout['wideSize'] ) ? $layout['wideSize'] : ''; |
246 if ( is_array( $gap_value ) ) { |
|
247 $gap_value = isset( $gap_value['top'] ) ? $gap_value['top'] : null; |
|
248 } |
|
249 if ( null !== $gap_value && ! $should_skip_gap_serialization ) { |
|
250 // Get spacing CSS variable from preset value if provided. |
|
251 if ( is_string( $gap_value ) && str_contains( $gap_value, 'var:preset|spacing|' ) ) { |
|
252 $index_to_splice = strrpos( $gap_value, '|' ) + 1; |
|
253 $slug = _wp_to_kebab_case( substr( $gap_value, $index_to_splice ) ); |
|
254 $gap_value = "var(--wp--preset--spacing--$slug)"; |
|
255 } |
|
256 |
|
257 array_push( |
|
258 $layout_styles, |
|
259 array( |
|
260 'selector' => "$selector > *", |
|
261 'declarations' => array( |
|
262 'margin-block-start' => '0', |
|
263 'margin-block-end' => '0', |
|
264 ), |
|
265 ), |
|
266 array( |
|
267 'selector' => "$selector > * + *", |
|
268 'declarations' => array( |
|
269 'margin-block-start' => $gap_value, |
|
270 'margin-block-end' => '0', |
|
271 ), |
|
272 ) |
|
273 ); |
|
274 } |
|
275 } |
|
276 } elseif ( 'constrained' === $layout_type ) { |
|
277 $content_size = isset( $layout['contentSize'] ) ? $layout['contentSize'] : ''; |
|
278 $wide_size = isset( $layout['wideSize'] ) ? $layout['wideSize'] : ''; |
|
279 $justify_content = isset( $layout['justifyContent'] ) ? $layout['justifyContent'] : 'center'; |
54 |
280 |
55 $all_max_width_value = $content_size ? $content_size : $wide_size; |
281 $all_max_width_value = $content_size ? $content_size : $wide_size; |
56 $wide_max_width_value = $wide_size ? $wide_size : $content_size; |
282 $wide_max_width_value = $wide_size ? $wide_size : $content_size; |
57 |
283 |
58 // Make sure there is a single CSS rule, and all tags are stripped for security. |
284 // Make sure there is a single CSS rule, and all tags are stripped for security. |
59 $all_max_width_value = safecss_filter_attr( explode( ';', $all_max_width_value )[0] ); |
285 $all_max_width_value = safecss_filter_attr( explode( ';', $all_max_width_value )[0] ); |
60 $wide_max_width_value = safecss_filter_attr( explode( ';', $wide_max_width_value )[0] ); |
286 $wide_max_width_value = safecss_filter_attr( explode( ';', $wide_max_width_value )[0] ); |
61 |
287 |
|
288 $margin_left = 'left' === $justify_content ? '0 !important' : 'auto !important'; |
|
289 $margin_right = 'right' === $justify_content ? '0 !important' : 'auto !important'; |
|
290 |
62 if ( $content_size || $wide_size ) { |
291 if ( $content_size || $wide_size ) { |
63 $style = "$selector > :where(:not(.alignleft):not(.alignright)) {"; |
292 array_push( |
64 $style .= 'max-width: ' . esc_html( $all_max_width_value ) . ';'; |
293 $layout_styles, |
65 $style .= 'margin-left: auto !important;'; |
294 array( |
66 $style .= 'margin-right: auto !important;'; |
295 'selector' => "$selector > :where(:not(.alignleft):not(.alignright):not(.alignfull))", |
67 $style .= '}'; |
296 'declarations' => array( |
68 |
297 'max-width' => $all_max_width_value, |
69 $style .= "$selector > .alignwide { max-width: " . esc_html( $wide_max_width_value ) . ';}'; |
298 'margin-left' => $margin_left, |
70 $style .= "$selector .alignfull { max-width: none; }"; |
299 'margin-right' => $margin_right, |
71 } |
300 ), |
72 |
301 ), |
73 $style .= "$selector > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }"; |
302 array( |
74 $style .= "$selector > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }"; |
303 'selector' => "$selector > .alignwide", |
75 $style .= "$selector > .aligncenter { margin-left: auto !important; margin-right: auto !important; }"; |
304 'declarations' => array( 'max-width' => $wide_max_width_value ), |
|
305 ), |
|
306 array( |
|
307 'selector' => "$selector .alignfull", |
|
308 'declarations' => array( 'max-width' => 'none' ), |
|
309 ) |
|
310 ); |
|
311 } |
|
312 |
|
313 if ( isset( $block_spacing ) ) { |
|
314 $block_spacing_values = wp_style_engine_get_styles( |
|
315 array( |
|
316 'spacing' => $block_spacing, |
|
317 ) |
|
318 ); |
|
319 |
|
320 /* |
|
321 * Handle negative margins for alignfull children of blocks with custom padding set. |
|
322 * They're added separately because padding might only be set on one side. |
|
323 */ |
|
324 if ( isset( $block_spacing_values['declarations']['padding-right'] ) ) { |
|
325 $padding_right = $block_spacing_values['declarations']['padding-right']; |
|
326 // Add unit if 0. |
|
327 if ( '0' === $padding_right ) { |
|
328 $padding_right = '0px'; |
|
329 } |
|
330 $layout_styles[] = array( |
|
331 'selector' => "$selector > .alignfull", |
|
332 'declarations' => array( 'margin-right' => "calc($padding_right * -1)" ), |
|
333 ); |
|
334 } |
|
335 if ( isset( $block_spacing_values['declarations']['padding-left'] ) ) { |
|
336 $padding_left = $block_spacing_values['declarations']['padding-left']; |
|
337 // Add unit if 0. |
|
338 if ( '0' === $padding_left ) { |
|
339 $padding_left = '0px'; |
|
340 } |
|
341 $layout_styles[] = array( |
|
342 'selector' => "$selector > .alignfull", |
|
343 'declarations' => array( 'margin-left' => "calc($padding_left * -1)" ), |
|
344 ); |
|
345 } |
|
346 } |
|
347 |
|
348 if ( 'left' === $justify_content ) { |
|
349 $layout_styles[] = array( |
|
350 'selector' => "$selector > :where(:not(.alignleft):not(.alignright):not(.alignfull))", |
|
351 'declarations' => array( 'margin-left' => '0 !important' ), |
|
352 ); |
|
353 } |
|
354 |
|
355 if ( 'right' === $justify_content ) { |
|
356 $layout_styles[] = array( |
|
357 'selector' => "$selector > :where(:not(.alignleft):not(.alignright):not(.alignfull))", |
|
358 'declarations' => array( 'margin-right' => '0 !important' ), |
|
359 ); |
|
360 } |
|
361 |
76 if ( $has_block_gap_support ) { |
362 if ( $has_block_gap_support ) { |
77 if ( is_array( $gap_value ) ) { |
363 if ( is_array( $gap_value ) ) { |
78 $gap_value = isset( $gap_value['top'] ) ? $gap_value['top'] : null; |
364 $gap_value = isset( $gap_value['top'] ) ? $gap_value['top'] : null; |
79 } |
365 } |
80 $gap_style = $gap_value && ! $should_skip_gap_serialization ? $gap_value : 'var( --wp--style--block-gap )'; |
366 if ( null !== $gap_value && ! $should_skip_gap_serialization ) { |
81 $style .= "$selector > * { margin-block-start: 0; margin-block-end: 0; }"; |
367 // Get spacing CSS variable from preset value if provided. |
82 $style .= "$selector > * + * { margin-block-start: $gap_style; margin-block-end: 0; }"; |
368 if ( is_string( $gap_value ) && str_contains( $gap_value, 'var:preset|spacing|' ) ) { |
|
369 $index_to_splice = strrpos( $gap_value, '|' ) + 1; |
|
370 $slug = _wp_to_kebab_case( substr( $gap_value, $index_to_splice ) ); |
|
371 $gap_value = "var(--wp--preset--spacing--$slug)"; |
|
372 } |
|
373 |
|
374 array_push( |
|
375 $layout_styles, |
|
376 array( |
|
377 'selector' => "$selector > *", |
|
378 'declarations' => array( |
|
379 'margin-block-start' => '0', |
|
380 'margin-block-end' => '0', |
|
381 ), |
|
382 ), |
|
383 array( |
|
384 'selector' => "$selector > * + *", |
|
385 'declarations' => array( |
|
386 'margin-block-start' => $gap_value, |
|
387 'margin-block-end' => '0', |
|
388 ), |
|
389 ) |
|
390 ); |
|
391 } |
83 } |
392 } |
84 } elseif ( 'flex' === $layout_type ) { |
393 } elseif ( 'flex' === $layout_type ) { |
85 $layout_orientation = isset( $layout['orientation'] ) ? $layout['orientation'] : 'horizontal'; |
394 $layout_orientation = isset( $layout['orientation'] ) ? $layout['orientation'] : 'horizontal'; |
86 |
395 |
87 $justify_content_options = array( |
396 $justify_content_options = array( |
88 'left' => 'flex-start', |
397 'left' => 'flex-start', |
89 'right' => 'flex-end', |
398 'right' => 'flex-end', |
90 'center' => 'center', |
399 'center' => 'center', |
91 ); |
400 ); |
92 |
401 |
|
402 $vertical_alignment_options = array( |
|
403 'top' => 'flex-start', |
|
404 'center' => 'center', |
|
405 'bottom' => 'flex-end', |
|
406 ); |
|
407 |
93 if ( 'horizontal' === $layout_orientation ) { |
408 if ( 'horizontal' === $layout_orientation ) { |
94 $justify_content_options += array( 'space-between' => 'space-between' ); |
409 $justify_content_options += array( 'space-between' => 'space-between' ); |
95 } |
410 $vertical_alignment_options += array( 'stretch' => 'stretch' ); |
96 |
|
97 $flex_wrap_options = array( 'wrap', 'nowrap' ); |
|
98 $flex_wrap = ! empty( $layout['flexWrap'] ) && in_array( $layout['flexWrap'], $flex_wrap_options, true ) ? |
|
99 $layout['flexWrap'] : |
|
100 'wrap'; |
|
101 |
|
102 $style = "$selector {"; |
|
103 $style .= 'display: flex;'; |
|
104 if ( $has_block_gap_support ) { |
|
105 if ( is_array( $gap_value ) ) { |
|
106 $gap_row = isset( $gap_value['top'] ) ? $gap_value['top'] : $fallback_gap_value; |
|
107 $gap_column = isset( $gap_value['left'] ) ? $gap_value['left'] : $fallback_gap_value; |
|
108 $gap_value = $gap_row === $gap_column ? $gap_row : $gap_row . ' ' . $gap_column; |
|
109 } |
|
110 $gap_style = $gap_value && ! $should_skip_gap_serialization ? $gap_value : "var( --wp--style--block-gap, $fallback_gap_value )"; |
|
111 $style .= "gap: $gap_style;"; |
|
112 } else { |
411 } else { |
113 $style .= "gap: $fallback_gap_value;"; |
412 $justify_content_options += array( 'stretch' => 'stretch' ); |
114 } |
413 $vertical_alignment_options += array( 'space-between' => 'space-between' ); |
115 |
414 } |
116 $style .= "flex-wrap: $flex_wrap;"; |
415 |
|
416 if ( ! empty( $layout['flexWrap'] ) && 'nowrap' === $layout['flexWrap'] ) { |
|
417 $layout_styles[] = array( |
|
418 'selector' => $selector, |
|
419 'declarations' => array( 'flex-wrap' => 'nowrap' ), |
|
420 ); |
|
421 } |
|
422 |
|
423 if ( $has_block_gap_support && isset( $gap_value ) ) { |
|
424 $combined_gap_value = ''; |
|
425 $gap_sides = is_array( $gap_value ) ? array( 'top', 'left' ) : array( 'top' ); |
|
426 |
|
427 foreach ( $gap_sides as $gap_side ) { |
|
428 $process_value = $gap_value; |
|
429 if ( is_array( $gap_value ) ) { |
|
430 $process_value = isset( $gap_value[ $gap_side ] ) ? $gap_value[ $gap_side ] : $fallback_gap_value; |
|
431 } |
|
432 // Get spacing CSS variable from preset value if provided. |
|
433 if ( is_string( $process_value ) && str_contains( $process_value, 'var:preset|spacing|' ) ) { |
|
434 $index_to_splice = strrpos( $process_value, '|' ) + 1; |
|
435 $slug = _wp_to_kebab_case( substr( $process_value, $index_to_splice ) ); |
|
436 $process_value = "var(--wp--preset--spacing--$slug)"; |
|
437 } |
|
438 $combined_gap_value .= "$process_value "; |
|
439 } |
|
440 $gap_value = trim( $combined_gap_value ); |
|
441 |
|
442 if ( null !== $gap_value && ! $should_skip_gap_serialization ) { |
|
443 $layout_styles[] = array( |
|
444 'selector' => $selector, |
|
445 'declarations' => array( 'gap' => $gap_value ), |
|
446 ); |
|
447 } |
|
448 } |
|
449 |
117 if ( 'horizontal' === $layout_orientation ) { |
450 if ( 'horizontal' === $layout_orientation ) { |
118 $style .= 'align-items: center;'; |
451 /* |
119 /** |
|
120 * Add this style only if is not empty for backwards compatibility, |
452 * Add this style only if is not empty for backwards compatibility, |
121 * since we intend to convert blocks that had flex layout implemented |
453 * since we intend to convert blocks that had flex layout implemented |
122 * by custom css. |
454 * by custom css. |
123 */ |
455 */ |
124 if ( ! empty( $layout['justifyContent'] ) && array_key_exists( $layout['justifyContent'], $justify_content_options ) ) { |
456 if ( ! empty( $layout['justifyContent'] ) && array_key_exists( $layout['justifyContent'], $justify_content_options ) ) { |
125 $style .= "justify-content: {$justify_content_options[ $layout['justifyContent'] ]};"; |
457 $layout_styles[] = array( |
|
458 'selector' => $selector, |
|
459 'declarations' => array( 'justify-content' => $justify_content_options[ $layout['justifyContent'] ] ), |
|
460 ); |
|
461 } |
|
462 |
|
463 if ( ! empty( $layout['verticalAlignment'] ) && array_key_exists( $layout['verticalAlignment'], $vertical_alignment_options ) ) { |
|
464 $layout_styles[] = array( |
|
465 'selector' => $selector, |
|
466 'declarations' => array( 'align-items' => $vertical_alignment_options[ $layout['verticalAlignment'] ] ), |
|
467 ); |
126 } |
468 } |
127 } else { |
469 } else { |
128 $style .= 'flex-direction: column;'; |
470 $layout_styles[] = array( |
|
471 'selector' => $selector, |
|
472 'declarations' => array( 'flex-direction' => 'column' ), |
|
473 ); |
129 if ( ! empty( $layout['justifyContent'] ) && array_key_exists( $layout['justifyContent'], $justify_content_options ) ) { |
474 if ( ! empty( $layout['justifyContent'] ) && array_key_exists( $layout['justifyContent'], $justify_content_options ) ) { |
130 $style .= "align-items: {$justify_content_options[ $layout['justifyContent'] ]};"; |
475 $layout_styles[] = array( |
|
476 'selector' => $selector, |
|
477 'declarations' => array( 'align-items' => $justify_content_options[ $layout['justifyContent'] ] ), |
|
478 ); |
131 } else { |
479 } else { |
132 $style .= 'align-items: flex-start;'; |
480 $layout_styles[] = array( |
133 } |
481 'selector' => $selector, |
134 } |
482 'declarations' => array( 'align-items' => 'flex-start' ), |
135 $style .= '}'; |
483 ); |
136 |
484 } |
137 $style .= "$selector > * { margin: 0; }"; |
485 if ( ! empty( $layout['verticalAlignment'] ) && array_key_exists( $layout['verticalAlignment'], $vertical_alignment_options ) ) { |
138 } |
486 $layout_styles[] = array( |
139 |
487 'selector' => $selector, |
140 return $style; |
488 'declarations' => array( 'justify-content' => $vertical_alignment_options[ $layout['verticalAlignment'] ] ), |
|
489 ); |
|
490 } |
|
491 } |
|
492 } elseif ( 'grid' === $layout_type ) { |
|
493 if ( ! empty( $layout['columnCount'] ) ) { |
|
494 $layout_styles[] = array( |
|
495 'selector' => $selector, |
|
496 'declarations' => array( 'grid-template-columns' => 'repeat(' . $layout['columnCount'] . ', minmax(0, 1fr))' ), |
|
497 ); |
|
498 } else { |
|
499 $minimum_column_width = ! empty( $layout['minimumColumnWidth'] ) ? $layout['minimumColumnWidth'] : '12rem'; |
|
500 |
|
501 $layout_styles[] = array( |
|
502 'selector' => $selector, |
|
503 'declarations' => array( |
|
504 'grid-template-columns' => 'repeat(auto-fill, minmax(min(' . $minimum_column_width . ', 100%), 1fr))', |
|
505 'container-type' => 'inline-size', |
|
506 ), |
|
507 ); |
|
508 } |
|
509 |
|
510 if ( $has_block_gap_support && isset( $gap_value ) ) { |
|
511 $combined_gap_value = ''; |
|
512 $gap_sides = is_array( $gap_value ) ? array( 'top', 'left' ) : array( 'top' ); |
|
513 |
|
514 foreach ( $gap_sides as $gap_side ) { |
|
515 $process_value = $gap_value; |
|
516 if ( is_array( $gap_value ) ) { |
|
517 $process_value = isset( $gap_value[ $gap_side ] ) ? $gap_value[ $gap_side ] : $fallback_gap_value; |
|
518 } |
|
519 // Get spacing CSS variable from preset value if provided. |
|
520 if ( is_string( $process_value ) && str_contains( $process_value, 'var:preset|spacing|' ) ) { |
|
521 $index_to_splice = strrpos( $process_value, '|' ) + 1; |
|
522 $slug = _wp_to_kebab_case( substr( $process_value, $index_to_splice ) ); |
|
523 $process_value = "var(--wp--preset--spacing--$slug)"; |
|
524 } |
|
525 $combined_gap_value .= "$process_value "; |
|
526 } |
|
527 $gap_value = trim( $combined_gap_value ); |
|
528 |
|
529 if ( null !== $gap_value && ! $should_skip_gap_serialization ) { |
|
530 $layout_styles[] = array( |
|
531 'selector' => $selector, |
|
532 'declarations' => array( 'gap' => $gap_value ), |
|
533 ); |
|
534 } |
|
535 } |
|
536 } |
|
537 |
|
538 if ( ! empty( $layout_styles ) ) { |
|
539 /* |
|
540 * Add to the style engine store to enqueue and render layout styles. |
|
541 * Return compiled layout styles to retain backwards compatibility. |
|
542 * Since https://github.com/WordPress/gutenberg/pull/42452, |
|
543 * wp_enqueue_block_support_styles is no longer called in this block supports file. |
|
544 */ |
|
545 return wp_style_engine_get_stylesheet_from_css_rules( |
|
546 $layout_styles, |
|
547 array( |
|
548 'context' => 'block-supports', |
|
549 'prettify' => false, |
|
550 ) |
|
551 ); |
|
552 } |
|
553 |
|
554 return ''; |
141 } |
555 } |
142 |
556 |
143 /** |
557 /** |
144 * Renders the layout config to the block wrapper. |
558 * Renders the layout config to the block wrapper. |
145 * |
559 * |
146 * @since 5.8.0 |
560 * @since 5.8.0 |
|
561 * @since 6.3.0 Adds compound class to layout wrapper for global spacing styles. |
|
562 * @since 6.3.0 Check for layout support via the `layout` key with fallback to `__experimentalLayout`. |
|
563 * @since 6.6.0 Removed duplicate container class from layout styles. |
147 * @access private |
564 * @access private |
148 * |
565 * |
149 * @param string $block_content Rendered block content. |
566 * @param string $block_content Rendered block content. |
150 * @param array $block Block object. |
567 * @param array $block Block object. |
151 * @return string Filtered block content. |
568 * @return string Filtered block content. |
152 */ |
569 */ |
153 function wp_render_layout_support_flag( $block_content, $block ) { |
570 function wp_render_layout_support_flag( $block_content, $block ) { |
154 $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] ); |
571 $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] ); |
155 $support_layout = block_has_support( $block_type, array( '__experimentalLayout' ), false ); |
572 $block_supports_layout = block_has_support( $block_type, 'layout', false ) || block_has_support( $block_type, '__experimentalLayout', false ); |
156 |
573 $child_layout = isset( $block['attrs']['style']['layout'] ) ? $block['attrs']['style']['layout'] : null; |
157 if ( ! $support_layout ) { |
574 |
|
575 if ( ! $block_supports_layout && ! $child_layout ) { |
158 return $block_content; |
576 return $block_content; |
159 } |
577 } |
160 |
578 |
161 $block_gap = wp_get_global_settings( array( 'spacing', 'blockGap' ) ); |
579 $outer_class_names = array(); |
162 $default_layout = wp_get_global_settings( array( 'layout' ) ); |
580 |
163 $has_block_gap_support = isset( $block_gap ) ? null !== $block_gap : false; |
581 // Child layout specific logic. |
164 $default_block_layout = _wp_array_get( $block_type->supports, array( '__experimentalLayout', 'default' ), array() ); |
582 if ( $child_layout ) { |
165 $used_layout = isset( $block['attrs']['layout'] ) ? $block['attrs']['layout'] : $default_block_layout; |
583 $container_content_class = wp_unique_prefixed_id( 'wp-container-content-' ); |
166 if ( isset( $used_layout['inherit'] ) && $used_layout['inherit'] ) { |
584 $child_layout_declarations = array(); |
167 if ( ! $default_layout ) { |
585 $child_layout_styles = array(); |
168 return $block_content; |
586 |
169 } |
587 $self_stretch = isset( $child_layout['selfStretch'] ) ? $child_layout['selfStretch'] : null; |
170 $used_layout = $default_layout; |
588 |
171 } |
589 if ( 'fixed' === $self_stretch && isset( $child_layout['flexSize'] ) ) { |
172 |
590 $child_layout_declarations['flex-basis'] = $child_layout['flexSize']; |
173 $class_names = array(); |
591 $child_layout_declarations['box-sizing'] = 'border-box'; |
174 $container_class = wp_unique_id( 'wp-container-' ); |
592 } elseif ( 'fill' === $self_stretch ) { |
175 $class_names[] = $container_class; |
593 $child_layout_declarations['flex-grow'] = '1'; |
176 |
594 } |
177 // The following section was added to reintroduce a small set of layout classnames that were |
595 |
178 // removed in the 5.9 release (https://github.com/WordPress/gutenberg/issues/38719). It is |
596 if ( isset( $child_layout['columnSpan'] ) ) { |
179 // not intended to provide an extended set of classes to match all block layout attributes |
597 $column_span = $child_layout['columnSpan']; |
180 // here. |
598 $child_layout_declarations['grid-column'] = "span $column_span"; |
|
599 } |
|
600 if ( isset( $child_layout['rowSpan'] ) ) { |
|
601 $row_span = $child_layout['rowSpan']; |
|
602 $child_layout_declarations['grid-row'] = "span $row_span"; |
|
603 } |
|
604 $child_layout_styles[] = array( |
|
605 'selector' => ".$container_content_class", |
|
606 'declarations' => $child_layout_declarations, |
|
607 ); |
|
608 |
|
609 /* |
|
610 * If columnSpan is set, and the parent grid is responsive, i.e. if it has a minimumColumnWidth set, |
|
611 * the columnSpan should be removed on small grids. If there's a minimumColumnWidth, the grid is responsive. |
|
612 * But if the minimumColumnWidth value wasn't changed, it won't be set. In that case, if columnCount doesn't |
|
613 * exist, we can assume that the grid is responsive. |
|
614 */ |
|
615 if ( isset( $child_layout['columnSpan'] ) && ( isset( $block['parentLayout']['minimumColumnWidth'] ) || ! isset( $block['parentLayout']['columnCount'] ) ) ) { |
|
616 $column_span_number = floatval( $child_layout['columnSpan'] ); |
|
617 $parent_column_width = isset( $block['parentLayout']['minimumColumnWidth'] ) ? $block['parentLayout']['minimumColumnWidth'] : '12rem'; |
|
618 $parent_column_value = floatval( $parent_column_width ); |
|
619 $parent_column_unit = explode( $parent_column_value, $parent_column_width ); |
|
620 |
|
621 /* |
|
622 * If there is no unit, the width has somehow been mangled so we reset both unit and value |
|
623 * to defaults. |
|
624 * Additionally, the unit should be one of px, rem or em, so that also needs to be checked. |
|
625 */ |
|
626 if ( count( $parent_column_unit ) <= 1 ) { |
|
627 $parent_column_unit = 'rem'; |
|
628 $parent_column_value = 12; |
|
629 } else { |
|
630 $parent_column_unit = $parent_column_unit[1]; |
|
631 |
|
632 if ( ! in_array( $parent_column_unit, array( 'px', 'rem', 'em' ), true ) ) { |
|
633 $parent_column_unit = 'rem'; |
|
634 } |
|
635 } |
|
636 |
|
637 /* |
|
638 * A default gap value is used for this computation because custom gap values may not be |
|
639 * viable to use in the computation of the container query value. |
|
640 */ |
|
641 $default_gap_value = 'px' === $parent_column_unit ? 24 : 1.5; |
|
642 $container_query_value = $column_span_number * $parent_column_value + ( $column_span_number - 1 ) * $default_gap_value; |
|
643 $container_query_value = $container_query_value . $parent_column_unit; |
|
644 |
|
645 $child_layout_styles[] = array( |
|
646 'rules_group' => "@container (max-width: $container_query_value )", |
|
647 'selector' => ".$container_content_class", |
|
648 'declarations' => array( |
|
649 'grid-column' => '1/-1', |
|
650 ), |
|
651 ); |
|
652 } |
|
653 |
|
654 /* |
|
655 * Add to the style engine store to enqueue and render layout styles. |
|
656 * Return styles here just to check if any exist. |
|
657 */ |
|
658 $child_css = wp_style_engine_get_stylesheet_from_css_rules( |
|
659 $child_layout_styles, |
|
660 array( |
|
661 'context' => 'block-supports', |
|
662 'prettify' => false, |
|
663 ) |
|
664 ); |
|
665 |
|
666 if ( $child_css ) { |
|
667 $outer_class_names[] = $container_content_class; |
|
668 } |
|
669 } |
|
670 |
|
671 // Prep the processor for modifying the block output. |
|
672 $processor = new WP_HTML_Tag_Processor( $block_content ); |
|
673 |
|
674 // Having no tags implies there are no tags onto which to add class names. |
|
675 if ( ! $processor->next_tag() ) { |
|
676 return $block_content; |
|
677 } |
|
678 |
|
679 /* |
|
680 * A block may not support layout but still be affected by a parent block's layout. |
|
681 * |
|
682 * In these cases add the appropriate class names and then return early; there's |
|
683 * no need to investigate on this block whether additional layout constraints apply. |
|
684 */ |
|
685 if ( ! $block_supports_layout && ! empty( $outer_class_names ) ) { |
|
686 foreach ( $outer_class_names as $class_name ) { |
|
687 $processor->add_class( $class_name ); |
|
688 } |
|
689 return $processor->get_updated_html(); |
|
690 } elseif ( ! $block_supports_layout ) { |
|
691 // Ensure layout classnames are not injected if there is no layout support. |
|
692 return $block_content; |
|
693 } |
|
694 |
|
695 $global_settings = wp_get_global_settings(); |
|
696 $fallback_layout = isset( $block_type->supports['layout']['default'] ) |
|
697 ? $block_type->supports['layout']['default'] |
|
698 : array(); |
|
699 if ( empty( $fallback_layout ) ) { |
|
700 $fallback_layout = isset( $block_type->supports['__experimentalLayout']['default'] ) |
|
701 ? $block_type->supports['__experimentalLayout']['default'] |
|
702 : array(); |
|
703 } |
|
704 $used_layout = isset( $block['attrs']['layout'] ) ? $block['attrs']['layout'] : $fallback_layout; |
|
705 |
|
706 $class_names = array(); |
|
707 $layout_definitions = wp_get_layout_definitions(); |
|
708 |
|
709 /* |
|
710 * Uses an incremental ID that is independent per prefix to make sure that |
|
711 * rendering different numbers of blocks doesn't affect the IDs of other |
|
712 * blocks. Makes the CSS class names stable across paginations |
|
713 * for features like the enhanced pagination of the Query block. |
|
714 */ |
|
715 $container_class = wp_unique_prefixed_id( |
|
716 'wp-container-' . sanitize_title( $block['blockName'] ) . '-is-layout-' |
|
717 ); |
|
718 |
|
719 // Set the correct layout type for blocks using legacy content width. |
|
720 if ( isset( $used_layout['inherit'] ) && $used_layout['inherit'] || isset( $used_layout['contentSize'] ) && $used_layout['contentSize'] ) { |
|
721 $used_layout['type'] = 'constrained'; |
|
722 } |
|
723 |
|
724 $root_padding_aware_alignments = isset( $global_settings['useRootPaddingAwareAlignments'] ) |
|
725 ? $global_settings['useRootPaddingAwareAlignments'] |
|
726 : false; |
|
727 |
|
728 if ( |
|
729 $root_padding_aware_alignments && |
|
730 isset( $used_layout['type'] ) && |
|
731 'constrained' === $used_layout['type'] |
|
732 ) { |
|
733 $class_names[] = 'has-global-padding'; |
|
734 } |
|
735 |
|
736 /* |
|
737 * The following section was added to reintroduce a small set of layout classnames that were |
|
738 * removed in the 5.9 release (https://github.com/WordPress/gutenberg/issues/38719). It is |
|
739 * not intended to provide an extended set of classes to match all block layout attributes |
|
740 * here. |
|
741 */ |
181 if ( ! empty( $block['attrs']['layout']['orientation'] ) ) { |
742 if ( ! empty( $block['attrs']['layout']['orientation'] ) ) { |
182 $class_names[] = 'is-' . sanitize_title( $block['attrs']['layout']['orientation'] ); |
743 $class_names[] = 'is-' . sanitize_title( $block['attrs']['layout']['orientation'] ); |
183 } |
744 } |
184 |
745 |
185 if ( ! empty( $block['attrs']['layout']['justifyContent'] ) ) { |
746 if ( ! empty( $block['attrs']['layout']['justifyContent'] ) ) { |
188 |
749 |
189 if ( ! empty( $block['attrs']['layout']['flexWrap'] ) && 'nowrap' === $block['attrs']['layout']['flexWrap'] ) { |
750 if ( ! empty( $block['attrs']['layout']['flexWrap'] ) && 'nowrap' === $block['attrs']['layout']['flexWrap'] ) { |
190 $class_names[] = 'is-nowrap'; |
751 $class_names[] = 'is-nowrap'; |
191 } |
752 } |
192 |
753 |
193 $gap_value = _wp_array_get( $block, array( 'attrs', 'style', 'spacing', 'blockGap' ) ); |
754 // Get classname for layout type. |
194 // Skip if gap value contains unsupported characters. |
755 if ( isset( $used_layout['type'] ) ) { |
195 // Regex for CSS value borrowed from `safecss_filter_attr`, and used here |
756 $layout_classname = isset( $layout_definitions[ $used_layout['type'] ]['className'] ) |
196 // because we only want to match against the value, not the CSS attribute. |
757 ? $layout_definitions[ $used_layout['type'] ]['className'] |
197 if ( is_array( $gap_value ) ) { |
758 : ''; |
198 foreach ( $gap_value as $key => $value ) { |
|
199 $gap_value[ $key ] = $value && preg_match( '%[\\\(&=}]|/\*%', $value ) ? null : $value; |
|
200 } |
|
201 } else { |
759 } else { |
202 $gap_value = $gap_value && preg_match( '%[\\\(&=}]|/\*%', $gap_value ) ? null : $gap_value; |
760 $layout_classname = isset( $layout_definitions['default']['className'] ) |
203 } |
761 ? $layout_definitions['default']['className'] |
204 |
762 : ''; |
205 $fallback_gap_value = _wp_array_get( $block_type->supports, array( 'spacing', 'blockGap', '__experimentalDefault' ), '0.5em' ); |
763 } |
206 |
764 |
207 // If a block's block.json skips serialization for spacing or spacing.blockGap, |
765 if ( $layout_classname && is_string( $layout_classname ) ) { |
208 // don't apply the user-defined value to the styles. |
766 $class_names[] = sanitize_title( $layout_classname ); |
209 $should_skip_gap_serialization = wp_should_skip_block_supports_serialization( $block_type, 'spacing', 'blockGap' ); |
767 } |
210 $style = wp_get_layout_style( ".$container_class", $used_layout, $has_block_gap_support, $gap_value, $should_skip_gap_serialization, $fallback_gap_value ); |
768 |
211 // This assumes the hook only applies to blocks with a single wrapper. |
769 /* |
212 // I think this is a reasonable limitation for that particular hook. |
770 * Only generate Layout styles if the theme has not opted-out. |
213 $content = preg_replace( |
771 * Attribute-based Layout classnames are output in all cases. |
214 '/' . preg_quote( 'class="', '/' ) . '/', |
772 */ |
215 'class="' . esc_attr( implode( ' ', $class_names ) ) . ' ', |
773 if ( ! current_theme_supports( 'disable-layout-styles' ) ) { |
216 $block_content, |
774 |
217 1 |
775 $gap_value = isset( $block['attrs']['style']['spacing']['blockGap'] ) |
218 ); |
776 ? $block['attrs']['style']['spacing']['blockGap'] |
219 |
777 : null; |
220 wp_enqueue_block_support_styles( $style ); |
778 /* |
221 |
779 * Skip if gap value contains unsupported characters. |
222 return $content; |
780 * Regex for CSS value borrowed from `safecss_filter_attr`, and used here |
|
781 * to only match against the value, not the CSS attribute. |
|
782 */ |
|
783 if ( is_array( $gap_value ) ) { |
|
784 foreach ( $gap_value as $key => $value ) { |
|
785 $gap_value[ $key ] = $value && preg_match( '%[\\\(&=}]|/\*%', $value ) ? null : $value; |
|
786 } |
|
787 } else { |
|
788 $gap_value = $gap_value && preg_match( '%[\\\(&=}]|/\*%', $gap_value ) ? null : $gap_value; |
|
789 } |
|
790 |
|
791 $fallback_gap_value = isset( $block_type->supports['spacing']['blockGap']['__experimentalDefault'] ) |
|
792 ? $block_type->supports['spacing']['blockGap']['__experimentalDefault'] |
|
793 : '0.5em'; |
|
794 $block_spacing = isset( $block['attrs']['style']['spacing'] ) |
|
795 ? $block['attrs']['style']['spacing'] |
|
796 : null; |
|
797 |
|
798 /* |
|
799 * If a block's block.json skips serialization for spacing or spacing.blockGap, |
|
800 * don't apply the user-defined value to the styles. |
|
801 */ |
|
802 $should_skip_gap_serialization = wp_should_skip_block_supports_serialization( $block_type, 'spacing', 'blockGap' ); |
|
803 |
|
804 $block_gap = isset( $global_settings['spacing']['blockGap'] ) |
|
805 ? $global_settings['spacing']['blockGap'] |
|
806 : null; |
|
807 $has_block_gap_support = isset( $block_gap ); |
|
808 |
|
809 $style = wp_get_layout_style( |
|
810 ".$container_class", |
|
811 $used_layout, |
|
812 $has_block_gap_support, |
|
813 $gap_value, |
|
814 $should_skip_gap_serialization, |
|
815 $fallback_gap_value, |
|
816 $block_spacing |
|
817 ); |
|
818 |
|
819 // Only add container class and enqueue block support styles if unique styles were generated. |
|
820 if ( ! empty( $style ) ) { |
|
821 $class_names[] = $container_class; |
|
822 } |
|
823 } |
|
824 |
|
825 // Add combined layout and block classname for global styles to hook onto. |
|
826 $block_name = explode( '/', $block['blockName'] ); |
|
827 $class_names[] = 'wp-block-' . end( $block_name ) . '-' . $layout_classname; |
|
828 |
|
829 // Add classes to the outermost HTML tag if necessary. |
|
830 if ( ! empty( $outer_class_names ) ) { |
|
831 foreach ( $outer_class_names as $outer_class_name ) { |
|
832 $processor->add_class( $outer_class_name ); |
|
833 } |
|
834 } |
|
835 |
|
836 /** |
|
837 * Attempts to refer to the inner-block wrapping element by its class attribute. |
|
838 * |
|
839 * When examining a block's inner content, if a block has inner blocks, then |
|
840 * the first content item will likely be a text (HTML) chunk immediately |
|
841 * preceding the inner blocks. The last HTML tag in that chunk would then be |
|
842 * an opening tag for an element that wraps the inner blocks. |
|
843 * |
|
844 * There's no reliable way to associate this wrapper in $block_content because |
|
845 * it may have changed during the rendering pipeline (as inner contents is |
|
846 * provided before rendering) and through previous filters. In many cases, |
|
847 * however, the `class` attribute will be a good-enough identifier, so this |
|
848 * code finds the last tag in that chunk and stores the `class` attribute |
|
849 * so that it can be used later when working through the rendered block output |
|
850 * to identify the wrapping element and add the remaining class names to it. |
|
851 * |
|
852 * It's also possible that no inner block wrapper even exists. If that's the |
|
853 * case this code could apply the class names to an invalid element. |
|
854 * |
|
855 * Example: |
|
856 * |
|
857 * $block['innerBlocks'] = array( $list_item ); |
|
858 * $block['innerContent'] = array( '<ul class="list-wrapper is-unordered">', null, '</ul>' ); |
|
859 * |
|
860 * // After rendering, the initial contents may have been modified by other renderers or filters. |
|
861 * $block_content = <<<HTML |
|
862 * <figure> |
|
863 * <ul class="annotated-list list-wrapper is-unordered"> |
|
864 * <li>Code</li> |
|
865 * </ul><figcaption>It's a list!</figcaption> |
|
866 * </figure> |
|
867 * HTML; |
|
868 * |
|
869 * Although it is possible that the original block-wrapper classes are changed in $block_content |
|
870 * from how they appear in $block['innerContent'], it's likely that the original class attributes |
|
871 * are still present in the wrapper as they are in this example. Frequently, additional classes |
|
872 * will also be present; rarely should classes be removed. |
|
873 * |
|
874 * @todo Find a better way to match the first inner block. If it's possible to identify where the |
|
875 * first inner block starts, then it will be possible to find the last tag before it starts |
|
876 * and then that tag, if an opening tag, can be solidly identified as a wrapping element. |
|
877 * Can some unique value or class or ID be added to the inner blocks when they process |
|
878 * so that they can be extracted here safely without guessing? Can the block rendering function |
|
879 * return information about where the rendered inner blocks start? |
|
880 * |
|
881 * @var string|null |
|
882 */ |
|
883 $inner_block_wrapper_classes = null; |
|
884 $first_chunk = isset( $block['innerContent'][0] ) ? $block['innerContent'][0] : null; |
|
885 if ( is_string( $first_chunk ) && count( $block['innerContent'] ) > 1 ) { |
|
886 $first_chunk_processor = new WP_HTML_Tag_Processor( $first_chunk ); |
|
887 while ( $first_chunk_processor->next_tag() ) { |
|
888 $class_attribute = $first_chunk_processor->get_attribute( 'class' ); |
|
889 if ( is_string( $class_attribute ) && ! empty( $class_attribute ) ) { |
|
890 $inner_block_wrapper_classes = $class_attribute; |
|
891 } |
|
892 } |
|
893 } |
|
894 |
|
895 /* |
|
896 * If necessary, advance to what is likely to be an inner block wrapper tag. |
|
897 * |
|
898 * This advances until it finds the first tag containing the original class |
|
899 * attribute from above. If none is found it will scan to the end of the block |
|
900 * and fail to add any class names. |
|
901 * |
|
902 * If there is no block wrapper it won't advance at all, in which case the |
|
903 * class names will be added to the first and outermost tag of the block. |
|
904 * For cases where this outermost tag is the only tag surrounding inner |
|
905 * blocks then the outer wrapper and inner wrapper are the same. |
|
906 */ |
|
907 do { |
|
908 if ( ! $inner_block_wrapper_classes ) { |
|
909 break; |
|
910 } |
|
911 |
|
912 $class_attribute = $processor->get_attribute( 'class' ); |
|
913 if ( is_string( $class_attribute ) && str_contains( $class_attribute, $inner_block_wrapper_classes ) ) { |
|
914 break; |
|
915 } |
|
916 } while ( $processor->next_tag() ); |
|
917 |
|
918 // Add the remaining class names. |
|
919 foreach ( $class_names as $class_name ) { |
|
920 $processor->add_class( $class_name ); |
|
921 } |
|
922 |
|
923 return $processor->get_updated_html(); |
223 } |
924 } |
|
925 |
|
926 /** |
|
927 * Check if the parent block exists and if it has a layout attribute. |
|
928 * If it does, add the parent layout to the parsed block |
|
929 * |
|
930 * @since 6.6.0 |
|
931 * @access private |
|
932 * |
|
933 * @param array $parsed_block The parsed block. |
|
934 * @param array $source_block The source block. |
|
935 * @param WP_Block $parent_block The parent block. |
|
936 * @return array The parsed block with parent layout attribute if it exists. |
|
937 */ |
|
938 function wp_add_parent_layout_to_parsed_block( $parsed_block, $source_block, $parent_block ) { |
|
939 if ( $parent_block && isset( $parent_block->parsed_block['attrs']['layout'] ) ) { |
|
940 $parsed_block['parentLayout'] = $parent_block->parsed_block['attrs']['layout']; |
|
941 } |
|
942 return $parsed_block; |
|
943 } |
|
944 |
|
945 add_filter( 'render_block_data', 'wp_add_parent_layout_to_parsed_block', 10, 3 ); |
224 |
946 |
225 // Register the block support. |
947 // Register the block support. |
226 WP_Block_Supports::get_instance()->register( |
948 WP_Block_Supports::get_instance()->register( |
227 'layout', |
949 'layout', |
228 array( |
950 array( |