From d9a96d928165209e585e2f23658ccb37ec345926 Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Wed, 15 Mar 2023 10:20:30 -0600 Subject: [PATCH] Revert "Duotone: Limit SVG filter output to used filters" (#49102) --- lib/block-supports/duotone.php | 190 +++++++-------------- lib/class-wp-duotone.php | 150 ---------------- lib/class-wp-theme-json-gutenberg.php | 37 +--- lib/compat/wordpress-6.2/script-loader.php | 4 - lib/load.php | 1 - phpunit/block-supports/duotone-test.php | 41 +---- 6 files changed, 65 insertions(+), 358 deletions(-) delete mode 100644 lib/class-wp-duotone.php diff --git a/lib/block-supports/duotone.php b/lib/block-supports/duotone.php index afb521f5ea73eb..ef950f80ce9448 100644 --- a/lib/block-supports/duotone.php +++ b/lib/block-supports/duotone.php @@ -436,67 +436,54 @@ function gutenberg_render_duotone_support( $block_content, $block ) { $duotone_support = _wp_array_get( $block_type->supports, array( 'color', '__experimentalDuotone' ), false ); } - // The block should have a duotone attribute or have duotone defined in its theme.json to be processed. - $has_duotone_attribute = isset( $block['attrs']['style']['color']['duotone'] ); - $has_global_styles_duotone = array_key_exists( $block['blockName'], WP_Duotone::$global_styles_block_names ); + $has_duotone_attribute = isset( $block['attrs']['style']['color']['duotone'] ); if ( - empty( $block_content ) || ! $duotone_support || - ( ! $has_duotone_attribute && ! $has_global_styles_duotone ) + ! $has_duotone_attribute ) { return $block_content; } - // Generate the pieces needed for rendering a duotone to the page. - if ( $has_duotone_attribute ) { - - // Possible values for duotone attribute: - // 1. Array of colors - e.g. array('#000000', '#ffffff'). - // 2. Variable for an existing Duotone preset - e.g. 'var:preset|duotone|green-blue' or 'var(--wp--preset--duotone--green-blue)'' - // 3. A CSS string - e.g. 'unset' to remove globally applied duotone. - - $duotone_attr = $block['attrs']['style']['color']['duotone']; - $is_preset = is_string( $duotone_attr ) && WP_Duotone::is_preset( $duotone_attr ); - $is_css = is_string( $duotone_attr ) && ! $is_preset; - $is_custom = is_array( $duotone_attr ); - - if ( $is_preset ) { - - // Extract the slug from the preset variable string. - $slug = WP_Duotone::gutenberg_get_slug_from_attr( $duotone_attr ); - - // Utilize existing preset CSS custom property. - $filter_property = "var(--wp--preset--duotone--$slug)"; - - WP_Duotone::$output[ $slug ] = WP_Duotone::$global_styles_presets[ $slug ]; + // Possible values for duotone attribute: + // 1. Array of colors - e.g. array('#000000', '#ffffff'). + // 2. Variable for an existing Duotone preset - e.g. 'var:preset|duotone|green-blue'. + // 3. A CSS string - e.g. 'unset' to remove globally applied duotone. + $duotone_attr = $block['attrs']['style']['color']['duotone']; - } elseif ( $is_css ) { - // Build a unique slug for the filter based on the CSS value. - $slug = wp_unique_id( sanitize_key( $duotone_attr . '-' ) ); + $is_preset = is_string( $duotone_attr ) && strpos( $duotone_attr, 'var:preset|duotone|' ) === 0; + $is_css = is_string( $duotone_attr ) && strpos( $duotone_attr, 'var:preset|duotone|' ) === false; + $is_custom = is_array( $duotone_attr ); - // Pass through the CSS value. - $filter_property = $duotone_attr; - } elseif ( $is_custom ) { - // Build a unique slug for the filter based on the array of colors. - $slug = wp_unique_id( sanitize_key( implode( '-', $duotone_attr ) . '-' ) ); - - $filter_data = array( - 'slug' => $slug, - 'colors' => $duotone_attr, - ); - // Build a customized CSS filter property for unique slug. - $filter_property = gutenberg_get_duotone_filter_property( $filter_data ); - - WP_Duotone::$output[ $slug ] = $filter_data; - } - } elseif ( $has_global_styles_duotone ) { - $slug = WP_Duotone::$global_styles_block_names[ $block['blockName'] ]; + // Generate the pieces needed for rendering a duotone to the page. + if ( $is_preset ) { + // Extract the slug from the preset variable string. + $slug = str_replace( 'var:preset|duotone|', '', $duotone_attr ); // Utilize existing preset CSS custom property. $filter_property = "var(--wp--preset--duotone--$slug)"; + } elseif ( $is_css ) { + // Build a unique slug for the filter based on the CSS value. + $slug = wp_unique_id( sanitize_key( $duotone_attr . '-' ) ); + + // Pass through the CSS value. + $filter_property = $duotone_attr; + } elseif ( $is_custom ) { + // Build a unique slug for the filter based on the array of colors. + $slug = wp_unique_id( sanitize_key( implode( '-', $duotone_attr ) . '-' ) ); + + // This has the same shape as a preset, so it can be used in place of a + // preset when getting the filter property and SVG filter. + $filter_data = array( + 'slug' => $slug, + 'colors' => $duotone_attr, + ); - WP_Duotone::$output[ $slug ] = WP_Duotone::$global_styles_presets[ $slug ]; + // Build a customized CSS filter property for unique slug. + $filter_property = gutenberg_get_duotone_filter_property( $filter_data ); + + // SVG will be output on the page later. + $filter_svg = gutenberg_get_duotone_filter_svg( $filter_data ); } // - Applied as a class attribute to the block wrapper. @@ -506,11 +493,6 @@ function gutenberg_render_duotone_support( $block_content, $block ) { // Build the CSS selectors to which the filter will be applied. $selector = WP_Theme_JSON_Gutenberg::scope_selector( '.' . $filter_id, $duotone_support ); - // We only want to add the selector if we have it in the output already, essentially skipping 'unset'. - if ( array_key_exists( $slug, WP_Duotone::$output ) ) { - WP_Duotone::$output[ $slug ]['selector'] = $selector; - } - // Calling gutenberg_style_engine_get_stylesheet_from_css_rules ensures that // the styles are rendered in an inline for block supports because we're // using the `context` option to instruct it so. @@ -532,6 +514,33 @@ function gutenberg_render_duotone_support( $block_content, $block ) { ) ); + // If we needed to generate an SVG, output it on the page. + if ( isset( $filter_svg ) ) { + 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 ) { + /* + * Simply accessing el.offsetHeight flushes layout and style + * changes in WebKit without having to wait for setTimeout. + */ + printf( + '', + 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="', '/' ) . '/', @@ -541,81 +550,6 @@ function gutenberg_render_duotone_support( $block_content, $block ) { ); } - -add_action( - 'wp_footer', - static function () { - - foreach ( WP_Duotone::$output as $filter_data ) { - - $filter_property = gutenberg_get_duotone_filter_property( $filter_data ); - // SVG will be output on the page later. - $filter_svg = gutenberg_get_duotone_filter_svg( $filter_data ); - - echo $filter_svg; - - // This is for classic themes - in block themes, the CSS is added in the head via the value_func. - if ( ! wp_is_block_theme() ) { - $duotone_preset_css_var = WP_Theme_JSON_Gutenberg::get_preset_css_var( array( 'color', 'duotone' ), $filter_data['slug'] ); - wp_add_inline_style( 'core-block-supports', 'body{' . $duotone_preset_css_var . ' :' . $filter_property . ';}' ); - } - - global $is_safari; - if ( $is_safari ) { - duotone_safari_rerender_hack( $filter_data['selector'] ); - } - } - } -); - -/** - * Appends the used duotone fitler CSS Vars to the inline global styles CSS - */ -add_action( - 'wp_enqueue_scripts', - static function() { - - if ( empty( WP_Duotone::$output ) ) { - return; - } - - $duotone_css_vars = ''; - - foreach ( WP_Duotone::$output as $filter_data ) { - if ( ! array_key_exists( $filter_data['slug'], WP_Duotone::$global_styles_presets ) ) { - continue; - } - - $filter_property = gutenberg_get_duotone_filter_property( $filter_data ); - - $duotone_preset_css_var = WP_Theme_JSON_Gutenberg::get_preset_css_var( array( 'color', 'duotone' ), $filter_data['slug'] ); - $duotone_css_vars .= $duotone_preset_css_var . ': ' . $filter_property . ';'; - } - - if ( ! empty( $duotone_css_vars ) ) { - wp_add_inline_style( 'global-styles', 'body{' . $duotone_css_vars . '}' ); - } - }, - 11 -); - -/** - * 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. - * - * @param string $selector The selector to apply the hack for. - */ -function duotone_safari_rerender_hack( $selector ) { - /* - * Simply accessing el.offsetHeight flushes layout and style - * changes in WebKit without having to wait for setTimeout. - */ - printf( - '', - wp_json_encode( $selector ) - ); -} - // Register the block support. WP_Block_Supports::get_instance()->register( 'duotone', diff --git a/lib/class-wp-duotone.php b/lib/class-wp-duotone.php deleted file mode 100644 index 8f15efbecf0ad3..00000000000000 --- a/lib/class-wp-duotone.php +++ /dev/null @@ -1,150 +0,0 @@ - - * [ - * 'slug' => 'blue-orange', - * 'colors' => [ '#0000ff', '#ffcc00' ], - * ] - * ], - * … - * ] - * - * @since 6.3.0 - * @var array - */ - static $global_styles_presets = array(); - - /** - * An array of block names from global, theme, and custom styles that have duotone presets. We'll use this to quickly - * check if a block being rendered needs to have duotone applied, and which duotone preset to use. - * - * Example: - * [ - * 'core/featured-image' => 'blue-orange', - * … - * ] - * - * @since 6.3.0 - * @var array - */ - static $global_styles_block_names = array(); - - /** - * An array of Duotone SVG and CSS ouput needed for the frontend duotone rendering based on what is - * being ouptput on the page. Organized by a slug of the preset/color group and the information needed - * to generate the SVG and CSS at render. - * - * Example: - * [ - * 'blue-orange' => [ - * 'slug' => 'blue-orange', - * 'colors' => [ '#0000ff', '#ffcc00' ], - * ], - * 'wp-duotone-000000-ffffff-2' => [ - * 'slug' => 'wp-duotone-000000-ffffff-2', - * 'colors' => [ '#000000', '#ffffff' ], - * ], - * ] - * - * @since 6.3.0 - * @var array - */ - static $output = array(); - - /** - * Get all possible duotone presets from global and theme styles and store as slug => [ colors array ] - * We only want to process this one time. On block render we'll access and output only the needed presets for that page. - */ - static function set_global_styles_presets() { - // Get the per block settings from the theme.json. - $tree = gutenberg_get_global_settings(); - $presets_by_origin = _wp_array_get( $tree, array( 'color', 'duotone' ), array() ); - - foreach ( $presets_by_origin as $presets ) { - foreach ( $presets as $preset ) { - self::$global_styles_presets[ _wp_to_kebab_case( $preset['slug'] ) ] = array( - 'slug' => $preset['slug'], - 'colors' => $preset['colors'], - ); - } - } - } - - /** - * Scrape all block names from global styles and store in WP_Duotone::$global_styles_block_names - */ - static function set_global_style_block_names() { - // Get the per block settings from the theme.json. - $tree = WP_Theme_JSON_Resolver::get_merged_data(); - $block_nodes = $tree->get_styles_block_nodes(); - $theme_json = $tree->get_raw_data(); - - foreach ( $block_nodes as $block_node ) { - // This block definition doesn't include any duotone settings. Skip it. - if ( empty( $block_node['duotone'] ) ) { - continue; - } - - // Value looks like this: 'var(--wp--preset--duotone--blue-orange)' or 'var:preset|duotone|default-filter'. - $duotone_attr_path = array_merge( $block_node['path'], array( 'filter', 'duotone' ) ); - $duotone_attr = _wp_array_get( $theme_json, $duotone_attr_path, array() ); - - if ( empty( $duotone_attr ) ) { - continue; - } - // If it has a duotone filter preset, save the block name and the preset slug. - $slug = self::gutenberg_get_slug_from_attr( $duotone_attr ); - - if ( $slug && $slug !== $duotone_attr ) { - self::$global_styles_block_names[ $block_node['name'] ] = $slug; - } - } - } - - /** - * Take the inline CSS duotone variable from a block and return the slug. Handles styles slugs like: - * var:preset|duotone|default-filter - * var(--wp--preset--duotone--blue-orange) - * - * @param string $duotone_attr The duotone attribute from a block. - * @return string The slug of the duotone preset or an empty string if no slug is found. - */ - static function gutenberg_get_slug_from_attr( $duotone_attr ) { - // Uses Branch Reset Groups `(?|…)` to return one capture group. - preg_match( '/(?|var:preset\|duotone\|(\S+)|var\(--wp--preset--duotone--(\S+)\))/', $duotone_attr, $matches ); - - return ! empty( $matches[1] ) ? $matches[1] : ''; - } - - /** - * Check if we have a valid duotone preset. - * - * @param string $duotone_attr The duotone attribute from a block. - * @return bool True if the duotone preset present and valid. - */ - static function is_preset( $duotone_attr ) { - $slug = WP_Duotone::gutenberg_get_slug_from_attr( $duotone_attr ); - - return array_key_exists( $slug, WP_Duotone::$global_styles_presets ); - } -} - -add_action( 'wp_loaded', array( 'WP_Duotone', 'set_global_styles_presets' ), 10 ); -add_action( 'wp_loaded', array( 'WP_Duotone', 'set_global_style_block_names' ), 10 ); diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index c13bd36baaf479..673e97d2b84e5c 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -144,7 +144,7 @@ class WP_Theme_JSON_Gutenberg { 'path' => array( 'color', 'duotone' ), 'prevent_override' => array( 'color', 'defaultDuotone' ), 'use_default_names' => false, - 'value_func' => null, // Don't output CSS Custom Properties for duotone. + 'value_func' => 'gutenberg_get_duotone_filter_property', 'css_vars' => '--wp--preset--duotone--$slug', 'classes' => array(), 'properties' => array( 'filter' ), @@ -3480,39 +3480,4 @@ public function set_spacing_sizes() { _wp_array_set( $this->theme_json, array( 'settings', 'spacing', 'spacingSizes', 'default' ), $spacing_sizes ); } - - /** - * Returns the CSS variable for a preset. - * - * @since 6.3.0 - * - * @param array $path Path to the preset. - * @param string $slug Slug of the preset. - * @return string CSS variable. - */ - public static function get_preset_css_var( $path, $slug ) { - $duotone_preset_metadata = static::get_preset_metadata_from_path( $path ); - return static::replace_slug_in_string( $duotone_preset_metadata['css_vars'], $slug ); - } - - /** - * Returns the metadata for a preset. - * - * @since 6.3.0 - * - * @param array $path Path to the preset. - * @return array Preset metadata. - */ - static function get_preset_metadata_from_path( $path ) { - $preset_metadata = array_filter( - static::PRESETS_METADATA, - function( $preset ) use ( &$path ) { - if ( $preset['path'] === $path ) { - return $preset; - } - } - ); - - return reset( $preset_metadata ); - } } diff --git a/lib/compat/wordpress-6.2/script-loader.php b/lib/compat/wordpress-6.2/script-loader.php index 876d14902fdcb2..149a6a18e14507 100644 --- a/lib/compat/wordpress-6.2/script-loader.php +++ b/lib/compat/wordpress-6.2/script-loader.php @@ -191,7 +191,3 @@ function gutenberg_enqueue_global_styles_custom_css() { } } add_action( 'wp_enqueue_scripts', 'gutenberg_enqueue_global_styles_custom_css' ); - - -remove_action( 'wp_body_open', 'wp_global_styles_render_svg_filters' ); -remove_action( 'in_admin_header', 'wp_global_styles_render_svg_filters' ); diff --git a/lib/load.php b/lib/load.php index 5d8babd0525683..a5be015320652f 100644 --- a/lib/load.php +++ b/lib/load.php @@ -131,7 +131,6 @@ function gutenberg_is_experiment_enabled( $name ) { // Plugin specific code. require __DIR__ . '/class-wp-theme-json-gutenberg.php'; require __DIR__ . '/class-wp-theme-json-resolver-gutenberg.php'; -require __DIR__ . '/class-wp-duotone.php'; require __DIR__ . '/blocks.php'; require __DIR__ . '/client-assets.php'; require __DIR__ . '/demo.php'; diff --git a/phpunit/block-supports/duotone-test.php b/phpunit/block-supports/duotone-test.php index 306ad977fba5db..3588950468aba4 100644 --- a/phpunit/block-supports/duotone-test.php +++ b/phpunit/block-supports/duotone-test.php @@ -10,10 +10,10 @@ class WP_Block_Supports_Duotone_Test extends WP_UnitTestCase { public function test_gutenberg_render_duotone_support_preset() { $block = array( 'blockName' => 'core/image', - 'attrs' => array( 'style' => array( 'color' => array( 'duotone' => 'var:preset|duotone|blue-orange' ) ) ), + 'attrs' => array( 'style' => array( 'color' => array( 'duotone' => 'var:preset|duotone|slug' ) ) ), ); $block_content = '
'; - $expected = '
'; + $expected = '
'; $this->assertSame( $expected, gutenberg_render_duotone_support( $block_content, $block ) ); } @@ -37,41 +37,4 @@ public function test_gutenberg_render_duotone_support_custom() { $this->assertMatchesRegularExpression( $expected, gutenberg_render_duotone_support( $block_content, $block ) ); } - public function data_gutenberg_get_slug_from_attr() { - return array( - 'pipe-slug' => array( 'var:preset|duotone|blue-orange', 'blue-orange' ), - 'css-var' => array( 'var(--wp--preset--duotone--blue-orange)', 'blue-orange' ), - 'css-var-weird-chars' => array( 'var(--wp--preset--duotone--.)', '.' ), - 'css-var-missing-end-parenthesis' => array( 'var(--wp--preset--duotone--blue-orange', '' ), - 'invalid' => array( 'not a valid attribute', '' ), - 'css-var-no-value' => array( 'var(--wp--preset--duotone--)', '' ), - 'pipe-slug-no-value' => array( 'var:preset|duotone|', '' ), - 'css-var-spaces' => array( 'var(--wp--preset--duotone-- ', '' ), - 'pipe-slug-spaces' => array( 'var:preset|duotone| ', '' ), - ); - } - - /** - * @dataProvider data_gutenberg_get_slug_from_attr - */ - public function test_gutenberg_get_slug_from_attr( $data_attr, $expected ) { - $this->assertSame( $expected, WP_Duotone::gutenberg_get_slug_from_attr( $data_attr ) ); - } - - public function data_is_preset() { - return array( - 'pipe-slug' => array( 'var:preset|duotone|blue-orange', true ), - 'css-var' => array( 'var(--wp--preset--duotone--blue-orange)', true ), - 'css-var-weird-chars' => array( 'var(--wp--preset--duotone--.)', false ), - 'css-var-missing-end-parenthesis' => array( 'var(--wp--preset--duotone--blue-orange', false ), - 'invalid' => array( 'not a valid attribute', false ), - ); - } - - /** - * @dataProvider data_is_preset - */ - public function test_is_preset( $data_attr, $expected ) { - $this->assertSame( $expected, WP_Duotone::is_preset( $data_attr ) ); - } }