From 9a275732a546042fec2add1f581de8ba2bf47550 Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Wed, 16 Feb 2022 19:40:35 +0400 Subject: [PATCH 01/14] Duotone theme cache --- src/wp-includes/block-supports/duotone.php | 141 +++++++++++++++++- src/wp-includes/class-wp-theme-json.php | 36 ++++- .../global-styles-and-settings.php | 40 +++++ 3 files changed, 214 insertions(+), 3 deletions(-) diff --git a/src/wp-includes/block-supports/duotone.php b/src/wp-includes/block-supports/duotone.php index f73988e33281a..19d1fb7327d56 100644 --- a/src/wp-includes/block-supports/duotone.php +++ b/src/wp-includes/block-supports/duotone.php @@ -352,6 +352,110 @@ function wp_tinycolor_string_to_rgb( $color_str ) { } } +/** + * Returns the prefixed id for the duotone filter for use as a CSS id. + * + * @since 5.9.0 + * @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 ) { + 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.0 + * @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(), + ); + 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. @@ -500,8 +604,9 @@ function wp_render_duotone_support( $block_content, $block ) { 'slug' => uniqid(), 'colors' => $block['attrs']['style']['color']['duotone'], ); - $filter_property = wp_render_duotone_filter_preset( $filter_preset ); - $filter_id = 'wp-duotone-' . $filter_preset['slug']; + $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 ); @@ -521,6 +626,20 @@ function wp_render_duotone_support( $block_content, $block ) { wp_add_inline_style( $filter_id, $filter_style ); wp_enqueue_style( $filter_id ); + // Render any custom filter the user may have added. + add_action( + // There are a couple of known rendering quirks in Safari. + // 1. Filters won't render at all when the SVG is in the head of + // the document. + // 2. Filters display incorrectly when the SVG is defined after + // where the filter is used in the document, so the footer does + // not work. + 'wp_body_open', + static function () use ( $filter_svg ) { + echo $filter_svg; + } + ); + // Like the layout hook, this assumes the hook only applies to blocks with a single wrapper. return preg_replace( '/' . preg_quote( 'class="', '/' ) . '/', @@ -538,3 +657,21 @@ function wp_render_duotone_support( $block_content, $block ) { ) ); 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.0 + */ +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' ); diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 6f7d4ee356bed..9ed88ddf22854 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -132,7 +132,7 @@ class WP_Theme_JSON { 'path' => array( 'color', 'duotone' ), 'override' => true, 'use_default_names' => false, - 'value_func' => 'wp_render_duotone_filter_preset', + 'value_func' => 'wp_get_duotone_filter_property', 'css_vars' => '--wp--preset--duotone--$slug', 'classes' => array(), 'properties' => array( 'filter' ), @@ -1574,6 +1574,40 @@ public function merge( $incoming ) { } } + /** + * Converts all filter (duotone) presets into SVGs. + * + * @since 5.9.0 + * + * @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. * diff --git a/src/wp-includes/global-styles-and-settings.php b/src/wp-includes/global-styles-and-settings.php index 0e382fe483f39..3492eb5d85cbf 100644 --- a/src/wp-includes/global-styles-and-settings.php +++ b/src/wp-includes/global-styles-and-settings.php @@ -150,3 +150,43 @@ function wp_get_global_stylesheet( $types = array() ) { return $stylesheet; } + +/** + * Returns a string containing the SVGs to be referenced as filters (duotone). + * + * @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; +} From 11fb01c54d421380594560aaf7a656bb491a16ba Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Wed, 16 Feb 2022 19:41:13 +0400 Subject: [PATCH 02/14] Deprecate wp_render_duotone_filter_preset --- src/wp-includes/block-supports/duotone.php | 84 ++-------------------- 1 file changed, 6 insertions(+), 78 deletions(-) diff --git a/src/wp-includes/block-supports/duotone.php b/src/wp-includes/block-supports/duotone.php index 19d1fb7327d56..036c0ba038e4c 100644 --- a/src/wp-includes/block-supports/duotone.php +++ b/src/wp-includes/block-supports/duotone.php @@ -489,88 +489,16 @@ function wp_register_duotone_support( $block_type ) { * reference the rendered SVG. * * @since 5.9.0 - * @access private - + * @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 ) { - $duotone_id = $preset['slug']; - $duotone_colors = $preset['colors']; - $filter_id = 'wp-duotone-' . $duotone_id; - $duotone_values = array( - 'r' => array(), - 'g' => array(), - 'b' => array(), - 'a' => array(), - ); - foreach ( $duotone_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 ); - } - - add_action( - // 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 . "')"; + _deprecated_function( __FUNCTION__, '5.9.1', 'wp_get_duotone_filter_property()' ); + return wp_get_duotone_filter_property( $preset ); } /** From 761278c935e79b5629da09defd1b5a88e5f5de42 Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Wed, 16 Feb 2022 19:51:24 +0400 Subject: [PATCH 03/14] Fix duotone render in classic themes --- src/wp-includes/block-supports/duotone.php | 24 ++++++++++++++-------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/wp-includes/block-supports/duotone.php b/src/wp-includes/block-supports/duotone.php index 036c0ba038e4c..d2b0df4496572 100644 --- a/src/wp-includes/block-supports/duotone.php +++ b/src/wp-includes/block-supports/duotone.php @@ -554,17 +554,23 @@ function wp_render_duotone_support( $block_content, $block ) { wp_add_inline_style( $filter_id, $filter_style ); wp_enqueue_style( $filter_id ); - // Render any custom filter the user may have added. add_action( - // There are a couple of known rendering quirks in Safari. - // 1. Filters won't render at all when the SVG is in the head of - // the document. - // 2. Filters display incorrectly when the SVG is defined after - // where the filter is used in the document, so the footer does - // not work. - 'wp_body_open', - static function () use ( $filter_svg ) { + '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 ) + ); + } } ); From b60d6f509c638cc89d2688c77a1aa30224e58631 Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Wed, 16 Feb 2022 19:55:46 +0400 Subject: [PATCH 04/14] Missing @since --- src/wp-includes/global-styles-and-settings.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/wp-includes/global-styles-and-settings.php b/src/wp-includes/global-styles-and-settings.php index 3492eb5d85cbf..0a0a5fc01b3f2 100644 --- a/src/wp-includes/global-styles-and-settings.php +++ b/src/wp-includes/global-styles-and-settings.php @@ -154,6 +154,8 @@ function wp_get_global_stylesheet( $types = array() ) { /** * Returns a string containing the SVGs to be referenced as filters (duotone). * + * @since 5.9.0 + * * @return string */ function wp_get_global_styles_svg_filters() { From ff2e91e3151f888ebbfb0095a8448bb08a9e69cd Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Thu, 17 Feb 2022 08:04:03 +0000 Subject: [PATCH 05/14] Use multi-line comment Co-authored-by: Tonya Mork --- src/wp-includes/block-supports/duotone.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/wp-includes/block-supports/duotone.php b/src/wp-includes/block-supports/duotone.php index d2b0df4496572..f4a6711de60e5 100644 --- a/src/wp-includes/block-supports/duotone.php +++ b/src/wp-includes/block-supports/duotone.php @@ -559,9 +559,11 @@ function wp_render_duotone_support( $block_content, $block ) { 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. + /* + * 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( From 3f32733043b34eae0257c51f1d0049ea15772e71 Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Thu, 17 Feb 2022 08:04:13 +0000 Subject: [PATCH 06/14] Fix version Co-authored-by: Tonya Mork --- src/wp-includes/block-supports/duotone.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/block-supports/duotone.php b/src/wp-includes/block-supports/duotone.php index f4a6711de60e5..212c9ba0f03a9 100644 --- a/src/wp-includes/block-supports/duotone.php +++ b/src/wp-includes/block-supports/duotone.php @@ -602,7 +602,7 @@ static function () use ( $filter_svg, $selector ) { * but it should be rendered in the same location as those to satisfy * Safari's rendering quirks. * - * @since 5.9.0 + * @since 5.9.1 */ function wp_global_styles_render_svg_filters() { $filters = wp_get_global_styles_svg_filters(); From 59b8a152f84102b75453adb6aa31b6528225d2e7 Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Thu, 17 Feb 2022 08:04:26 +0000 Subject: [PATCH 07/14] Fix version Co-authored-by: Tonya Mork --- src/wp-includes/block-supports/duotone.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/block-supports/duotone.php b/src/wp-includes/block-supports/duotone.php index 212c9ba0f03a9..9639905b5f303 100644 --- a/src/wp-includes/block-supports/duotone.php +++ b/src/wp-includes/block-supports/duotone.php @@ -355,7 +355,7 @@ function wp_tinycolor_string_to_rgb( $color_str ) { /** * Returns the prefixed id for the duotone filter for use as a CSS id. * - * @since 5.9.0 + * @since 5.9.1 * @access private * * @param array $preset Duotone preset value as seen in theme.json. From 2009af49548be5d768454d48a50adf36d615d745 Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Thu, 17 Feb 2022 08:06:25 +0000 Subject: [PATCH 08/14] Fix version Co-authored-by: Tonya Mork --- src/wp-includes/class-wp-theme-json.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 9ed88ddf22854..8389cef733020 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -1577,7 +1577,7 @@ public function merge( $incoming ) { /** * Converts all filter (duotone) presets into SVGs. * - * @since 5.9.0 + * @since 5.9.1 * * @param array $origins List of origins to process. * @return string SVG filters. From 482bfc859bedd811a16d5b05e742120b65cd3134 Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Thu, 17 Feb 2022 08:06:34 +0000 Subject: [PATCH 09/14] Fix version Co-authored-by: Tonya Mork --- src/wp-includes/global-styles-and-settings.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/global-styles-and-settings.php b/src/wp-includes/global-styles-and-settings.php index 0a0a5fc01b3f2..efc2edcaaa354 100644 --- a/src/wp-includes/global-styles-and-settings.php +++ b/src/wp-includes/global-styles-and-settings.php @@ -154,7 +154,7 @@ function wp_get_global_stylesheet( $types = array() ) { /** * Returns a string containing the SVGs to be referenced as filters (duotone). * - * @since 5.9.0 + * @since 5.9.1 * * @return string */ From 933ac8850a0e4c1664c186f5737032990941b8d3 Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Thu, 17 Feb 2022 08:07:29 +0000 Subject: [PATCH 10/14] Guard against missing slug Co-authored-by: Tonya Mork --- src/wp-includes/block-supports/duotone.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/wp-includes/block-supports/duotone.php b/src/wp-includes/block-supports/duotone.php index 9639905b5f303..23921ec4e2553 100644 --- a/src/wp-includes/block-supports/duotone.php +++ b/src/wp-includes/block-supports/duotone.php @@ -362,6 +362,10 @@ function wp_tinycolor_string_to_rgb( $color_str ) { * @return string Duotone filter CSS id. */ function wp_get_duotone_filter_id( $preset ) { + if ( ! isset( $preset['slug'] ) ) { + return ''; + } + return 'wp-duotone-' . $preset['slug']; } From af165f74cf2d84a54904743cd99e6e84567d1a1d Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Thu, 17 Feb 2022 08:08:00 +0000 Subject: [PATCH 11/14] Add guard clause Co-authored-by: Tonya Mork --- src/wp-includes/block-supports/duotone.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/wp-includes/block-supports/duotone.php b/src/wp-includes/block-supports/duotone.php index 23921ec4e2553..11fad4bc45b07 100644 --- a/src/wp-includes/block-supports/duotone.php +++ b/src/wp-includes/block-supports/duotone.php @@ -401,6 +401,10 @@ function wp_get_duotone_filter_svg( $preset ) { '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 ); From 53ec3e1396cf7a813c841c6bcd7eb071f7195336 Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Thu, 17 Feb 2022 08:08:42 +0000 Subject: [PATCH 12/14] Fix version Co-authored-by: Tonya Mork --- src/wp-includes/block-supports/duotone.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/block-supports/duotone.php b/src/wp-includes/block-supports/duotone.php index 11fad4bc45b07..00a3fd2bd34d3 100644 --- a/src/wp-includes/block-supports/duotone.php +++ b/src/wp-includes/block-supports/duotone.php @@ -386,7 +386,7 @@ function wp_get_duotone_filter_property( $preset ) { /** * Returns the duotone filter SVG string for the preset. * - * @since 5.9.0 + * @since 5.9.1 * @access private * * @param array $preset Duotone preset value as seen in theme.json. From 4090e672360c08f122398fd6519c456aeb489462 Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Thu, 17 Feb 2022 12:24:40 +0400 Subject: [PATCH 13/14] Fix parentheses --- src/wp-includes/block-supports/duotone.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wp-includes/block-supports/duotone.php b/src/wp-includes/block-supports/duotone.php index 00a3fd2bd34d3..fe0c74c60f303 100644 --- a/src/wp-includes/block-supports/duotone.php +++ b/src/wp-includes/block-supports/duotone.php @@ -401,10 +401,10 @@ function wp_get_duotone_filter_svg( $preset ) { 'b' => array(), 'a' => array(), ); - if ( ! isset( $preset['colors'] || ! is_array( $preset['colors'] ) ) { + 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 ); From 29d1f74184299be5e654a33c8df92e62d53cff06 Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Thu, 17 Feb 2022 12:51:52 +0400 Subject: [PATCH 14/14] Move deprecated function --- src/wp-includes/block-supports/duotone.php | 17 ----------------- src/wp-includes/deprecated.php | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/wp-includes/block-supports/duotone.php b/src/wp-includes/block-supports/duotone.php index fe0c74c60f303..a243929eee259 100644 --- a/src/wp-includes/block-supports/duotone.php +++ b/src/wp-includes/block-supports/duotone.php @@ -492,23 +492,6 @@ function wp_register_duotone_support( $block_type ) { } } -/** - * 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 ); -} - /** * Render out the duotone stylesheet and SVG. * diff --git a/src/wp-includes/deprecated.php b/src/wp-includes/deprecated.php index 7f29f9dcb6330..36b7dacd55a98 100644 --- a/src/wp-includes/deprecated.php +++ b/src/wp-includes/deprecated.php @@ -4208,3 +4208,20 @@ function _excerpt_render_inner_columns_blocks( $columns, $allowed_blocks ) { _deprecated_function( __FUNCTION__, '5.8.0', '_excerpt_render_inner_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 ); +}