diff --git a/lib/block-supports/duotone.php b/lib/block-supports/duotone.php index b4a8397d72ece..71fba2ce24a67 100644 --- a/lib/block-supports/duotone.php +++ b/lib/block-supports/duotone.php @@ -519,3 +519,47 @@ static function () use ( $filter_svg, $selector ) { // Remove WordPress core filter to avoid rendering duplicate support elements. remove_filter( 'render_block', 'wp_render_duotone_support', 10, 2 ); add_filter( 'render_block', 'gutenberg_render_duotone_support', 10, 2 ); + +class WP_Duotone { + /** + * An array of Duotone presets. + * + * @since 6.3.0 + * @var array + */ + static $duotone_presets = array(); + + /** + * Registers the duotone preset. + * + * @param array $settings The block editor settings. + * + * @return array The block editor settings. + */ + public static function duotone_declarations( $declarations, $selector ) { + foreach ( $declarations as $index => $declaration ) { + if ( 'filter' === $declaration['name'] ) { + static::$duotone_presets[] = $declarations[ $index ]['value']; + } + } + } + + public static function get_filter_svg( $duotone_preset ) { + $filters = ''; + // Get the CSS variable for the preset. + $duotone_preset_css_var = WP_Theme_JSON_Gutenberg::get_preset_css_var( array( 'color', 'duotone' ), $duotone_preset['slug'] ); + $duotone_preset_css_var_with_wrapper = 'var(' . $duotone_preset_css_var . ')'; + // Only output the preset if it's used by a block. + if ( in_array( $duotone_preset_css_var_with_wrapper, WP_Duotone::$duotone_presets, true ) ) { + // Output the CSS for the preset. + // I think we should do this differently, but I'm not sure how. + $filters .= ''; + $filters .= wp_get_duotone_filter_svg( $duotone_preset ); + } + + return $filters; + } +} +add_action( 'theme_json_register_declarations', array( 'WP_Duotone', 'duotone_declarations' ), 10, 2 ); + +add_filter( 'theme_json_get_filter_svg', array( 'WP_Duotone', 'get_filter_svg' ), 10, 2 ); \ No newline at end of file diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index 1e828edcaddc3..eb8ad262fdc15 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -152,7 +152,7 @@ class WP_Theme_JSON_Gutenberg { 'path' => array( 'color', 'duotone' ), 'prevent_override' => array( 'color', 'defaultDuotone' ), 'use_default_names' => false, - 'value_func' => 'gutenberg_get_duotone_filter_property', + 'value_func' => null, // Don't output CSS Custom Properties for duotone. 'css_vars' => '--wp--preset--duotone--$slug', 'classes' => array(), 'properties' => array( 'filter' ), @@ -1463,7 +1463,6 @@ protected function get_css_variables( $nodes, $origins ) { foreach ( $theme_vars_declarations as $theme_vars_declaration ) { $declarations[] = $theme_vars_declaration; } - $stylesheet .= static::to_ruleset( $selector, $declarations ); } @@ -2418,6 +2417,9 @@ function( $pseudo_selector ) use ( $selector ) { $block_rules = ''; + // TODO + do_action( 'theme_json_register_declarations', $declarations, $selector ); + /* * 1. Separate the declarations that use the general selector * from the ones using the duotone selector. @@ -2700,7 +2702,7 @@ public function get_svg_filters( $origins ) { continue; } foreach ( $duotone_presets[ $origin ] as $duotone_preset ) { - $filters .= wp_get_duotone_filter_svg( $duotone_preset ); + $filters .= apply_filters( 'theme_json_get_filter_svg', $duotone_preset ); } } } @@ -2708,6 +2710,41 @@ public function get_svg_filters( $origins ) { return $filters; } + /** + * 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 ); + } + /** * Determines whether a presets should be overridden or not. * diff --git a/lib/compat/wordpress-6.2/get-global-styles-and-settings.php b/lib/compat/wordpress-6.2/get-global-styles-and-settings.php index e02a0466a0b98..7e987dc435ab5 100644 --- a/lib/compat/wordpress-6.2/get-global-styles-and-settings.php +++ b/lib/compat/wordpress-6.2/get-global-styles-and-settings.php @@ -255,3 +255,45 @@ function _gutenberg_add_non_persistent_theme_json_cache_group() { wp_cache_add_non_persistent_groups( 'theme_json' ); } add_action( 'plugins_loaded', '_gutenberg_add_non_persistent_theme_json_cache_group' ); + + +/** + * Returns a string containing the SVGs to be referenced as filters (duotone). + * + * @since 5.9.1 + * + * @return string + */ +function gutenberg_get_global_styles_svg_filters() { + /* + * Ignore cache when `WP_DEBUG` is enabled, so it doesn't interfere with the theme + * developer's workflow. + * + * @todo Replace `WP_DEBUG` once an "in development mode" check is available in Core. + */ + $can_use_cached = ! WP_DEBUG; + $cache_group = 'theme_json'; + $cache_key = 'wp_get_global_styles_svg_filters'; + if ( $can_use_cached ) { + $cached = wp_cache_get( $cache_key, $cache_group ); + if ( $cached ) { + return $cached; + } + } + + $supports_theme_json = wp_theme_has_theme_json(); + + $origins = array( 'default', 'theme', 'custom' ); + if ( ! $supports_theme_json ) { + $origins = array( 'default' ); + } + + $tree = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data(); + $svgs = $tree->get_svg_filters( $origins ); + + if ( $can_use_cached ) { + wp_cache_set( $cache_key, $svgs, $cache_group ); + } + + return $svgs; +} diff --git a/lib/compat/wordpress-6.2/script-loader.php b/lib/compat/wordpress-6.2/script-loader.php index 149a6a18e1450..172191ac59a43 100644 --- a/lib/compat/wordpress-6.2/script-loader.php +++ b/lib/compat/wordpress-6.2/script-loader.php @@ -191,3 +191,38 @@ function gutenberg_enqueue_global_styles_custom_css() { } } add_action( 'wp_enqueue_scripts', 'gutenberg_enqueue_global_styles_custom_css' ); + + + +/** + * Renders 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 before the filtered content + * in the body to satisfy Safari's rendering quirks. + * + * @since 5.9.1 + */ +function gutenberg_global_styles_render_svg_filters() { + /* + * When calling via the in_admin_header action, we only want to render the + * SVGs on block editor pages. + */ + if ( + is_admin() && + ! get_current_screen()->is_block_editor() + ) { + return; + } + + $filters = gutenberg_get_global_styles_svg_filters(); + if ( ! empty( $filters ) ) { + echo $filters; + } +} + +remove_action( 'wp_body_open', 'wp_global_styles_render_svg_filters' ); +remove_action( 'in_admin_header', 'wp_global_styles_render_svg_filters' ); +add_action( 'wp_body_open', 'gutenberg_global_styles_render_svg_filters' ); +add_action( 'in_admin_header', 'gutenberg_global_styles_render_svg_filters' );