generated-classname.php 0000644 00000003353 15237752303 0011172 0 ustar 00 name ); if ( $block_classname ) { $attributes['class'] = $block_classname; } } return $attributes; } // Register the block support. WP_Block_Supports::get_instance()->register( 'generated-classname', array( 'apply' => 'wp_apply_generated_classname_support', ) ); border.php 0000644 00000013410 15237752303 0006540 0 ustar 00 attributes ) { $block_type->attributes = array(); } if ( $has_border_support && ! array_key_exists( 'style', $block_type->attributes ) ) { $block_type->attributes['style'] = array( 'type' => 'object', ); } if ( $has_border_color_support && ! array_key_exists( 'borderColor', $block_type->attributes ) ) { $block_type->attributes['borderColor'] = array( 'type' => 'string', ); } } /** * Adds CSS classes and inline styles for border styles to the incoming * attributes array. This will be applied to the block markup in the front-end. * * @since 5.8.0 * @access private * * @param WP_Block_Type $block_type Block type. * @param array $block_attributes Block attributes. * @return array Border CSS classes and inline styles. */ function wp_apply_border_support( $block_type, $block_attributes ) { if ( wp_should_skip_block_supports_serialization( $block_type, 'border' ) ) { return array(); } $classes = array(); $styles = array(); // Border radius. if ( wp_has_border_feature_support( $block_type, 'radius' ) && isset( $block_attributes['style']['border']['radius'] ) && ! wp_should_skip_block_supports_serialization( $block_type, '__experimentalBorder', 'radius' ) ) { $border_radius = $block_attributes['style']['border']['radius']; if ( is_array( $border_radius ) ) { // We have individual border radius corner values. foreach ( $border_radius as $key => $radius ) { // Convert CamelCase corner name to kebab-case. $corner = strtolower( preg_replace( '/(?supports, array( '__experimentalBorder' ), $default_value ) ) ) { return true; } // Check if the specific feature has been opted into individually // via nested flag under `__experimentalBorder`. return block_has_support( $block_type, array( '__experimentalBorder', $feature ), $default_value ); } // Register the block support. WP_Block_Supports::get_instance()->register( 'border', array( 'register_attribute' => 'wp_register_border_support', 'apply' => 'wp_apply_border_support', ) ); duotone.php 0000644 00000037012 15237752303 0006744 0 ustar 00 = 0 && $n <= 1 ) { return $n; } } return 1; } /** * Rounds and converts values of an RGB object. * * Direct port of TinyColor's function, lightly simplified to maintain * consistency with TinyColor. * * @see https://github.com/bgrins/TinyColor * * @since 5.8.0 * @access private * * @param array $rgb_color RGB object. * @return array Rounded and converted RGB object. */ function wp_tinycolor_rgb_to_rgb( $rgb_color ) { return array( 'r' => wp_tinycolor_bound01( $rgb_color['r'], 255 ) * 255, 'g' => wp_tinycolor_bound01( $rgb_color['g'], 255 ) * 255, 'b' => wp_tinycolor_bound01( $rgb_color['b'], 255 ) * 255, ); } /** * Helper function for hsl to rgb conversion. * * Direct port of TinyColor's function, lightly simplified to maintain * consistency with TinyColor. * * @see https://github.com/bgrins/TinyColor * * @since 5.8.0 * @access private * * @param float $p first component. * @param float $q second component. * @param float $t third component. * @return float R, G, or B component. */ function wp_tinycolor_hue_to_rgb( $p, $q, $t ) { if ( $t < 0 ) { $t += 1; } if ( $t > 1 ) { $t -= 1; } if ( $t < 1 / 6 ) { return $p + ( $q - $p ) * 6 * $t; } if ( $t < 1 / 2 ) { return $q; } if ( $t < 2 / 3 ) { return $p + ( $q - $p ) * ( 2 / 3 - $t ) * 6; } return $p; } /** * Converts an HSL object to an RGB object with converted and rounded values. * * Direct port of TinyColor's function, lightly simplified to maintain * consistency with TinyColor. * * @see https://github.com/bgrins/TinyColor * * @since 5.8.0 * @access private * * @param array $hsl_color HSL object. * @return array Rounded and converted RGB object. */ function wp_tinycolor_hsl_to_rgb( $hsl_color ) { $h = wp_tinycolor_bound01( $hsl_color['h'], 360 ); $s = wp_tinycolor_bound01( $hsl_color['s'], 100 ); $l = wp_tinycolor_bound01( $hsl_color['l'], 100 ); if ( 0 === $s ) { // Achromatic. $r = $l; $g = $l; $b = $l; } else { $q = $l < 0.5 ? $l * ( 1 + $s ) : $l + $s - $l * $s; $p = 2 * $l - $q; $r = wp_tinycolor_hue_to_rgb( $p, $q, $h + 1 / 3 ); $g = wp_tinycolor_hue_to_rgb( $p, $q, $h ); $b = wp_tinycolor_hue_to_rgb( $p, $q, $h - 1 / 3 ); } return array( 'r' => $r * 255, 'g' => $g * 255, 'b' => $b * 255, ); } /** * Parses hex, hsl, and rgb CSS strings using the same regex as TinyColor v1.4.2 * used in the JavaScript. Only colors output from react-color are implemented. * * Direct port of TinyColor's function, lightly simplified to maintain * consistency with TinyColor. * * @see https://github.com/bgrins/TinyColor * @see https://github.com/casesandberg/react-color/ * * @since 5.8.0 * @since 5.9.0 Added alpha processing. * @access private * * @param string $color_str CSS color string. * @return array RGB object. */ function wp_tinycolor_string_to_rgb( $color_str ) { $color_str = strtolower( trim( $color_str ) ); $css_integer = '[-\\+]?\\d+%?'; $css_number = '[-\\+]?\\d*\\.\\d+%?'; $css_unit = '(?:' . $css_number . ')|(?:' . $css_integer . ')'; $permissive_match3 = '[\\s|\\(]+(' . $css_unit . ')[,|\\s]+(' . $css_unit . ')[,|\\s]+(' . $css_unit . ')\\s*\\)?'; $permissive_match4 = '[\\s|\\(]+(' . $css_unit . ')[,|\\s]+(' . $css_unit . ')[,|\\s]+(' . $css_unit . ')[,|\\s]+(' . $css_unit . ')\\s*\\)?'; $rgb_regexp = '/^rgb' . $permissive_match3 . '$/'; if ( preg_match( $rgb_regexp, $color_str, $match ) ) { $rgb = wp_tinycolor_rgb_to_rgb( array( 'r' => $match[1], 'g' => $match[2], 'b' => $match[3], ) ); $rgb['a'] = 1; return $rgb; } $rgba_regexp = '/^rgba' . $permissive_match4 . '$/'; if ( preg_match( $rgba_regexp, $color_str, $match ) ) { $rgb = wp_tinycolor_rgb_to_rgb( array( 'r' => $match[1], 'g' => $match[2], 'b' => $match[3], ) ); $rgb['a'] = _wp_tinycolor_bound_alpha( $match[4] ); return $rgb; } $hsl_regexp = '/^hsl' . $permissive_match3 . '$/'; if ( preg_match( $hsl_regexp, $color_str, $match ) ) { $rgb = wp_tinycolor_hsl_to_rgb( array( 'h' => $match[1], 's' => $match[2], 'l' => $match[3], ) ); $rgb['a'] = 1; return $rgb; } $hsla_regexp = '/^hsla' . $permissive_match4 . '$/'; if ( preg_match( $hsla_regexp, $color_str, $match ) ) { $rgb = wp_tinycolor_hsl_to_rgb( array( 'h' => $match[1], 's' => $match[2], 'l' => $match[3], ) ); $rgb['a'] = _wp_tinycolor_bound_alpha( $match[4] ); return $rgb; } $hex8_regexp = '/^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/'; if ( preg_match( $hex8_regexp, $color_str, $match ) ) { $rgb = wp_tinycolor_rgb_to_rgb( array( 'r' => base_convert( $match[1], 16, 10 ), 'g' => base_convert( $match[2], 16, 10 ), 'b' => base_convert( $match[3], 16, 10 ), ) ); $rgb['a'] = _wp_tinycolor_bound_alpha( base_convert( $match[4], 16, 10 ) / 255 ); return $rgb; } $hex6_regexp = '/^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/'; if ( preg_match( $hex6_regexp, $color_str, $match ) ) { $rgb = wp_tinycolor_rgb_to_rgb( array( 'r' => base_convert( $match[1], 16, 10 ), 'g' => base_convert( $match[2], 16, 10 ), 'b' => base_convert( $match[3], 16, 10 ), ) ); $rgb['a'] = 1; return $rgb; } $hex4_regexp = '/^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/'; if ( preg_match( $hex4_regexp, $color_str, $match ) ) { $rgb = wp_tinycolor_rgb_to_rgb( array( 'r' => base_convert( $match[1] . $match[1], 16, 10 ), 'g' => base_convert( $match[2] . $match[2], 16, 10 ), 'b' => base_convert( $match[3] . $match[3], 16, 10 ), ) ); $rgb['a'] = _wp_tinycolor_bound_alpha( base_convert( $match[4] . $match[4], 16, 10 ) / 255 ); return $rgb; } $hex3_regexp = '/^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/'; if ( preg_match( $hex3_regexp, $color_str, $match ) ) { $rgb = wp_tinycolor_rgb_to_rgb( array( 'r' => base_convert( $match[1] . $match[1], 16, 10 ), 'g' => base_convert( $match[2] . $match[2], 16, 10 ), 'b' => base_convert( $match[3] . $match[3], 16, 10 ), ) ); $rgb['a'] = 1; return $rgb; } /* * The JS color picker considers the string "transparent" to be a hex value, * so we need to handle it here as a special case. */ if ( 'transparent' === $color_str ) { return array( 'r' => 0, 'g' => 0, 'b' => 0, 'a' => 0, ); } } /** * Returns the prefixed id for the duotone filter for use as a CSS id. * * @since 5.9.1 * @access private * * @param array $preset Duotone preset value as seen in theme.json. * @return string Duotone filter CSS id. */ function wp_get_duotone_filter_id( $preset ) { if ( ! isset( $preset['slug'] ) ) { return ''; } return 'wp-duotone-' . $preset['slug']; } /** * Returns the CSS filter property url to reference the rendered SVG. * * @since 5.9.0 * @access private * * @param array $preset Duotone preset value as seen in theme.json. * @return string Duotone CSS filter property url value. */ function wp_get_duotone_filter_property( $preset ) { $filter_id = wp_get_duotone_filter_id( $preset ); return "url('#" . $filter_id . "')"; } /** * Returns the duotone filter SVG string for the preset. * * @since 5.9.1 * @access private * * @param array $preset Duotone preset value as seen in theme.json. * @return string Duotone SVG filter. */ function wp_get_duotone_filter_svg( $preset ) { $filter_id = wp_get_duotone_filter_id( $preset ); $duotone_values = array( 'r' => array(), 'g' => array(), 'b' => array(), 'a' => array(), ); if ( ! isset( $preset['colors'] ) || ! is_array( $preset['colors'] ) ) { $preset['colors'] = array(); } foreach ( $preset['colors'] as $color_str ) { $color = wp_tinycolor_string_to_rgb( $color_str ); $duotone_values['r'][] = $color['r'] / 255; $duotone_values['g'][] = $color['g'] / 255; $duotone_values['b'][] = $color['b'] / 255; $duotone_values['a'][] = $color['a']; } ob_start(); ?> ', '><', $svg ); $svg = trim( $svg ); } return $svg; } /** * Registers the style and colors block attributes for block types that support it. * * @since 5.8.0 * @access private * * @param WP_Block_Type $block_type Block Type. */ function wp_register_duotone_support( $block_type ) { $has_duotone_support = false; if ( property_exists( $block_type, 'supports' ) ) { $has_duotone_support = _wp_array_get( $block_type->supports, array( 'color', '__experimentalDuotone' ), false ); } if ( $has_duotone_support ) { if ( ! $block_type->attributes ) { $block_type->attributes = array(); } if ( ! array_key_exists( 'style', $block_type->attributes ) ) { $block_type->attributes['style'] = array( 'type' => 'object', ); } } } /** * Render out the duotone stylesheet and SVG. * * @since 5.8.0 * @access private * * @param string $block_content Rendered block content. * @param array $block Block object. * @return string Filtered block content. */ function wp_render_duotone_support( $block_content, $block ) { $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] ); $duotone_support = false; if ( $block_type && property_exists( $block_type, 'supports' ) ) { $duotone_support = _wp_array_get( $block_type->supports, array( 'color', '__experimentalDuotone' ), false ); } $has_duotone_attribute = isset( $block['attrs']['style']['color']['duotone'] ); if ( ! $duotone_support || ! $has_duotone_attribute ) { return $block_content; } $filter_preset = array( 'slug' => wp_unique_id( sanitize_key( implode( '-', $block['attrs']['style']['color']['duotone'] ) . '-' ) ), 'colors' => $block['attrs']['style']['color']['duotone'], ); $filter_property = wp_get_duotone_filter_property( $filter_preset ); $filter_id = wp_get_duotone_filter_id( $filter_preset ); $filter_svg = wp_get_duotone_filter_svg( $filter_preset ); $scope = '.' . $filter_id; $selectors = explode( ',', $duotone_support ); $scoped = array(); foreach ( $selectors as $sel ) { $scoped[] = $scope . ' ' . trim( $sel ); } $selector = implode( ', ', $scoped ); // !important is needed because these styles render before global styles, // and they should be overriding the duotone filters set by global styles. $filter_style = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? $selector . " {\n\tfilter: " . $filter_property . " !important;\n}\n" : $selector . '{filter:' . $filter_property . ' !important;}'; wp_register_style( $filter_id, false, array(), true, true ); wp_add_inline_style( $filter_id, $filter_style ); wp_enqueue_style( $filter_id ); add_action( 'wp_footer', static function () use ( $filter_svg, $selector ) { echo $filter_svg; /* * Safari renders elements incorrectly on first paint when the SVG * filter comes after the content that it is filtering, so we force * a repaint with a WebKit hack which solves the issue. */ global $is_safari; if ( $is_safari ) { printf( // Simply accessing el.offsetHeight flushes layout and style // changes in WebKit without having to wait for setTimeout. '', wp_json_encode( $selector ) ); } } ); // Like the layout hook, this assumes the hook only applies to blocks with a single wrapper. return preg_replace( '/' . preg_quote( 'class="', '/' ) . '/', 'class="' . $filter_id . ' ', $block_content, 1 ); } // Register the block support. WP_Block_Supports::get_instance()->register( 'duotone', array( 'register_attribute' => 'wp_register_duotone_support', ) ); add_filter( 'render_block', 'wp_render_duotone_support', 10, 2 ); custom-classname.php 0000644 00000003234 15237752303 0010544 0 ustar 00 attributes ) { $block_type->attributes = array(); } if ( ! array_key_exists( 'className', $block_type->attributes ) ) { $block_type->attributes['className'] = array( 'type' => 'string', ); } } } /** * Add the custom classnames to the output. * * @since 5.6.0 * @access private * * @param WP_Block_Type $block_type Block Type. * @param array $block_attributes Block attributes. * * @return array Block CSS classes and inline styles. */ function wp_apply_custom_classname_support( $block_type, $block_attributes ) { $has_custom_classname_support = block_has_support( $block_type, array( 'customClassName' ), true ); $attributes = array(); if ( $has_custom_classname_support ) { $has_custom_classnames = array_key_exists( 'className', $block_attributes ); if ( $has_custom_classnames ) { $attributes['class'] = $block_attributes['className']; } } return $attributes; } // Register the block support. WP_Block_Supports::get_instance()->register( 'custom-classname', array( 'register_attribute' => 'wp_register_custom_classname_support', 'apply' => 'wp_apply_custom_classname_support', ) ); utils.php 0000644 00000001766 15237752303 0006436 0 ustar 00 supports, $path, false ); if ( is_array( $skip_serialization ) ) { return in_array( $feature, $skip_serialization, true ); } return $skip_serialization; } elements.php 0000644 00000010722 15237752303 0007102 0 ustar 00 get_registered( $block['blockName'] ); $skip_link_color_serialization = wp_should_skip_block_supports_serialization( $block_type, 'color', 'link' ); if ( $skip_link_color_serialization ) { return $block_content; } $link_color = null; if ( ! empty( $block['attrs'] ) ) { $link_color = _wp_array_get( $block['attrs'], array( 'style', 'elements', 'link', 'color', 'text' ), null ); } /* * For now we only care about link color. * This code in the future when we have a public API * should take advantage of WP_Theme_JSON::compute_style_properties * and work for any element and style. */ if ( null === $link_color ) { return $block_content; } $class_name = wp_get_elements_class_name( $block ); // Like the layout hook this assumes the hook only applies to blocks with a single wrapper. // Retrieve the opening tag of the first HTML element. $html_element_matches = array(); preg_match( '/<[^>]+>/', $block_content, $html_element_matches, PREG_OFFSET_CAPTURE ); $first_element = $html_element_matches[0][0]; // If the first HTML element has a class attribute just add the new class // as we do on layout and duotone. if ( strpos( $first_element, 'class="' ) !== false ) { $content = preg_replace( '/' . preg_quote( 'class="', '/' ) . '/', 'class="' . $class_name . ' ', $block_content, 1 ); } else { // If the first HTML element has no class attribute we should inject the attribute before the attribute at the end. $first_element_offset = $html_element_matches[0][1]; $content = substr_replace( $block_content, ' class="' . $class_name . '"', $first_element_offset + strlen( $first_element ) - 1, 0 ); } return $content; } /** * Render the elements stylesheet. * * In the case of nested blocks we want the parent element styles to be rendered before their descendants. * This solves the issue of an element (e.g.: link color) being styled in both the parent and a descendant: * we want the descendant style to take priority, and this is done by loading it after, in DOM order. * * @since 6.0.0 * @access private * * @param string|null $pre_render The pre-rendered content. Default null. * @param array $block The block being rendered. * * @return null */ function wp_render_elements_support_styles( $pre_render, $block ) { $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] ); $skip_link_color_serialization = wp_should_skip_block_supports_serialization( $block_type, 'color', 'link' ); if ( $skip_link_color_serialization ) { return null; } $link_color = null; if ( ! empty( $block['attrs'] ) ) { $link_color = _wp_array_get( $block['attrs'], array( 'style', 'elements', 'link', 'color', 'text' ), null ); } /* * For now we only care about link color. * This code in the future when we have a public API * should take advantage of WP_Theme_JSON::compute_style_properties * and work for any element and style. */ if ( null === $link_color ) { return null; } $class_name = wp_get_elements_class_name( $block ); if ( strpos( $link_color, 'var:preset|color|' ) !== false ) { // Get the name from the string and add proper styles. $index_to_splice = strrpos( $link_color, '|' ) + 1; $link_color_name = substr( $link_color, $index_to_splice ); $link_color = "var(--wp--preset--color--$link_color_name)"; } $link_color_declaration = esc_html( safecss_filter_attr( "color: $link_color" ) ); $style = ".$class_name a{" . $link_color_declaration . ';}'; wp_enqueue_block_support_styles( $style ); return null; } add_filter( 'render_block', 'wp_render_elements_support', 10, 2 ); add_filter( 'pre_render_block', 'wp_render_elements_support_styles', 10, 2 ); layout.php 0000644 00000030455 15237752303 0006610 0 ustar 00 attributes ) { $block_type->attributes = array(); } if ( ! array_key_exists( 'layout', $block_type->attributes ) ) { $block_type->attributes['layout'] = array( 'type' => 'object', ); } } } /** * Generates the CSS corresponding to the provided layout. * * @since 5.9.0 * @access private * * @param string $selector CSS selector. * @param array $layout Layout object. The one that is passed has already checked * the existence of default block layout. * @param boolean $has_block_gap_support Whether the theme has support for the block gap. * @param string $gap_value The block gap value to apply. * @param boolean $should_skip_gap_serialization Whether to skip applying the user-defined value set in the editor. * @param string $fallback_gap_value The custom fallback value for block gap. * @return string CSS style. */ 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' ) { $layout_type = isset( $layout['type'] ) ? $layout['type'] : 'default'; $style = ''; if ( 'default' === $layout_type ) { $content_size = isset( $layout['contentSize'] ) ? $layout['contentSize'] : ''; $wide_size = isset( $layout['wideSize'] ) ? $layout['wideSize'] : ''; $all_max_width_value = $content_size ? $content_size : $wide_size; $wide_max_width_value = $wide_size ? $wide_size : $content_size; // Make sure there is a single CSS rule, and all tags are stripped for security. $all_max_width_value = safecss_filter_attr( explode( ';', $all_max_width_value )[0] ); $wide_max_width_value = safecss_filter_attr( explode( ';', $wide_max_width_value )[0] ); if ( $content_size || $wide_size ) { $style = "$selector > :where(:not(.alignleft):not(.alignright)) {"; $style .= 'max-width: ' . esc_html( $all_max_width_value ) . ';'; $style .= 'margin-left: auto !important;'; $style .= 'margin-right: auto !important;'; $style .= '}'; $style .= "$selector > .alignwide { max-width: " . esc_html( $wide_max_width_value ) . ';}'; $style .= "$selector .alignfull { max-width: none; }"; } $style .= "$selector > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }"; $style .= "$selector > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }"; $style .= "$selector > .aligncenter { margin-left: auto !important; margin-right: auto !important; }"; if ( $has_block_gap_support ) { if ( is_array( $gap_value ) ) { $gap_value = isset( $gap_value['top'] ) ? $gap_value['top'] : null; } $gap_style = $gap_value && ! $should_skip_gap_serialization ? $gap_value : 'var( --wp--style--block-gap )'; $style .= "$selector > * { margin-block-start: 0; margin-block-end: 0; }"; $style .= "$selector > * + * { margin-block-start: $gap_style; margin-block-end: 0; }"; } } elseif ( 'flex' === $layout_type ) { $layout_orientation = isset( $layout['orientation'] ) ? $layout['orientation'] : 'horizontal'; $justify_content_options = array( 'left' => 'flex-start', 'right' => 'flex-end', 'center' => 'center', ); if ( 'horizontal' === $layout_orientation ) { $justify_content_options += array( 'space-between' => 'space-between' ); } $flex_wrap_options = array( 'wrap', 'nowrap' ); $flex_wrap = ! empty( $layout['flexWrap'] ) && in_array( $layout['flexWrap'], $flex_wrap_options, true ) ? $layout['flexWrap'] : 'wrap'; $style = "$selector {"; $style .= 'display: flex;'; if ( $has_block_gap_support ) { if ( is_array( $gap_value ) ) { $gap_row = isset( $gap_value['top'] ) ? $gap_value['top'] : $fallback_gap_value; $gap_column = isset( $gap_value['left'] ) ? $gap_value['left'] : $fallback_gap_value; $gap_value = $gap_row === $gap_column ? $gap_row : $gap_row . ' ' . $gap_column; } $gap_style = $gap_value && ! $should_skip_gap_serialization ? $gap_value : "var( --wp--style--block-gap, $fallback_gap_value )"; $style .= "gap: $gap_style;"; } else { $style .= "gap: $fallback_gap_value;"; } $style .= "flex-wrap: $flex_wrap;"; if ( 'horizontal' === $layout_orientation ) { $style .= 'align-items: center;'; /** * Add this style only if is not empty for backwards compatibility, * since we intend to convert blocks that had flex layout implemented * by custom css. */ if ( ! empty( $layout['justifyContent'] ) && array_key_exists( $layout['justifyContent'], $justify_content_options ) ) { $style .= "justify-content: {$justify_content_options[ $layout['justifyContent'] ]};"; } } else { $style .= 'flex-direction: column;'; if ( ! empty( $layout['justifyContent'] ) && array_key_exists( $layout['justifyContent'], $justify_content_options ) ) { $style .= "align-items: {$justify_content_options[ $layout['justifyContent'] ]};"; } else { $style .= 'align-items: flex-start;'; } } $style .= '}'; $style .= "$selector > * { margin: 0; }"; } return $style; } /** * Renders the layout config to the block wrapper. * * @since 5.8.0 * @access private * * @param string $block_content Rendered block content. * @param array $block Block object. * @return string Filtered block content. */ function wp_render_layout_support_flag( $block_content, $block ) { $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] ); $support_layout = block_has_support( $block_type, array( '__experimentalLayout' ), false ); if ( ! $support_layout ) { return $block_content; } $block_gap = wp_get_global_settings( array( 'spacing', 'blockGap' ) ); $default_layout = wp_get_global_settings( array( 'layout' ) ); $has_block_gap_support = isset( $block_gap ) ? null !== $block_gap : false; $default_block_layout = _wp_array_get( $block_type->supports, array( '__experimentalLayout', 'default' ), array() ); $used_layout = isset( $block['attrs']['layout'] ) ? $block['attrs']['layout'] : $default_block_layout; if ( isset( $used_layout['inherit'] ) && $used_layout['inherit'] ) { if ( ! $default_layout ) { return $block_content; } $used_layout = $default_layout; } $class_names = array(); $container_class = wp_unique_id( 'wp-container-' ); $class_names[] = $container_class; // The following section was added to reintroduce a small set of layout classnames that were // removed in the 5.9 release (https://github.com/WordPress/gutenberg/issues/38719). It is // not intended to provide an extended set of classes to match all block layout attributes // here. if ( ! empty( $block['attrs']['layout']['orientation'] ) ) { $class_names[] = 'is-' . sanitize_title( $block['attrs']['layout']['orientation'] ); } if ( ! empty( $block['attrs']['layout']['justifyContent'] ) ) { $class_names[] = 'is-content-justification-' . sanitize_title( $block['attrs']['layout']['justifyContent'] ); } if ( ! empty( $block['attrs']['layout']['flexWrap'] ) && 'nowrap' === $block['attrs']['layout']['flexWrap'] ) { $class_names[] = 'is-nowrap'; } $gap_value = _wp_array_get( $block, array( 'attrs', 'style', 'spacing', 'blockGap' ) ); // Skip if gap value contains unsupported characters. // Regex for CSS value borrowed from `safecss_filter_attr`, and used here // because we only want to match against the value, not the CSS attribute. if ( is_array( $gap_value ) ) { foreach ( $gap_value as $key => $value ) { $gap_value[ $key ] = $value && preg_match( '%[\\\(&=}]|/\*%', $value ) ? null : $value; } } else { $gap_value = $gap_value && preg_match( '%[\\\(&=}]|/\*%', $gap_value ) ? null : $gap_value; } $fallback_gap_value = _wp_array_get( $block_type->supports, array( 'spacing', 'blockGap', '__experimentalDefault' ), '0.5em' ); // If a block's block.json skips serialization for spacing or spacing.blockGap, // don't apply the user-defined value to the styles. $should_skip_gap_serialization = wp_should_skip_block_supports_serialization( $block_type, 'spacing', 'blockGap' ); $style = wp_get_layout_style( ".$container_class", $used_layout, $has_block_gap_support, $gap_value, $should_skip_gap_serialization, $fallback_gap_value ); // This assumes the hook only applies to blocks with a single wrapper. // I think this is a reasonable limitation for that particular hook. $content = preg_replace( '/' . preg_quote( 'class="', '/' ) . '/', 'class="' . esc_attr( implode( ' ', $class_names ) ) . ' ', $block_content, 1 ); wp_enqueue_block_support_styles( $style ); return $content; } // Register the block support. WP_Block_Supports::get_instance()->register( 'layout', array( 'register_attribute' => 'wp_register_layout_support', ) ); add_filter( 'render_block', 'wp_render_layout_support_flag', 10, 2 ); /** * For themes without theme.json file, make sure * to restore the inner div for the group block * to avoid breaking styles relying on that div. * * @since 5.8.0 * @access private * * @param string $block_content Rendered block content. * @param array $block Block object. * @return string Filtered block content. */ function wp_restore_group_inner_container( $block_content, $block ) { $tag_name = isset( $block['attrs']['tagName'] ) ? $block['attrs']['tagName'] : 'div'; $group_with_inner_container_regex = sprintf( '/(^\s*<%1$s\b[^>]*wp-block-group(\s|")[^>]*>)(\s*