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 ) );
- }
}