[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Layout block support flag. 4 * 5 * @package WordPress 6 * @since 5.8.0 7 */ 8 9 /** 10 * Registers the layout block attribute for block types that support it. 11 * 12 * @since 5.8.0 13 * @access private 14 * 15 * @param WP_Block_Type $block_type Block Type. 16 */ 17 function wp_register_layout_support( $block_type ) { 18 $support_layout = block_has_support( $block_type, array( '__experimentalLayout' ), false ); 19 if ( $support_layout ) { 20 if ( ! $block_type->attributes ) { 21 $block_type->attributes = array(); 22 } 23 24 if ( ! array_key_exists( 'layout', $block_type->attributes ) ) { 25 $block_type->attributes['layout'] = array( 26 'type' => 'object', 27 ); 28 } 29 } 30 } 31 32 /** 33 * Generates the CSS corresponding to the provided layout. 34 * 35 * @since 5.9.0 36 * @since 6.1.0 Added `$block_spacing` param, use style engine to enqueue styles. 37 * @access private 38 * 39 * @param string $selector CSS selector. 40 * @param array $layout Layout object. The one that is passed has already checked 41 * the existence of default block layout. 42 * @param bool $has_block_gap_support Optional. Whether the theme has support for the block gap. Default false. 43 * @param string|string[]|null $gap_value Optional. The block gap value to apply. Default null. 44 * @param bool $should_skip_gap_serialization Optional. Whether to skip applying the user-defined value set in the editor. Default false. 45 * @param string $fallback_gap_value Optional. The block gap value to apply. Default '0.5em'. 46 * @param array|null $block_spacing Optional. Custom spacing set on the block. Default null. 47 * @return string CSS styles on success. Else, empty string. 48 */ 49 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 ) { 50 $layout_type = isset( $layout['type'] ) ? $layout['type'] : 'default'; 51 $layout_styles = array(); 52 53 if ( 'default' === $layout_type ) { 54 if ( $has_block_gap_support ) { 55 if ( is_array( $gap_value ) ) { 56 $gap_value = isset( $gap_value['top'] ) ? $gap_value['top'] : null; 57 } 58 if ( null !== $gap_value && ! $should_skip_gap_serialization ) { 59 // Get spacing CSS variable from preset value if provided. 60 if ( is_string( $gap_value ) && str_contains( $gap_value, 'var:preset|spacing|' ) ) { 61 $index_to_splice = strrpos( $gap_value, '|' ) + 1; 62 $slug = _wp_to_kebab_case( substr( $gap_value, $index_to_splice ) ); 63 $gap_value = "var(--wp--preset--spacing--$slug)"; 64 } 65 66 array_push( 67 $layout_styles, 68 array( 69 'selector' => "$selector > *", 70 'declarations' => array( 71 'margin-block-start' => '0', 72 'margin-block-end' => '0', 73 ), 74 ), 75 array( 76 'selector' => "$selector$selector > * + *", 77 'declarations' => array( 78 'margin-block-start' => $gap_value, 79 'margin-block-end' => '0', 80 ), 81 ) 82 ); 83 } 84 } 85 } elseif ( 'constrained' === $layout_type ) { 86 $content_size = isset( $layout['contentSize'] ) ? $layout['contentSize'] : ''; 87 $wide_size = isset( $layout['wideSize'] ) ? $layout['wideSize'] : ''; 88 $justify_content = isset( $layout['justifyContent'] ) ? $layout['justifyContent'] : 'center'; 89 90 $all_max_width_value = $content_size ? $content_size : $wide_size; 91 $wide_max_width_value = $wide_size ? $wide_size : $content_size; 92 93 // Make sure there is a single CSS rule, and all tags are stripped for security. 94 $all_max_width_value = safecss_filter_attr( explode( ';', $all_max_width_value )[0] ); 95 $wide_max_width_value = safecss_filter_attr( explode( ';', $wide_max_width_value )[0] ); 96 97 $margin_left = 'left' === $justify_content ? '0 !important' : 'auto !important'; 98 $margin_right = 'right' === $justify_content ? '0 !important' : 'auto !important'; 99 100 if ( $content_size || $wide_size ) { 101 array_push( 102 $layout_styles, 103 array( 104 'selector' => "$selector > :where(:not(.alignleft):not(.alignright):not(.alignfull))", 105 'declarations' => array( 106 'max-width' => $all_max_width_value, 107 'margin-left' => $margin_left, 108 'margin-right' => $margin_right, 109 ), 110 ), 111 array( 112 'selector' => "$selector > .alignwide", 113 'declarations' => array( 'max-width' => $wide_max_width_value ), 114 ), 115 array( 116 'selector' => "$selector .alignfull", 117 'declarations' => array( 'max-width' => 'none' ), 118 ) 119 ); 120 121 if ( isset( $block_spacing ) ) { 122 $block_spacing_values = wp_style_engine_get_styles( 123 array( 124 'spacing' => $block_spacing, 125 ) 126 ); 127 128 /* 129 * Handle negative margins for alignfull children of blocks with custom padding set. 130 * They're added separately because padding might only be set on one side. 131 */ 132 if ( isset( $block_spacing_values['declarations']['padding-right'] ) ) { 133 $padding_right = $block_spacing_values['declarations']['padding-right']; 134 $layout_styles[] = array( 135 'selector' => "$selector > .alignfull", 136 'declarations' => array( 'margin-right' => "calc($padding_right * -1)" ), 137 ); 138 } 139 if ( isset( $block_spacing_values['declarations']['padding-left'] ) ) { 140 $padding_left = $block_spacing_values['declarations']['padding-left']; 141 $layout_styles[] = array( 142 'selector' => "$selector > .alignfull", 143 'declarations' => array( 'margin-left' => "calc($padding_left * -1)" ), 144 ); 145 } 146 } 147 } 148 149 if ( 'left' === $justify_content ) { 150 $layout_styles[] = array( 151 'selector' => "$selector > :where(:not(.alignleft):not(.alignright):not(.alignfull))", 152 'declarations' => array( 'margin-left' => '0 !important' ), 153 ); 154 } 155 156 if ( 'right' === $justify_content ) { 157 $layout_styles[] = array( 158 'selector' => "$selector > :where(:not(.alignleft):not(.alignright):not(.alignfull))", 159 'declarations' => array( 'margin-right' => '0 !important' ), 160 ); 161 } 162 163 if ( $has_block_gap_support ) { 164 if ( is_array( $gap_value ) ) { 165 $gap_value = isset( $gap_value['top'] ) ? $gap_value['top'] : null; 166 } 167 if ( null !== $gap_value && ! $should_skip_gap_serialization ) { 168 // Get spacing CSS variable from preset value if provided. 169 if ( is_string( $gap_value ) && str_contains( $gap_value, 'var:preset|spacing|' ) ) { 170 $index_to_splice = strrpos( $gap_value, '|' ) + 1; 171 $slug = _wp_to_kebab_case( substr( $gap_value, $index_to_splice ) ); 172 $gap_value = "var(--wp--preset--spacing--$slug)"; 173 } 174 175 array_push( 176 $layout_styles, 177 array( 178 'selector' => "$selector > *", 179 'declarations' => array( 180 'margin-block-start' => '0', 181 'margin-block-end' => '0', 182 ), 183 ), 184 array( 185 'selector' => "$selector$selector > * + *", 186 'declarations' => array( 187 'margin-block-start' => $gap_value, 188 'margin-block-end' => '0', 189 ), 190 ) 191 ); 192 } 193 } 194 } elseif ( 'flex' === $layout_type ) { 195 $layout_orientation = isset( $layout['orientation'] ) ? $layout['orientation'] : 'horizontal'; 196 197 $justify_content_options = array( 198 'left' => 'flex-start', 199 'right' => 'flex-end', 200 'center' => 'center', 201 ); 202 203 $vertical_alignment_options = array( 204 'top' => 'flex-start', 205 'center' => 'center', 206 'bottom' => 'flex-end', 207 ); 208 209 if ( 'horizontal' === $layout_orientation ) { 210 $justify_content_options += array( 'space-between' => 'space-between' ); 211 $vertical_alignment_options += array( 'stretch' => 'stretch' ); 212 } else { 213 $justify_content_options += array( 'stretch' => 'stretch' ); 214 $vertical_alignment_options += array( 'space-between' => 'space-between' ); 215 } 216 217 if ( ! empty( $layout['flexWrap'] ) && 'nowrap' === $layout['flexWrap'] ) { 218 $layout_styles[] = array( 219 'selector' => $selector, 220 'declarations' => array( 'flex-wrap' => 'nowrap' ), 221 ); 222 } 223 224 if ( $has_block_gap_support && isset( $gap_value ) ) { 225 $combined_gap_value = ''; 226 $gap_sides = is_array( $gap_value ) ? array( 'top', 'left' ) : array( 'top' ); 227 228 foreach ( $gap_sides as $gap_side ) { 229 $process_value = is_string( $gap_value ) ? $gap_value : _wp_array_get( $gap_value, array( $gap_side ), $fallback_gap_value ); 230 // Get spacing CSS variable from preset value if provided. 231 if ( is_string( $process_value ) && str_contains( $process_value, 'var:preset|spacing|' ) ) { 232 $index_to_splice = strrpos( $process_value, '|' ) + 1; 233 $slug = _wp_to_kebab_case( substr( $process_value, $index_to_splice ) ); 234 $process_value = "var(--wp--preset--spacing--$slug)"; 235 } 236 $combined_gap_value .= "$process_value "; 237 } 238 $gap_value = trim( $combined_gap_value ); 239 240 if ( null !== $gap_value && ! $should_skip_gap_serialization ) { 241 $layout_styles[] = array( 242 'selector' => $selector, 243 'declarations' => array( 'gap' => $gap_value ), 244 ); 245 } 246 } 247 248 if ( 'horizontal' === $layout_orientation ) { 249 /* 250 * Add this style only if is not empty for backwards compatibility, 251 * since we intend to convert blocks that had flex layout implemented 252 * by custom css. 253 */ 254 if ( ! empty( $layout['justifyContent'] ) && array_key_exists( $layout['justifyContent'], $justify_content_options ) ) { 255 $layout_styles[] = array( 256 'selector' => $selector, 257 'declarations' => array( 'justify-content' => $justify_content_options[ $layout['justifyContent'] ] ), 258 ); 259 } 260 261 if ( ! empty( $layout['verticalAlignment'] ) && array_key_exists( $layout['verticalAlignment'], $vertical_alignment_options ) ) { 262 $layout_styles[] = array( 263 'selector' => $selector, 264 'declarations' => array( 'align-items' => $vertical_alignment_options[ $layout['verticalAlignment'] ] ), 265 ); 266 } 267 } else { 268 $layout_styles[] = array( 269 'selector' => $selector, 270 'declarations' => array( 'flex-direction' => 'column' ), 271 ); 272 if ( ! empty( $layout['justifyContent'] ) && array_key_exists( $layout['justifyContent'], $justify_content_options ) ) { 273 $layout_styles[] = array( 274 'selector' => $selector, 275 'declarations' => array( 'align-items' => $justify_content_options[ $layout['justifyContent'] ] ), 276 ); 277 } else { 278 $layout_styles[] = array( 279 'selector' => $selector, 280 'declarations' => array( 'align-items' => 'flex-start' ), 281 ); 282 } 283 if ( ! empty( $layout['verticalAlignment'] ) && array_key_exists( $layout['verticalAlignment'], $vertical_alignment_options ) ) { 284 $layout_styles[] = array( 285 'selector' => $selector, 286 'declarations' => array( 'justify-content' => $vertical_alignment_options[ $layout['verticalAlignment'] ] ), 287 ); 288 } 289 } 290 } 291 292 if ( ! empty( $layout_styles ) ) { 293 /* 294 * Add to the style engine store to enqueue and render layout styles. 295 * Return compiled layout styles to retain backwards compatibility. 296 * Since https://github.com/WordPress/gutenberg/pull/42452, 297 * wp_enqueue_block_support_styles is no longer called in this block supports file. 298 */ 299 return wp_style_engine_get_stylesheet_from_css_rules( 300 $layout_styles, 301 array( 302 'context' => 'block-supports', 303 'prettify' => false, 304 ) 305 ); 306 } 307 308 return ''; 309 } 310 311 /** 312 * Renders the layout config to the block wrapper. 313 * 314 * @since 5.8.0 315 * @access private 316 * 317 * @param string $block_content Rendered block content. 318 * @param array $block Block object. 319 * @return string Filtered block content. 320 */ 321 function wp_render_layout_support_flag( $block_content, $block ) { 322 $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] ); 323 $support_layout = block_has_support( $block_type, array( '__experimentalLayout' ), false ); 324 $has_child_layout = isset( $block['attrs']['style']['layout']['selfStretch'] ); 325 326 if ( ! $support_layout && ! $has_child_layout ) { 327 return $block_content; 328 } 329 $outer_class_names = array(); 330 331 if ( $has_child_layout && ( 'fixed' === $block['attrs']['style']['layout']['selfStretch'] || 'fill' === $block['attrs']['style']['layout']['selfStretch'] ) ) { 332 $container_content_class = wp_unique_id( 'wp-container-content-' ); 333 334 $child_layout_styles = array(); 335 336 if ( 'fixed' === $block['attrs']['style']['layout']['selfStretch'] && isset( $block['attrs']['style']['layout']['flexSize'] ) ) { 337 $child_layout_styles[] = array( 338 'selector' => ".$container_content_class", 339 'declarations' => array( 340 'flex-basis' => $block['attrs']['style']['layout']['flexSize'], 341 'box-sizing' => 'border-box', 342 ), 343 ); 344 } elseif ( 'fill' === $block['attrs']['style']['layout']['selfStretch'] ) { 345 $child_layout_styles[] = array( 346 'selector' => ".$container_content_class", 347 'declarations' => array( 348 'flex-grow' => '1', 349 ), 350 ); 351 } 352 353 wp_style_engine_get_stylesheet_from_css_rules( 354 $child_layout_styles, 355 array( 356 'context' => 'block-supports', 357 'prettify' => false, 358 ) 359 ); 360 361 $outer_class_names[] = $container_content_class; 362 } 363 364 // Return early if only child layout exists. 365 if ( ! $support_layout && ! empty( $outer_class_names ) ) { 366 $content = new WP_HTML_Tag_Processor( $block_content ); 367 $content->next_tag(); 368 $content->add_class( implode( ' ', $outer_class_names ) ); 369 return (string) $content; 370 } 371 372 $global_settings = wp_get_global_settings(); 373 $global_layout_settings = _wp_array_get( $global_settings, array( 'layout' ), null ); 374 $used_layout = isset( $block['attrs']['layout'] ) ? $block['attrs']['layout'] : _wp_array_get( $block_type->supports, array( '__experimentalLayout', 'default' ), array() ); 375 376 if ( isset( $used_layout['inherit'] ) && $used_layout['inherit'] && ! $global_layout_settings ) { 377 return $block_content; 378 } 379 380 $class_names = array(); 381 $layout_definitions = _wp_array_get( $global_layout_settings, array( 'definitions' ), array() ); 382 $container_class = wp_unique_id( 'wp-container-' ); 383 $layout_classname = ''; 384 385 // Set the correct layout type for blocks using legacy content width. 386 if ( isset( $used_layout['inherit'] ) && $used_layout['inherit'] || isset( $used_layout['contentSize'] ) && $used_layout['contentSize'] ) { 387 $used_layout['type'] = 'constrained'; 388 } 389 390 $root_padding_aware_alignments = _wp_array_get( $global_settings, array( 'useRootPaddingAwareAlignments' ), false ); 391 392 if ( 393 $root_padding_aware_alignments && 394 isset( $used_layout['type'] ) && 395 'constrained' === $used_layout['type'] 396 ) { 397 $class_names[] = 'has-global-padding'; 398 } 399 400 /* 401 * The following section was added to reintroduce a small set of layout classnames that were 402 * removed in the 5.9 release (https://github.com/WordPress/gutenberg/issues/38719). It is 403 * not intended to provide an extended set of classes to match all block layout attributes 404 * here. 405 */ 406 if ( ! empty( $block['attrs']['layout']['orientation'] ) ) { 407 $class_names[] = 'is-' . sanitize_title( $block['attrs']['layout']['orientation'] ); 408 } 409 410 if ( ! empty( $block['attrs']['layout']['justifyContent'] ) ) { 411 $class_names[] = 'is-content-justification-' . sanitize_title( $block['attrs']['layout']['justifyContent'] ); 412 } 413 414 if ( ! empty( $block['attrs']['layout']['flexWrap'] ) && 'nowrap' === $block['attrs']['layout']['flexWrap'] ) { 415 $class_names[] = 'is-nowrap'; 416 } 417 418 // Get classname for layout type. 419 if ( isset( $used_layout['type'] ) ) { 420 $layout_classname = _wp_array_get( $layout_definitions, array( $used_layout['type'], 'className' ), '' ); 421 } else { 422 $layout_classname = _wp_array_get( $layout_definitions, array( 'default', 'className' ), '' ); 423 } 424 425 if ( $layout_classname && is_string( $layout_classname ) ) { 426 $class_names[] = sanitize_title( $layout_classname ); 427 } 428 429 /* 430 * Only generate Layout styles if the theme has not opted-out. 431 * Attribute-based Layout classnames are output in all cases. 432 */ 433 if ( ! current_theme_supports( 'disable-layout-styles' ) ) { 434 435 $gap_value = _wp_array_get( $block, array( 'attrs', 'style', 'spacing', 'blockGap' ) ); 436 /* 437 * Skip if gap value contains unsupported characters. 438 * Regex for CSS value borrowed from `safecss_filter_attr`, and used here 439 * to only match against the value, not the CSS attribute. 440 */ 441 if ( is_array( $gap_value ) ) { 442 foreach ( $gap_value as $key => $value ) { 443 $gap_value[ $key ] = $value && preg_match( '%[\\\(&=}]|/\*%', $value ) ? null : $value; 444 } 445 } else { 446 $gap_value = $gap_value && preg_match( '%[\\\(&=}]|/\*%', $gap_value ) ? null : $gap_value; 447 } 448 449 $fallback_gap_value = _wp_array_get( $block_type->supports, array( 'spacing', 'blockGap', '__experimentalDefault' ), '0.5em' ); 450 $block_spacing = _wp_array_get( $block, array( 'attrs', 'style', 'spacing' ), null ); 451 452 /* 453 * If a block's block.json skips serialization for spacing or spacing.blockGap, 454 * don't apply the user-defined value to the styles. 455 */ 456 $should_skip_gap_serialization = wp_should_skip_block_supports_serialization( $block_type, 'spacing', 'blockGap' ); 457 458 $block_gap = _wp_array_get( $global_settings, array( 'spacing', 'blockGap' ), null ); 459 $has_block_gap_support = isset( $block_gap ); 460 461 $style = wp_get_layout_style( 462 ".$container_class.$container_class", 463 $used_layout, 464 $has_block_gap_support, 465 $gap_value, 466 $should_skip_gap_serialization, 467 $fallback_gap_value, 468 $block_spacing 469 ); 470 471 // Only add container class and enqueue block support styles if unique styles were generated. 472 if ( ! empty( $style ) ) { 473 $class_names[] = $container_class; 474 } 475 } 476 477 $content_with_outer_classnames = ''; 478 479 if ( ! empty( $outer_class_names ) ) { 480 $content_with_outer_classnames = new WP_HTML_Tag_Processor( $block_content ); 481 $content_with_outer_classnames->next_tag(); 482 foreach ( $outer_class_names as $outer_class_name ) { 483 $content_with_outer_classnames->add_class( $outer_class_name ); 484 } 485 486 $content_with_outer_classnames = (string) $content_with_outer_classnames; 487 } 488 489 /** 490 * The first chunk of innerContent contains the block markup up until the inner blocks start. 491 * This targets the opening tag of the inner blocks wrapper, which is the last tag in that chunk. 492 */ 493 $inner_content_classnames = ''; 494 495 if ( isset( $block['innerContent'][0] ) && 'string' === gettype( $block['innerContent'][0] ) && count( $block['innerContent'] ) > 1 ) { 496 $tags = new WP_HTML_Tag_Processor( $block['innerContent'][0] ); 497 $last_classnames = ''; 498 while ( $tags->next_tag() ) { 499 $last_classnames = $tags->get_attribute( 'class' ); 500 } 501 502 $inner_content_classnames = (string) $last_classnames; 503 } 504 505 $content = $content_with_outer_classnames ? new WP_HTML_Tag_Processor( $content_with_outer_classnames ) : new WP_HTML_Tag_Processor( $block_content ); 506 507 if ( $inner_content_classnames ) { 508 $content->next_tag( array( 'class_name' => $inner_content_classnames ) ); 509 foreach ( $class_names as $class_name ) { 510 $content->add_class( $class_name ); 511 } 512 } else { 513 $content->next_tag(); 514 foreach ( $class_names as $class_name ) { 515 $content->add_class( $class_name ); 516 } 517 } 518 519 return (string) $content; 520 } 521 522 // Register the block support. 523 WP_Block_Supports::get_instance()->register( 524 'layout', 525 array( 526 'register_attribute' => 'wp_register_layout_support', 527 ) 528 ); 529 add_filter( 'render_block', 'wp_render_layout_support_flag', 10, 2 ); 530 531 /** 532 * For themes without theme.json file, make sure 533 * to restore the inner div for the group block 534 * to avoid breaking styles relying on that div. 535 * 536 * @since 5.8.0 537 * @access private 538 * 539 * @param string $block_content Rendered block content. 540 * @param array $block Block object. 541 * @return string Filtered block content. 542 */ 543 function wp_restore_group_inner_container( $block_content, $block ) { 544 $tag_name = isset( $block['attrs']['tagName'] ) ? $block['attrs']['tagName'] : 'div'; 545 $group_with_inner_container_regex = sprintf( 546 '/(^\s*<%1$s\b[^>]*wp-block-group(\s|")[^>]*>)(\s*<div\b[^>]*wp-block-group__inner-container(\s|")[^>]*>)((.|\S|\s)*)/U', 547 preg_quote( $tag_name, '/' ) 548 ); 549 550 if ( 551 wp_theme_has_theme_json() || 552 1 === preg_match( $group_with_inner_container_regex, $block_content ) || 553 ( isset( $block['attrs']['layout']['type'] ) && 'flex' === $block['attrs']['layout']['type'] ) 554 ) { 555 return $block_content; 556 } 557 558 $replace_regex = sprintf( 559 '/(^\s*<%1$s\b[^>]*wp-block-group[^>]*>)(.*)(<\/%1$s>\s*$)/ms', 560 preg_quote( $tag_name, '/' ) 561 ); 562 $updated_content = preg_replace_callback( 563 $replace_regex, 564 static function( $matches ) { 565 return $matches[1] . '<div class="wp-block-group__inner-container">' . $matches[2] . '</div>' . $matches[3]; 566 }, 567 $block_content 568 ); 569 return $updated_content; 570 } 571 572 add_filter( 'render_block_core/group', 'wp_restore_group_inner_container', 10, 2 ); 573 574 /** 575 * For themes without theme.json file, make sure 576 * to restore the outer div for the aligned image block 577 * to avoid breaking styles relying on that div. 578 * 579 * @since 6.0.0 580 * @access private 581 * 582 * @param string $block_content Rendered block content. 583 * @param array $block Block object. 584 * @return string Filtered block content. 585 */ 586 function wp_restore_image_outer_container( $block_content, $block ) { 587 $image_with_align = " 588 /# 1) everything up to the class attribute contents 589 ( 590 ^\s* 591 <figure\b 592 [^>]* 593 \bclass= 594 [\"'] 595 ) 596 # 2) the class attribute contents 597 ( 598 [^\"']* 599 \bwp-block-image\b 600 [^\"']* 601 \b(?:alignleft|alignright|aligncenter)\b 602 [^\"']* 603 ) 604 # 3) everything after the class attribute contents 605 ( 606 [\"'] 607 [^>]* 608 > 609 .* 610 <\/figure> 611 )/iUx"; 612 613 if ( 614 wp_theme_has_theme_json() || 615 0 === preg_match( $image_with_align, $block_content, $matches ) 616 ) { 617 return $block_content; 618 } 619 620 $wrapper_classnames = array( 'wp-block-image' ); 621 622 // If the block has a classNames attribute these classnames need to be removed from the content and added back 623 // to the new wrapper div also. 624 if ( ! empty( $block['attrs']['className'] ) ) { 625 $wrapper_classnames = array_merge( $wrapper_classnames, explode( ' ', $block['attrs']['className'] ) ); 626 } 627 $content_classnames = explode( ' ', $matches[2] ); 628 $filtered_content_classnames = array_diff( $content_classnames, $wrapper_classnames ); 629 630 return '<div class="' . implode( ' ', $wrapper_classnames ) . '">' . $matches[1] . implode( ' ', $filtered_content_classnames ) . $matches[3] . '</div>'; 631 } 632 633 add_filter( 'render_block_core/image', 'wp_restore_image_outer_container', 10, 2 );
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Sun Jun 4 08:20:02 2023 | Cross-referenced by PHPXref |