Editor: Backport Duotone fixes for 5.9.1.

This changeset is a backport for the following Gutenberg PRs:

- Fix duotone theme cache gutenberg#36236
- Fix duotone render in non-fse themes gutenberg#37954
- Duotone: Allow users to specify custom filters gutenberg#38442

Props oandregal, scruffian, Mamaduka.
See #55179.

Built from https://develop.svn.wordpress.org/trunk@52757


git-svn-id: http://core.svn.wordpress.org/trunk@52346 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
audrasjb 2022-02-17 16:18:03 +00:00
parent 9ac43b6ade
commit 26667ab0e1
5 changed files with 199 additions and 42 deletions

View File

@ -352,55 +352,61 @@ function wp_tinycolor_string_to_rgb( $color_str ) {
} }
} }
/** /**
* Registers the style and colors block attributes for block types that support it. * Returns the prefixed id for the duotone filter for use as a CSS id.
* *
* @since 5.8.0 * @since 5.9.1
* @access private * @access private
* *
* @param WP_Block_Type $block_type Block Type. * @param array $preset Duotone preset value as seen in theme.json.
* @return string Duotone filter CSS id.
*/ */
function wp_register_duotone_support( $block_type ) { function wp_get_duotone_filter_id( $preset ) {
$has_duotone_support = false; if ( ! isset( $preset['slug'] ) ) {
if ( property_exists( $block_type, 'supports' ) ) { return '';
$has_duotone_support = _wp_array_get( $block_type->supports, array( 'color', '__experimentalDuotone' ), false );
} }
if ( $has_duotone_support ) { return 'wp-duotone-' . $preset['slug'];
if ( ! $block_type->attributes ) {
$block_type->attributes = array();
}
if ( ! array_key_exists( 'style', $block_type->attributes ) ) {
$block_type->attributes['style'] = array(
'type' => 'object',
);
}
}
} }
/** /**
* Renders the duotone filter SVG and returns the CSS filter property to * Returns the CSS filter property url to reference the rendered SVG.
* reference the rendered SVG.
* *
* @since 5.9.0 * @since 5.9.0
* @access private * @access private
*
* @param array $preset Duotone preset value as seen in theme.json. * @param array $preset Duotone preset value as seen in theme.json.
* @return string Duotone CSS filter property. * @return string Duotone CSS filter property url value.
*/ */
function wp_render_duotone_filter_preset( $preset ) { function wp_get_duotone_filter_property( $preset ) {
$duotone_id = $preset['slug']; $filter_id = wp_get_duotone_filter_id( $preset );
$duotone_colors = $preset['colors']; return "url('#" . $filter_id . "')";
$filter_id = 'wp-duotone-' . $duotone_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( $duotone_values = array(
'r' => array(), 'r' => array(),
'g' => array(), 'g' => array(),
'b' => array(), 'b' => array(),
'a' => array(), 'a' => array(),
); );
foreach ( $duotone_colors as $color_str ) {
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 ); $color = wp_tinycolor_string_to_rgb( $color_str );
$duotone_values['r'][] = $color['r'] / 255; $duotone_values['r'][] = $color['r'] / 255;
@ -456,17 +462,34 @@ function wp_render_duotone_filter_preset( $preset ) {
$svg = trim( $svg ); $svg = trim( $svg );
} }
add_action( return $svg;
// Safari doesn't render SVG filters defined in data URIs, }
// and SVG filters won't render in the head of a document,
// so the next best place to put the SVG is in the footer.
is_admin() ? 'admin_footer' : 'wp_footer',
function () use ( $svg ) {
echo $svg;
}
);
return "url('#" . $filter_id . "')"; /**
* 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',
);
}
}
} }
/** /**
@ -500,8 +523,9 @@ function wp_render_duotone_support( $block_content, $block ) {
'slug' => uniqid(), 'slug' => uniqid(),
'colors' => $block['attrs']['style']['color']['duotone'], 'colors' => $block['attrs']['style']['color']['duotone'],
); );
$filter_property = wp_render_duotone_filter_preset( $filter_preset ); $filter_property = wp_get_duotone_filter_property( $filter_preset );
$filter_id = 'wp-duotone-' . $filter_preset['slug']; $filter_id = wp_get_duotone_filter_id( $filter_preset );
$filter_svg = wp_get_duotone_filter_svg( $filter_preset );
$scope = '.' . $filter_id; $scope = '.' . $filter_id;
$selectors = explode( ',', $duotone_support ); $selectors = explode( ',', $duotone_support );
@ -521,6 +545,28 @@ function wp_render_duotone_support( $block_content, $block ) {
wp_add_inline_style( $filter_id, $filter_style ); wp_add_inline_style( $filter_id, $filter_style );
wp_enqueue_style( $filter_id ); 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.
'<script>( function() { var el = document.querySelector( %s ); var display = el.style.display; el.style.display = "none"; el.offsetHeight; el.style.display = display; } )();</script>',
wp_json_encode( $selector )
);
}
}
);
// Like the layout hook, this assumes the hook only applies to blocks with a single wrapper. // Like the layout hook, this assumes the hook only applies to blocks with a single wrapper.
return preg_replace( return preg_replace(
'/' . preg_quote( 'class="', '/' ) . '/', '/' . preg_quote( 'class="', '/' ) . '/',
@ -538,3 +584,21 @@ WP_Block_Supports::get_instance()->register(
) )
); );
add_filter( 'render_block', 'wp_render_duotone_support', 10, 2 ); add_filter( 'render_block', 'wp_render_duotone_support', 10, 2 );
/**
* Render the SVG filters supplied by theme.json.
*
* Note that this doesn't render the per-block user-defined
* filters which are handled by wp_render_duotone_support,
* but it should be rendered in the same location as those to satisfy
* Safari's rendering quirks.
*
* @since 5.9.1
*/
function wp_global_styles_render_svg_filters() {
$filters = wp_get_global_styles_svg_filters();
if ( ! empty( $filters ) ) {
echo $filters;
}
}
add_action( 'wp_body_open', 'wp_global_styles_render_svg_filters' );

View File

@ -132,7 +132,7 @@ class WP_Theme_JSON {
'path' => array( 'color', 'duotone' ), 'path' => array( 'color', 'duotone' ),
'override' => true, 'override' => true,
'use_default_names' => false, 'use_default_names' => false,
'value_func' => 'wp_render_duotone_filter_preset', 'value_func' => 'wp_get_duotone_filter_property',
'css_vars' => '--wp--preset--duotone--$slug', 'css_vars' => '--wp--preset--duotone--$slug',
'classes' => array(), 'classes' => array(),
'properties' => array( 'filter' ), 'properties' => array( 'filter' ),
@ -1586,6 +1586,40 @@ class WP_Theme_JSON {
} }
} }
/**
* Converts all filter (duotone) presets into SVGs.
*
* @since 5.9.1
*
* @param array $origins List of origins to process.
* @return string SVG filters.
*/
public function get_svg_filters( $origins ) {
$blocks_metadata = static::get_blocks_metadata();
$setting_nodes = static::get_setting_nodes( $this->theme_json, $blocks_metadata );
foreach ( $setting_nodes as $metadata ) {
$node = _wp_array_get( $this->theme_json, $metadata['path'], array() );
if ( empty( $node['color']['duotone'] ) ) {
continue;
}
$duotone_presets = $node['color']['duotone'];
$filters = '';
foreach ( $origins as $origin ) {
if ( ! isset( $duotone_presets[ $origin ] ) ) {
continue;
}
foreach ( $duotone_presets[ $origin ] as $duotone_preset ) {
$filters .= wp_get_duotone_filter_svg( $duotone_preset );
}
}
}
return $filters;
}
/** /**
* Returns whether a presets should be overridden or not. * Returns whether a presets should be overridden or not.
* *

View File

@ -4208,3 +4208,20 @@ function _excerpt_render_inner_columns_blocks( $columns, $allowed_blocks ) {
_deprecated_function( __FUNCTION__, '5.8.0', '_excerpt_render_inner_blocks()' ); _deprecated_function( __FUNCTION__, '5.8.0', '_excerpt_render_inner_blocks()' );
return _excerpt_render_inner_blocks( $columns, $allowed_blocks ); return _excerpt_render_inner_blocks( $columns, $allowed_blocks );
} }
/**
* Renders the duotone filter SVG and returns the CSS filter property to
* reference the rendered SVG.
*
* @since 5.9.0
* @deprecated 5.9.1 Use `wp_get_duotone_filter_property` introduced in 5.9.1.
*
* @see wp_get_duotone_filter_property()
*
* @param array $preset Duotone preset value as seen in theme.json.
* @return string Duotone CSS filter property.
*/
function wp_render_duotone_filter_preset( $preset ) {
_deprecated_function( __FUNCTION__, '5.9.1', 'wp_get_duotone_filter_property()' );
return wp_get_duotone_filter_property( $preset );
}

View File

@ -150,3 +150,45 @@ function wp_get_global_stylesheet( $types = array() ) {
return $stylesheet; return $stylesheet;
} }
/**
* Returns a string containing the SVGs to be referenced as filters (duotone).
*
* @since 5.9.1
*
* @return string
*/
function wp_get_global_styles_svg_filters() {
// Return cached value if it can be used and exists.
// It's cached by theme to make sure that theme switching clears the cache.
$can_use_cached = (
( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ) &&
( ! defined( 'SCRIPT_DEBUG' ) || ! SCRIPT_DEBUG ) &&
( ! defined( 'REST_REQUEST' ) || ! REST_REQUEST ) &&
! is_admin()
);
$transient_name = 'global_styles_svg_filters_' . get_stylesheet();
if ( $can_use_cached ) {
$cached = get_transient( $transient_name );
if ( $cached ) {
return $cached;
}
}
$supports_theme_json = WP_Theme_JSON_Resolver::theme_has_support();
$origins = array( 'default', 'theme', 'custom' );
if ( ! $supports_theme_json ) {
$origins = array( 'default' );
}
$tree = WP_Theme_JSON_Resolver::get_merged_data();
$svgs = $tree->get_svg_filters( $origins );
if ( $can_use_cached ) {
// Cache for a minute, same as wp_get_global_stylesheet.
set_transient( $transient_name, $svgs, MINUTE_IN_SECONDS );
}
return $svgs;
}

View File

@ -16,7 +16,7 @@
* *
* @global string $wp_version * @global string $wp_version
*/ */
$wp_version = '6.0-alpha-52755'; $wp_version = '6.0-alpha-52757';
/** /**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema. * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.