From 69b61549213c385def41c9ea68d97527f2658e9d Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Thu, 15 Jun 2023 10:43:41 +0200 Subject: [PATCH 01/47] BP: Duotone: Limit SVG filter output to used filters #49103 --- src/wp-admin/includes/class-wp-duotone.php | 370 ++++++++++++++++++ src/wp-includes/block-supports/duotone.php | 86 +--- src/wp-includes/class-wp-theme-json.php | 4 +- src/wp-includes/default-filters.php | 4 - src/wp-settings.php | 1 + .../phpunit/tests/block-supports/duotone.php | 92 +++++ 6 files changed, 473 insertions(+), 84 deletions(-) create mode 100644 src/wp-admin/includes/class-wp-duotone.php create mode 100644 tests/phpunit/tests/block-supports/duotone.php diff --git a/src/wp-admin/includes/class-wp-duotone.php b/src/wp-admin/includes/class-wp-duotone.php new file mode 100644 index 0000000000000..9669479ae3c06 --- /dev/null +++ b/src/wp-admin/includes/class-wp-duotone.php @@ -0,0 +1,370 @@ + + * [ + * 'slug' => 'blue-orange', + * 'colors' => [ '#0000ff', '#ffcc00' ], + * ] + * ], + * … + * ] + * + * @since 6.3.0 + * @var array + */ + private 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 + */ + private static $global_styles_block_names = array(); + + /** + * An array of Duotone SVG and CSS output needed for the frontend duotone rendering based on what is + * being output 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 + */ + private static $output = array(); + + /** + * Prefix used for generating and referencing duotone CSS custom properties. + */ + const CSS_VAR_PREFIX = '--wp--preset--duotone--'; + + /** + * 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. + */ + public static function set_global_styles_presets() { + // Get the per block settings from the theme.json. + $tree = wp_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 self::$global_styles_block_names + */ + public 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::wp_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. + */ + private static function wp_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. + */ + private static function is_preset( $duotone_attr ) { + $slug = self::wp_get_slug_from_attr( $duotone_attr ); + + return array_key_exists( $slug, self::$global_styles_presets ); + } + + /** + * Get the CSS variable name for a duotone preset. + * + * @param string $slug The slug of the duotone preset. + * @return string The CSS variable name. + */ + private static function get_css_custom_property_name( $slug ) { + return self::CSS_VAR_PREFIX . $slug; + } + + /** + * Get the CSS variable for a duotone preset. + * + * @param string $slug The slug of the duotone preset. + * @return string The CSS variable. + */ + private static function get_css_var( $slug ) { + return 'var(' . self::get_css_custom_property_name( $slug ) . ')'; + } + + /** + * Get the CSS declaration for a duotone preset. + * Example: --wp--preset--duotone--blue-orange: url('#wp-duotone-blue-orange'); + * + * @param array $filter_data The duotone data for presets and custom filters. + * @return string The CSS declaration. + */ + private static function get_css_custom_property_declaration( $filter_data ) { + $declaration_value = wp_get_duotone_filter_property( $filter_data ); + $duotone_preset_css_property_name = self::get_css_custom_property_name( $filter_data['slug'] ); + return $duotone_preset_css_property_name . ': ' . $declaration_value . ';'; + } + + /** + * 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. + */ + private static function 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 ) + ); + } + + /** + * Outputs all necessary SVG for duotone filters, CSS for classic themes, and safari rerendering hack + */ + public static function output_footer_assets() { + foreach ( self::$output as $filter_data ) { + + // SVG will be output on the page later. + $filter_svg = wp_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 wp_add_inline_style in the wp_enqueue_scripts action. + if ( ! wp_is_block_theme() ) { + wp_add_inline_style( 'core-block-supports', 'body{' . self::get_css_custom_property_declaration( $filter_data ) . '}' ); + } + + global $is_safari; + if ( $is_safari ) { + self::safari_rerender_hack( $filter_data['selector'] ); + } + } + } + + /** + * Appends the used global style duotone filter CSS Vars to the inline global styles CSS + */ + public static function output_global_styles() { + + if ( empty( self::$output ) ) { + return; + } + + $duotone_css_vars = ''; + + foreach ( self::$output as $filter_data ) { + if ( ! array_key_exists( $filter_data['slug'], self::$global_styles_presets ) ) { + continue; + } + + $duotone_css_vars .= self::get_css_custom_property_declaration( $filter_data ); + } + + if ( ! empty( $duotone_css_vars ) ) { + wp_add_inline_style( 'global-styles', 'body{' . $duotone_css_vars . '}' ); + } + } + + /** + * Render out the duotone CSS styles and SVG. + * + * @param string $block_content Rendered block content. + * @param array $block Block object. + * @return string Filtered block content. + */ + public static function render_duotone_support( $block_content, $block ) { + $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] ); + + $duotone_support = false; + if ( $block_type && property_exists( $block_type, 'supports' ) ) { + $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'], self::$global_styles_block_names ); + + if ( + empty( $block_content ) || + ! $duotone_support || + ( ! $has_duotone_attribute && ! $has_global_styles_duotone ) + ) { + 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 ) && self::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 = self::wp_get_slug_from_attr( $duotone_attr ); + + // Utilize existing preset CSS custom property. + $declaration_value = self::get_css_var( $slug ); + + self::$output[ $slug ] = self::$global_styles_presets[ $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. + $declaration_value = $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. + $declaration_value = wp_get_duotone_filter_property( $filter_data ); + + self::$output[ $slug ] = $filter_data; + } + } elseif ( $has_global_styles_duotone ) { + $slug = self::$global_styles_block_names[ $block['blockName'] ]; + + // Utilize existing preset CSS custom property. + $declaration_value = self::get_css_var( $slug ); + + self::$output[ $slug ] = self::$global_styles_presets[ $slug ]; + } + + // - Applied as a class attribute to the block wrapper. + // - Used as a selector to apply the filter to the block. + $filter_id = wp_get_duotone_filter_id( array( 'slug' => $slug ) ); + + // Build the CSS selectors to which the filter will be applied. + $selector = WP_Theme_JSON::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, self::$output ) ) { + self::$output[ $slug ]['selector'] = $selector; + } + + // Pass styles to the block-supports stylesheet via the style engine. + // This ensures that Duotone styles are included in a single stylesheet, + // avoiding multiple style tags or multiple stylesheets being output to + // the site frontend. + wp_style_engine_get_stylesheet_from_css_rules( + array( + array( + 'selector' => $selector, + 'declarations' => array( + // !important is needed because these styles + // render before global styles, + // and they should be overriding the duotone + // filters set by global styles. + 'filter' => $declaration_value . ' !important', + ), + ), + ), + array( + 'context' => 'block-supports', + ) + ); + + // Like the layout hook, this assumes the hook only applies to blocks with a single wrapper. + return preg_replace( + '/' . preg_quote( 'class="', '/' ) . '/', + 'class="' . $filter_id . ' ', + $block_content, + 1 + ); + } +} diff --git a/src/wp-includes/block-supports/duotone.php b/src/wp-includes/block-supports/duotone.php index 429eeee0514a8..314eaeb61621c 100644 --- a/src/wp-includes/block-supports/duotone.php +++ b/src/wp-includes/block-supports/duotone.php @@ -505,86 +505,12 @@ function wp_register_duotone_support( $block_type ) { * * @param string $block_content Rendered block content. * @param array $block Block object. + * @deprecated 6.3.0 Use WP_Duotone::render_duotone_support() instead. * @return string Filtered block content. */ function wp_render_duotone_support( $block_content, $block ) { - $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] ); - - $duotone_support = false; - if ( $block_type && property_exists( $block_type, 'supports' ) ) { - $duotone_support = _wp_array_get( $block_type->supports, array( 'color', '__experimentalDuotone' ), false ); - } - - $has_duotone_attribute = isset( $block['attrs']['style']['color']['duotone'] ); - - if ( - ! $duotone_support || - ! $has_duotone_attribute - ) { - return $block_content; - } - - $colors = $block['attrs']['style']['color']['duotone']; - $filter_key = is_array( $colors ) ? implode( '-', $colors ) : $colors; - $filter_preset = array( - 'slug' => wp_unique_id( sanitize_key( $filter_key . '-' ) ), - 'colors' => $colors, - ); - $filter_property = wp_get_duotone_filter_property( $filter_preset ); - $filter_id = wp_get_duotone_filter_id( $filter_preset ); - - $scope = '.' . $filter_id; - $selectors = explode( ',', $duotone_support ); - $scoped = array(); - foreach ( $selectors as $sel ) { - $scoped[] = $scope . ' ' . trim( $sel ); - } - $selector = implode( ', ', $scoped ); - - // !important is needed because these styles render before global styles, - // and they should be overriding the duotone filters set by global styles. - $filter_style = SCRIPT_DEBUG - ? $selector . " {\n\tfilter: " . $filter_property . " !important;\n}\n" - : $selector . '{filter:' . $filter_property . ' !important;}'; - - wp_register_style( $filter_id, false ); - wp_add_inline_style( $filter_id, $filter_style ); - wp_enqueue_style( $filter_id ); - - if ( 'unset' !== $colors ) { - $filter_svg = wp_get_duotone_filter_svg( $filter_preset ); - 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="', '/' ) . '/', - 'class="' . $filter_id . ' ', - $block_content, - 1 - ); + _deprecated_function( __FUNCTION__, '6.3.0', 'WP_Duotone::render_duotone_support' ); + return WP_Duotone::render_duotone_support( $block_content, $block ); } // Register the block support. @@ -594,4 +520,8 @@ static function () use ( $filter_svg, $selector ) { 'register_attribute' => 'wp_register_duotone_support', ) ); -add_filter( 'render_block', 'wp_render_duotone_support', 10, 2 ); +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 ); +add_filter( 'render_block', array( 'WP_Duotone', 'render_duotone_support' ), 10, 2 ); +add_action( 'wp_enqueue_scripts', array( 'WP_Duotone', 'output_global_styles' ), 11 ); +add_action( 'wp_footer', array( 'WP_Duotone', 'output_footer_assets' ), 10 ); \ No newline at end of file diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index c9517576a3bb9..0091496f3013e 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -143,8 +143,8 @@ class WP_Theme_JSON { 'path' => array( 'color', 'duotone' ), 'prevent_override' => array( 'color', 'defaultDuotone' ), 'use_default_names' => false, - 'value_func' => 'wp_get_duotone_filter_property', - 'css_vars' => '--wp--preset--duotone--$slug', + 'value_func' => null, // CSS Custom Properties for duotone are handled by block supports in class-wp-duotone.php. + 'css_vars' => null, 'classes' => array(), 'properties' => array( 'filter' ), ), diff --git a/src/wp-includes/default-filters.php b/src/wp-includes/default-filters.php index 4ddaf291bb115..44cf5bd705a02 100644 --- a/src/wp-includes/default-filters.php +++ b/src/wp-includes/default-filters.php @@ -606,10 +606,6 @@ add_action( 'wp_enqueue_scripts', 'wp_enqueue_stored_styles' ); add_action( 'wp_footer', 'wp_enqueue_stored_styles', 1 ); -// SVG filters like duotone have to be loaded at the beginning of the body in both admin and the front-end. -add_action( 'wp_body_open', 'wp_global_styles_render_svg_filters' ); -add_action( 'in_admin_header', 'wp_global_styles_render_svg_filters' ); - add_action( 'wp_default_styles', 'wp_default_styles' ); add_filter( 'style_loader_src', 'wp_style_loader_src', 10, 2 ); diff --git a/src/wp-settings.php b/src/wp-settings.php index ac3365ab3fdbb..08651606bc47a 100644 --- a/src/wp-settings.php +++ b/src/wp-settings.php @@ -175,6 +175,7 @@ require ABSPATH . WPINC . '/class-wp-theme-json-data.php'; require ABSPATH . WPINC . '/class-wp-theme-json.php'; require ABSPATH . WPINC . '/class-wp-theme-json-resolver.php'; +require ABSPATH . WPINC . '/class-wp-duotone.php'; require ABSPATH . WPINC . '/global-styles-and-settings.php'; require ABSPATH . WPINC . '/class-wp-block-template.php'; require ABSPATH . WPINC . '/block-template-utils.php'; diff --git a/tests/phpunit/tests/block-supports/duotone.php b/tests/phpunit/tests/block-supports/duotone.php new file mode 100644 index 0000000000000..a9bc676457dc9 --- /dev/null +++ b/tests/phpunit/tests/block-supports/duotone.php @@ -0,0 +1,92 @@ + 'core/image', + 'attrs' => array( 'style' => array( 'color' => array( 'duotone' => 'var:preset|duotone|blue-orange' ) ) ), + ); + $block_content = '
'; + $expected = '
'; + $this->assertSame( $expected, WP_Duotone::render_duotone_support( $block_content, $block ) ); + } + + public function test_render_duotone_support_css() { + $block = array( + 'blockName' => 'core/image', + 'attrs' => array( 'style' => array( 'color' => array( 'duotone' => 'unset' ) ) ), + ); + $block_content = '
'; + $expected = '/
<\\/figure>/'; + $this->assertMatchesRegularExpression( $expected, WP_Duotone::render_duotone_support( $block_content, $block ) ); + } + + public function test_render_duotone_support_custom() { + $block = array( + 'blockName' => 'core/image', + 'attrs' => array( 'style' => array( 'color' => array( 'duotone' => array( '#FFFFFF', '#000000' ) ) ) ), + ); + $block_content = '
'; + $expected = '/
<\\/figure>/'; + $this->assertMatchesRegularExpression( $expected, WP_Duotone::render_duotone_support( $block_content, $block ) ); + } + + public function data_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-invalid-slug-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_get_slug_from_attr + */ + public function test_get_slug_from_attr( $data_attr, $expected ) { + + $reflection = new ReflectionMethod( 'WP_Duotone', 'get_slug_from_attr' ); + $reflection->setAccessible( true ); + + $this->assertSame( $expected, $reflection->invoke( null, $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-invalid-slug-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 ) { + $reflection = new ReflectionMethod( 'WP_Duotone', 'is_preset' ); + $reflection->setAccessible( true ); + + $this->assertSame( $expected, $reflection->invoke( null, $data_attr ) ); + } +} From 26ee6d3f5fbe63450989b00316aa018a20f0b131 Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Thu, 15 Jun 2023 11:42:29 +0200 Subject: [PATCH 02/47] wrong place for the included file --- src/{wp-admin/includes => wp-includes}/class-wp-duotone.php | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{wp-admin/includes => wp-includes}/class-wp-duotone.php (100%) diff --git a/src/wp-admin/includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php similarity index 100% rename from src/wp-admin/includes/class-wp-duotone.php rename to src/wp-includes/class-wp-duotone.php From 4615585d642e79b66c6664e1ebe367d24c7841fc Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Thu, 15 Jun 2023 11:45:51 +0200 Subject: [PATCH 03/47] BP: Duotone: Remove Safari rerender hack (#49232) --- src/wp-includes/class-wp-duotone.php | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index 9669479ae3c06..afa55707ddc4a 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -184,24 +184,7 @@ private static function get_css_custom_property_declaration( $filter_data ) { } /** - * 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. - */ - private static function 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 ) - ); - } - - /** - * Outputs all necessary SVG for duotone filters, CSS for classic themes, and safari rerendering hack + * Outputs all necessary SVG for duotone filters, CSS for classic themes. */ public static function output_footer_assets() { foreach ( self::$output as $filter_data ) { @@ -215,11 +198,6 @@ public static function output_footer_assets() { if ( ! wp_is_block_theme() ) { wp_add_inline_style( 'core-block-supports', 'body{' . self::get_css_custom_property_declaration( $filter_data ) . '}' ); } - - global $is_safari; - if ( $is_safari ) { - self::safari_rerender_hack( $filter_data['selector'] ); - } } } From 984486c3a1d0b0e505645c78627184c5769931ad Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Thu, 15 Jun 2023 11:49:42 +0200 Subject: [PATCH 04/47] BP: Replace regex with tag processor for duotone class render #49212 --- src/wp-includes/class-wp-duotone.php | 11 +++++------ tests/phpunit/tests/block-supports/duotone.php | 6 +++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index afa55707ddc4a..75c832757fd3f 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -338,11 +338,10 @@ public static function render_duotone_support( $block_content, $block ) { ); // Like the layout hook, this assumes the hook only applies to blocks with a single wrapper. - return preg_replace( - '/' . preg_quote( 'class="', '/' ) . '/', - 'class="' . $filter_id . ' ', - $block_content, - 1 - ); + $tags = new WP_HTML_Tag_Processor( $block_content ); + if ( $tags->next_tag() ) { + $tags->add_class( $filter_id ); + } + return $tags->get_updated_html(); } } diff --git a/tests/phpunit/tests/block-supports/duotone.php b/tests/phpunit/tests/block-supports/duotone.php index a9bc676457dc9..5ce1788c20fc4 100644 --- a/tests/phpunit/tests/block-supports/duotone.php +++ b/tests/phpunit/tests/block-supports/duotone.php @@ -21,7 +21,7 @@ public function test_render_duotone_support_preset() { 'attrs' => array( 'style' => array( 'color' => array( 'duotone' => 'var:preset|duotone|blue-orange' ) ) ), ); $block_content = '
'; - $expected = '
'; + $expected = '
'; $this->assertSame( $expected, WP_Duotone::render_duotone_support( $block_content, $block ) ); } @@ -31,7 +31,7 @@ public function test_render_duotone_support_css() { 'attrs' => array( 'style' => array( 'color' => array( 'duotone' => 'unset' ) ) ), ); $block_content = '
'; - $expected = '/
<\\/figure>/'; + $expected = '/
<\\/figure>/'; $this->assertMatchesRegularExpression( $expected, WP_Duotone::render_duotone_support( $block_content, $block ) ); } @@ -41,7 +41,7 @@ public function test_render_duotone_support_custom() { 'attrs' => array( 'style' => array( 'color' => array( 'duotone' => array( '#FFFFFF', '#000000' ) ) ) ), ); $block_content = '
'; - $expected = '/
<\\/figure>/'; + $expected = '/
<\\/figure>/'; $this->assertMatchesRegularExpression( $expected, WP_Duotone::render_duotone_support( $block_content, $block ) ); } From 72f6355c6ce76567e418666ae8779cf0c1e74862 Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Thu, 15 Jun 2023 11:54:23 +0200 Subject: [PATCH 05/47] BP: Duotone: Pass filters to the Post Editor #49239 --- src/wp-includes/block-supports/duotone.php | 3 +- src/wp-includes/class-wp-duotone.php | 39 ++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/wp-includes/block-supports/duotone.php b/src/wp-includes/block-supports/duotone.php index 314eaeb61621c..d33d4c2a069db 100644 --- a/src/wp-includes/block-supports/duotone.php +++ b/src/wp-includes/block-supports/duotone.php @@ -524,4 +524,5 @@ function wp_render_duotone_support( $block_content, $block ) { add_action( 'wp_loaded', array( 'WP_Duotone', 'set_global_style_block_names' ), 10 ); add_filter( 'render_block', array( 'WP_Duotone', 'render_duotone_support' ), 10, 2 ); add_action( 'wp_enqueue_scripts', array( 'WP_Duotone', 'output_global_styles' ), 11 ); -add_action( 'wp_footer', array( 'WP_Duotone', 'output_footer_assets' ), 10 ); \ No newline at end of file +add_action( 'wp_footer', array( 'WP_Duotone', 'output_footer_assets' ), 10 ); +add_filter( 'block_editor_settings_all', array( 'WP_Duotone', 'add_editor_settings' ), 10 ); \ No newline at end of file diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index 75c832757fd3f..6cdf956b2b9e9 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -201,6 +201,45 @@ public static function output_footer_assets() { } } + /** + * Adds the duotone SVGs and CSS custom properties to the editor settings so + * they can be pulled in by the EditorStyles component in JS and rendered in + * the post editor. + * + * @param array $settings The block editor settings from the `block_editor_settings_all` filter. + * @return array The editor settings with duotone SVGs and CSS custom properties. + */ + public static function add_editor_settings( $settings ) { + $duotone_svgs = ''; + $duotone_css = 'body{'; + foreach ( self::$global_styles_presets as $filter_data ) { + $duotone_svgs .= get_duotone_filter_svg( $filter_data ); + $duotone_css .= self::get_css_custom_property_declaration( $filter_data ); + } + $duotone_css .= '}'; + + if ( ! isset( $settings['styles'] ) ) { + $settings['styles'] = array(); + } + + $settings['styles'][] = array( + 'assets' => $duotone_svgs, + // The 'svgs' type is new in 6.3 and requires the corresponding JS changes in the EditorStyles component to work. + '__unstableType' => 'svgs', + 'isGlobalStyles' => false, + ); + + $settings['styles'][] = array( + 'css' => $duotone_css, + // This must be set and must be something other than 'theme' or they will be stripped out in the post editor component. + '__unstableType' => 'presets', + // These styles are no longer generated by global styles, so this must be false or they will be stripped out in get_block_editor_settings. + 'isGlobalStyles' => false, + ); + + return $settings; + } + /** * Appends the used global style duotone filter CSS Vars to the inline global styles CSS */ From cb980d059a130fe9766fb06201e91344ecf98d0a Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Thu, 15 Jun 2023 12:50:48 +0200 Subject: [PATCH 06/47] BP: Port colord to PHP #49700 --- src/wp-includes/block-supports/duotone.php | 98 ++--- src/wp-includes/class-wp-duotone.php | 431 ++++++++++++++++++++- 2 files changed, 456 insertions(+), 73 deletions(-) diff --git a/src/wp-includes/block-supports/duotone.php b/src/wp-includes/block-supports/duotone.php index d33d4c2a069db..0b33bbc0cfcf8 100644 --- a/src/wp-includes/block-supports/duotone.php +++ b/src/wp-includes/block-supports/duotone.php @@ -40,6 +40,8 @@ * * @see https://github.com/bgrins/TinyColor * + * @deprecated 6.3.0 + * * @since 5.8.0 * @access private * @@ -48,6 +50,7 @@ * @return float Value in the range [0, 1]. */ function wp_tinycolor_bound01( $n, $max ) { + _deprecated_function( __FUNCTION__, '6.3.0' ); if ( 'string' === gettype( $n ) && str_contains( $n, '.' ) && 1 === (float) $n ) { $n = '100%'; } @@ -74,6 +77,8 @@ function wp_tinycolor_bound01( $n, $max ) { * * @see https://github.com/bgrins/TinyColor * + * @deprecated 6.3.0 + * * @since 5.9.0 * @access private * @@ -81,6 +86,8 @@ function wp_tinycolor_bound01( $n, $max ) { * @return float Value in the range [0,1]. */ function _wp_tinycolor_bound_alpha( $n ) { + _deprecated_function( __FUNCTION__, '6.3.0' ); + if ( is_numeric( $n ) ) { $n = (float) $n; if ( $n >= 0 && $n <= 1 ) { @@ -97,6 +104,8 @@ function _wp_tinycolor_bound_alpha( $n ) { * consistency with TinyColor. * * @see https://github.com/bgrins/TinyColor + * + * @deprecated 6.3.0 * * @since 5.8.0 * @access private @@ -105,6 +114,8 @@ function _wp_tinycolor_bound_alpha( $n ) { * @return array Rounded and converted RGB object. */ function wp_tinycolor_rgb_to_rgb( $rgb_color ) { + _deprecated_function( __FUNCTION__, '6.3.0' ); + return array( 'r' => wp_tinycolor_bound01( $rgb_color['r'], 255 ) * 255, 'g' => wp_tinycolor_bound01( $rgb_color['g'], 255 ) * 255, @@ -119,6 +130,8 @@ function wp_tinycolor_rgb_to_rgb( $rgb_color ) { * consistency with TinyColor. * * @see https://github.com/bgrins/TinyColor + * + * @deprecated 6.3.0 * * @since 5.8.0 * @access private @@ -129,6 +142,8 @@ function wp_tinycolor_rgb_to_rgb( $rgb_color ) { * @return float R, G, or B component. */ function wp_tinycolor_hue_to_rgb( $p, $q, $t ) { + _deprecated_function( __FUNCTION__, '6.3.0' ); + if ( $t < 0 ) { ++$t; } @@ -155,6 +170,8 @@ function wp_tinycolor_hue_to_rgb( $p, $q, $t ) { * * @see https://github.com/bgrins/TinyColor * + * @deprecated 6.3.0 + * * @since 5.8.0 * @access private * @@ -162,6 +179,8 @@ function wp_tinycolor_hue_to_rgb( $p, $q, $t ) { * @return array Rounded and converted RGB object. */ function wp_tinycolor_hsl_to_rgb( $hsl_color ) { + _deprecated_function( __FUNCTION__, '6.3.0' ); + $h = wp_tinycolor_bound01( $hsl_color['h'], 360 ); $s = wp_tinycolor_bound01( $hsl_color['s'], 100 ); $l = wp_tinycolor_bound01( $hsl_color['l'], 100 ); @@ -196,6 +215,8 @@ function wp_tinycolor_hsl_to_rgb( $hsl_color ) { * @see https://github.com/bgrins/TinyColor * @see https://github.com/casesandberg/react-color/ * + * @deprecated 6.3.0 + * * @since 5.8.0 * @since 5.9.0 Added alpha processing. * @access private @@ -204,6 +225,8 @@ function wp_tinycolor_hsl_to_rgb( $hsl_color ) { * @return array RGB object. */ function wp_tinycolor_string_to_rgb( $color_str ) { + _deprecated_function( __FUNCTION__, '6.3.0' ); + $color_str = strtolower( trim( $color_str ) ); $css_integer = '[-\\+]?\\d+%?'; @@ -393,80 +416,13 @@ function wp_get_duotone_filter_property( $preset ) { * @since 5.9.1 * @access private * + * @deprecated 6.3.0 + * * @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(), - ); - - 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 ); - - $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; +function wp_get_duotone_filter_svg( $preset ) {_deprecated_function( __FUNCTION__, '6.3.0' ); + return WP_Duotone::get_filter_svg_from_preset( $preset ); } /** diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index 6cdf956b2b9e9..6da5091384f4d 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -2,6 +2,32 @@ /** * WP_Duotone class * + * Parts of this source were derived and modified from colord, + * released under the MIT license. + * + * https://github.com/omgovich/colord + * + * Copyright (c) 2020 Vlad Shilov omgovich@ya.ru + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * * @package WordPress * @since 6.3.0 */ @@ -73,6 +99,321 @@ class WP_Duotone { */ const CSS_VAR_PREFIX = '--wp--preset--duotone--'; + /** + * Direct port of colord's clamp function. Using min/max instead of + * nested ternaries. + * + * @see https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/helpers.ts#L23 + * + * @param float $number The number to clamp. + * @param float $min The minimum value. + * @param float $max The maximum value. + * @return float The clamped value. + */ + private static function colord_clamp( $number, $min = 0, $max = 1 ) { + return $number > $max ? $max : ( $number > $min ? $number : $min ); + } + + /** + * Direct port of colord's clampHue function. + * + * @see https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/helpers.ts#L32 + * + * @param float $degrees The hue to clamp. + * @return float The clamped hue. + */ + private static function colord_clamp_hue( $degrees ) { + $degrees = is_finite( $degrees ) ? $degrees % 360 : 0; + return $degrees > 0 ? $degrees : $degrees + 360; + } + + /** + * Direct port of colord's parseHue function. + * + * @see https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/helpers.ts#L40 + * + * @param float $value The hue value to parse. + * @param string $unit The unit of the hue value. + * @return float The parsed hue value. + */ + private static function colord_parse_hue( $value, $unit = 'deg' ) { + $angle_units = array( + 'grad' => 360 / 400, + 'turn' => 360, + 'rad' => 360 / ( M_PI * 2 ), + ); + + $factor = $angle_units[ $unit ]; + if ( ! $factor ) { + $factor = 1; + } + + return (float) $value * $factor; + } + + /** + * Direct port of colord's parseHex function. + * + * @see https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colorModels/hex.ts#L8 + * + * @param string $hex The hex string to parse. + * @return array|null An array of RGBA values or null if the hex string is invalid. + */ + private static function colord_parse_hex( $hex ) { + $is_match = preg_match( + '/^#([0-9a-f]{3,8})$/i', + $hex, + $hex_match + ); + + if ( ! $is_match ) { + return null; + } + + $hex = $hex_match[1]; + + if ( 4 >= strlen( $hex ) ) { + return array( + 'r' => (int) base_convert( $hex[0] . $hex[0], 16, 10 ), + 'g' => (int) base_convert( $hex[1] . $hex[1], 16, 10 ), + 'b' => (int) base_convert( $hex[2] . $hex[2], 16, 10 ), + 'a' => 4 === strlen( $hex ) ? round( base_convert( $hex[3] . $hex[3], 16, 10 ) / 255, 2 ) : 1, + ); + } + + if ( 6 === strlen( $hex ) || 8 === strlen( $hex ) ) { + return array( + 'r' => (int) base_convert( substr( $hex, 0, 2 ), 16, 10 ), + 'g' => (int) base_convert( substr( $hex, 2, 2 ), 16, 10 ), + 'b' => (int) base_convert( substr( $hex, 4, 2 ), 16, 10 ), + 'a' => 8 === strlen( $hex ) ? round( (int) base_convert( substr( $hex, 6, 2 ), 16, 10 ) / 255, 2 ) : 1, + ); + } + + return null; + } + + /** + * Direct port of colord's clampRgba function. + * + * @see https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colorModels/rgb.ts#L5 + * + * @param array $rgba The RGBA array to clamp. + * @return array The clamped RGBA array. + */ + private static function colord_clamp_rgba( $rgba ) { + $rgba['r'] = self::colord_clamp( $rgba['r'], 0, 255 ); + $rgba['g'] = self::colord_clamp( $rgba['g'], 0, 255 ); + $rgba['b'] = self::colord_clamp( $rgba['b'], 0, 255 ); + $rgba['a'] = self::colord_clamp( $rgba['a'] ); + + return $rgba; + } + + /** + * Direct port of colord's parseRgbaString function. + * + * @see https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colorModels/rgbString.ts#L18 + * + * @param string $input The RGBA string to parse. + * @return array|null An array of RGBA values or null if the RGB string is invalid. + */ + private static function colord_parse_rgba_string( $input ) { + // Functional syntax. + $is_match = preg_match( + '/^rgba?\(\s*([+-]?\d*\.?\d+)(%)?\s*,\s*([+-]?\d*\.?\d+)(%)?\s*,\s*([+-]?\d*\.?\d+)(%)?\s*(?:,\s*([+-]?\d*\.?\d+)(%)?\s*)?\)$/i', + $input, + $match + ); + + if ( ! $is_match ) { + // Whitespace syntax. + $is_match = preg_match( + '/^rgba?\(\s*([+-]?\d*\.?\d+)(%)?\s+([+-]?\d*\.?\d+)(%)?\s+([+-]?\d*\.?\d+)(%)?\s*(?:\/\s*([+-]?\d*\.?\d+)(%)?\s*)?\)$/i', + $input, + $match + ); + } + + if ( ! $is_match ) { + return null; + } + + // For some reason, preg_match doesn't include empty matches at the end + // of the array, so we add them manually to make things easier later. + for ( $i = 1; $i <= 8; $i++ ) { + if ( ! isset( $match[ $i ] ) ) { + $match[ $i ] = ''; + } + } + + if ( $match[2] !== $match[4] || $match[4] !== $match[6] ) { + return null; + } + + return self::colord_clamp_rgba( + array( + 'r' => (float) $match[1] / ( $match[2] ? 100 / 255 : 1 ), + 'g' => (float) $match[3] / ( $match[4] ? 100 / 255 : 1 ), + 'b' => (float) $match[5] / ( $match[6] ? 100 / 255 : 1 ), + 'a' => '' === $match[7] ? 1 : (float) $match[7] / ( $match[8] ? 100 : 1 ), + ) + ); + } + + /** + * Direct port of colord's clampHsla function. + * + * @see https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colorModels/hsl.ts#L6 + * + * @param array $hsla The HSLA array to clamp. + * @return array The clamped HSLA array. + */ + private static function colord_clamp_hsla( $hsla ) { + $hsla['h'] = self::colord_clamp_hue( $hsla['h'] ); + $hsla['s'] = self::colord_clamp( $hsla['s'], 0, 100 ); + $hsla['l'] = self::colord_clamp( $hsla['l'], 0, 100 ); + $hsla['a'] = self::colord_clamp( $hsla['a'] ); + + return $hsla; + } + + /** + * Direct port of colord's hsvaToRgba function. + * + * @see https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colorModels/hsv.ts#L52 + * + * @param array $hsva The HSVA array to convert. + * @return array The RGBA array. + */ + private static function colord_hsva_to_rgba( $hsva ) { + $h = ( $hsva['h'] / 360 ) * 6; + $s = $hsva['s'] / 100; + $v = $hsva['v'] / 100; + $a = $hsva['a']; + + $hh = floor( $h ); + $b = $v * ( 1 - $s ); + $c = $v * ( 1 - ( $h - $hh ) * $s ); + $d = $v * ( 1 - ( 1 - $h + $hh ) * $s ); + $module = $hh % 6; + + return array( + 'r' => array( $v, $c, $b, $b, $d, $v )[ $module ] * 255, + 'g' => array( $d, $v, $v, $c, $b, $b )[ $module ] * 255, + 'b' => array( $b, $b, $d, $v, $v, $c )[ $module ] * 255, + 'a' => $a, + ); + } + + /** + * Direct port of colord's hslaToHsva function. + * + * @see https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colorModels/hsl.ts#L33 + * + * @param array $hsla The HSLA array to convert. + * @return array The HSVA array. + */ + private static function colord_hsla_to_hsva( $hsla ) { + $h = $hsla['h']; + $s = $hsla['s']; + $l = $hsla['l']; + $a = $hsla['a']; + + $s *= ( $l < 50 ? $l : 100 - $l ) / 100; + + return array( + 'h' => $h, + 's' => $s > 0 ? ( ( 2 * $s ) / ( $l + $s ) ) * 100 : 0, + 'v' => $l + $s, + 'a' => $a, + ); + } + + /** + * Direct port of colord's hslaToRgba function. + * + * @see https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colorModels/hsl.ts#L55 + * + * @param array $hsla The HSLA array to convert. + * @return array The RGBA array. + */ + private static function colord_hsla_to_rgba( $hsla ) { + return self::colord_hsva_to_rgba( self::colord_hsla_to_hsva( $hsla ) ); + } + + /** + * Direct port of colord's parseHslaString function. + * + * @see https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colorModels/hslString.ts#L17 + * + * @param string $input The HSLA string to parse. + * @return array|null An array of RGBA values or null if the RGB string is invalid. + */ + private static function colord_parse_hsla_string( $input ) { + // Functional syntax. + $is_match = preg_match( + '/^hsla?\(\s*([+-]?\d*\.?\d+)(deg|rad|grad|turn)?\s*,\s*([+-]?\d*\.?\d+)%\s*,\s*([+-]?\d*\.?\d+)%\s*(?:,\s*([+-]?\d*\.?\d+)(%)?\s*)?\)$/i', + $input, + $match + ); + + if ( ! $is_match ) { + // Whitespace syntax. + $is_match = preg_match( + '/^hsla?\(\s*([+-]?\d*\.?\d+)(deg|rad|grad|turn)?\s+([+-]?\d*\.?\d+)%\s+([+-]?\d*\.?\d+)%\s*(?:\/\s*([+-]?\d*\.?\d+)(%)?\s*)?\)$/i', + $input, + $match + ); + } + + if ( ! $is_match ) { + return null; + } + + // For some reason, preg_match doesn't include empty matches at the end + // of the array, so we add them manually to make things easier later. + for ( $i = 1; $i <= 6; $i++ ) { + if ( ! isset( $match[ $i ] ) ) { + $match[ $i ] = ''; + } + } + + $hsla = self::colord_clamp_hsla( + array( + 'h' => self::colord_parse_hue( $match[1], $match[2] ), + 's' => (float) $match[3], + 'l' => (float) $match[4], + 'a' => '' === $match[5] ? 1 : (float) $match[5] / ( $match[6] ? 100 : 1 ), + ) + ); + + return self::colord_hsla_to_rgba( $hsla ); + } + + /** + * Direct port of colord's parse function simplified for our use case. This + * version only supports string parsing and only returns RGBA values. + * + * @see https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/parse.ts#L37 + * + * @param string $input The string to parse. + * @return array|null An array of RGBA values or null if the string is invalid. + */ + private static function colord_parse( $input ) { + $result = self::colord_parse_hex( $input ); + + if ( ! $result ) { + $result = self::colord_parse_rgba_string( $input ); + } + + if ( ! $result ) { + $result = self::colord_parse_hsla_string( $input ); + } + + return $result; + } + /** * 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. @@ -160,6 +501,80 @@ private static function get_css_custom_property_name( $slug ) { return self::CSS_VAR_PREFIX . $slug; } + /** + * Gets the SVG for the duotone filter definition. + * + * @param string $filter_id The ID of the filter. + * @param array $colors An array of color strings. + * @return string An SVG with a duotone filter definition. + */ + private static function get_filter_svg( $filter_id, $colors ) { + $duotone_values = array( + 'r' => array(), + 'g' => array(), + 'b' => array(), + 'a' => array(), + ); + + foreach ( $colors as $color_str ) { + $color = self::colord_parse( $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; + } + /** * Get the CSS variable for a duotone preset. * @@ -190,7 +605,7 @@ public static function output_footer_assets() { foreach ( self::$output as $filter_data ) { // SVG will be output on the page later. - $filter_svg = wp_get_duotone_filter_svg( $filter_data ); + $filter_svg = self::get_filter_svg_from_preset( $filter_data ); echo $filter_svg; @@ -213,7 +628,7 @@ public static function add_editor_settings( $settings ) { $duotone_svgs = ''; $duotone_css = 'body{'; foreach ( self::$global_styles_presets as $filter_data ) { - $duotone_svgs .= get_duotone_filter_svg( $filter_data ); + $duotone_svgs .= self::get_filter_svg_from_preset( $filter_data ); $duotone_css .= self::get_css_custom_property_declaration( $filter_data ); } $duotone_css .= '}'; @@ -240,6 +655,18 @@ public static function add_editor_settings( $settings ) { return $settings; } + /** + * Gets the SVG for the duotone filter definition from a preset. + * + * @param array $preset The duotone preset. + * @return string The SVG for the filter definition. + */ + public static function get_filter_svg_from_preset( $preset ) { + // TODO: This function will be refactored out in a follow-up PR where it will be deprecated. + $filter_id = get_duotone_filter_id( $preset ); + return self::get_filter_svg( $filter_id, $preset['colors'] ); + } + /** * Appends the used global style duotone filter CSS Vars to the inline global styles CSS */ From b6f01c642847e17713d5073d9ad58d60e7f739ce Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Thu, 15 Jun 2023 13:04:25 +0200 Subject: [PATCH 07/47] BP:Deprecate remaining global duotone functions #49702 --- src/wp-includes/block-supports/duotone.php | 87 ++++++++++++---------- src/wp-includes/class-wp-duotone.php | 80 ++++++++++++++++++-- 2 files changed, 122 insertions(+), 45 deletions(-) diff --git a/src/wp-includes/block-supports/duotone.php b/src/wp-includes/block-supports/duotone.php index 0b33bbc0cfcf8..5265f7f3287b4 100644 --- a/src/wp-includes/block-supports/duotone.php +++ b/src/wp-includes/block-supports/duotone.php @@ -32,6 +32,39 @@ * @since 5.8.0 */ +// Register duotone block supports. +WP_Block_Supports::get_instance()->register( + 'duotone', + array( + 'register_attribute' => array( 'WP_Duotone', 'register_duotone_support' ), + ) +); + +// Set up metadata prior to rendering any blocks. +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 ); + +// Remove WordPress core filter to avoid rendering duplicate support elements. +remove_filter( 'render_block', 'wp_render_duotone_support', 10, 2 ); +add_filter( 'render_block', array( 'WP_Duotone', 'render_duotone_support' ), 10, 2 ); + +// Enqueue styles. +// Global styles (global-styles-inline-css) after the other global styles (wp_enqueue_global_styles). +add_action( 'wp_enqueue_scripts', array( 'WP_Duotone', 'output_global_styles' ), 11 ); + +// Add SVG filters to the footer. Also, for classic themes, output block styles (core-block-supports-inline-css). +add_action( 'wp_footer', array( 'WP_Duotone', 'output_footer_assets' ), 10 ); + +// Add styles and SVGs for use in the editor via the EditorStyles component. +add_filter( 'block_editor_settings_all', array( 'WP_Duotone', 'add_editor_settings' ), 10 ); + +// Migrate the old experimental duotone support flag. +add_filter( 'block_type_metadata_settings', array( 'WP_Duotone', 'migrate_experimental_duotone_support_flag' ), 10, 2 ); + +/* + * Deprecated functions below. All new functions should be added in class-wp-duotone.php. + */ + /** * Takes input from [0, n] and returns it as [0, 1]. * @@ -380,16 +413,15 @@ function wp_tinycolor_string_to_rgb( $color_str ) { * * @since 5.9.1 * @access private + * + * @deprecated 6.3.0 * * @param array $preset Duotone preset value as seen in theme.json. * @return string Duotone filter CSS id. */ function wp_get_duotone_filter_id( $preset ) { - if ( ! isset( $preset['slug'] ) ) { - return ''; - } - - return 'wp-duotone-' . $preset['slug']; + _deprecated_function( __FUNCTION__, '6.3.0' ); + return WP_Duotone::get_filter_id_from_preset( $preset ); } /** @@ -398,16 +430,15 @@ function wp_get_duotone_filter_id( $preset ) { * @since 5.9.0 * @since 6.1.0 Allow unset for preset colors. * @access private + * + * @deprecated 6.3.0 * * @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 ) { - if ( isset( $preset['colors'] ) && 'unset' === $preset['colors'] ) { - return 'none'; - } - $filter_id = wp_get_duotone_filter_id( $preset ); - return "url('#" . $filter_id . "')"; + _deprecated_function( __FUNCTION__, '6.3.0' ); + return WP_Duotone::get_filter_css_property_value_from_preset( $preset ); } /** @@ -430,26 +461,14 @@ function wp_get_duotone_filter_svg( $preset ) {_deprecated_function( __FUNCTION_ * * @since 5.8.0 * @access private + * + * @deprecated 6.3.0 Use WP_Duotone::register_duotone_support() instead. * * @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', - ); - } - } + _deprecated_function( __FUNCTION__, '6.3.0', 'WP_Duotone::register_duotone_support' ); + return WP_Duotone::register_duotone_support( $block_type ); } /** @@ -458,6 +477,8 @@ function wp_register_duotone_support( $block_type ) { * @since 5.8.0 * @since 6.1.0 Allow unset for preset colors. * @access private + * + * @deprecated 6.3.0 Use WP_Duotone::render_duotone_support() instead. * * @param string $block_content Rendered block content. * @param array $block Block object. @@ -468,17 +489,3 @@ function wp_render_duotone_support( $block_content, $block ) { _deprecated_function( __FUNCTION__, '6.3.0', 'WP_Duotone::render_duotone_support' ); return WP_Duotone::render_duotone_support( $block_content, $block ); } - -// Register the block support. -WP_Block_Supports::get_instance()->register( - 'duotone', - array( - 'register_attribute' => 'wp_register_duotone_support', - ) -); -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 ); -add_filter( 'render_block', array( 'WP_Duotone', 'render_duotone_support' ), 10, 2 ); -add_action( 'wp_enqueue_scripts', array( 'WP_Duotone', 'output_global_styles' ), 11 ); -add_action( 'wp_footer', array( 'WP_Duotone', 'output_footer_assets' ), 10 ); -add_filter( 'block_editor_settings_all', array( 'WP_Duotone', 'add_editor_settings' ), 10 ); \ No newline at end of file diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index 6da5091384f4d..38d2bbd4c8b9f 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -99,6 +99,11 @@ class WP_Duotone { */ const CSS_VAR_PREFIX = '--wp--preset--duotone--'; + /** + * Prefix used for generating and referencing duotone filter IDs. + */ + const FILTER_ID_PREFIX = 'wp-duotone-'; + /** * Direct port of colord's clamp function. Using min/max instead of * nested ternaries. @@ -501,6 +506,16 @@ private static function get_css_custom_property_name( $slug ) { return self::CSS_VAR_PREFIX . $slug; } + /** + * Get the ID of the duotone filter. + * + * @param string $slug The slug of the duotone preset. + * @return string The ID of the duotone filter. + */ + private static function get_filter_id( $slug ) { + return self::FILTER_ID_PREFIX . $slug; + } + /** * Gets the SVG for the duotone filter definition. * @@ -593,7 +608,7 @@ private static function get_css_var( $slug ) { * @return string The CSS declaration. */ private static function get_css_custom_property_declaration( $filter_data ) { - $declaration_value = wp_get_duotone_filter_property( $filter_data ); + $declaration_value = self::get_filter_css_property_value_from_preset( $filter_data ); $duotone_preset_css_property_name = self::get_css_custom_property_name( $filter_data['slug'] ); return $duotone_preset_css_property_name . ': ' . $declaration_value . ';'; } @@ -655,6 +670,20 @@ public static function add_editor_settings( $settings ) { return $settings; } + /** + * Returns the prefixed id for the duotone filter for use as a CSS id. + * + * @param array $preset Duotone preset value as seen in theme.json. + * @return string Duotone filter CSS id. + */ + public static function get_filter_id_from_preset( $preset ) { + $filter_id = ''; + if ( isset( $preset['slug'] ) ) { + $filter_id = self::get_filter_id( $preset['slug'] ); + } + return $filter_id; + } + /** * Gets the SVG for the duotone filter definition from a preset. * @@ -662,8 +691,7 @@ public static function add_editor_settings( $settings ) { * @return string The SVG for the filter definition. */ public static function get_filter_svg_from_preset( $preset ) { - // TODO: This function will be refactored out in a follow-up PR where it will be deprecated. - $filter_id = get_duotone_filter_id( $preset ); + $filter_id = self::get_filter_id_from_preset( $preset ); return self::get_filter_svg( $filter_id, $preset['colors'] ); } @@ -691,6 +719,32 @@ public static function output_global_styles() { } } + /** + * Registers the style and colors block attributes for block types that support it. + * + * @param WP_Block_Type $block_type Block Type. + */ + public static function register_duotone_support( $block_type ) { + $has_duotone_support = false; + if ( property_exists( $block_type, 'supports' ) ) { + // Previous `color.__experimentalDuotone` support flag is migrated + // to `filter.duotone` via `block_type_metadata_settings` filter. + $has_duotone_support = _wp_array_get( $block_type->supports, array( 'filter', 'duotone' ), null ); + } + + 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', + ); + } + } + } + /** * Render out the duotone CSS styles and SVG. * @@ -756,7 +810,7 @@ public static function render_duotone_support( $block_content, $block ) { 'colors' => $duotone_attr, ); // Build a customized CSS filter property for unique slug. - $declaration_value = wp_get_duotone_filter_property( $filter_data ); + $declaration_value = self::get_filter_css_property_value_from_preset( $filter_data ); self::$output[ $slug ] = $filter_data; } @@ -771,7 +825,7 @@ public static function render_duotone_support( $block_content, $block ) { // - Applied as a class attribute to the block wrapper. // - Used as a selector to apply the filter to the block. - $filter_id = wp_get_duotone_filter_id( array( 'slug' => $slug ) ); + $filter_id = self::get_filter_id_from_preset( array( 'slug' => $slug ) ); // Build the CSS selectors to which the filter will be applied. $selector = WP_Theme_JSON::scope_selector( '.' . $filter_id, $duotone_support ); @@ -810,4 +864,20 @@ public static function render_duotone_support( $block_content, $block ) { } return $tags->get_updated_html(); } + + /** + * Gets the CSS filter property value from a preset. + * + * @param array $preset The duotone preset. + * @return string The CSS filter property value. + */ + public static function get_filter_css_property_value_from_preset( $preset ) { + if ( isset( $preset['colors'] ) && is_string( $preset['colors'] ) ) { + return $preset['colors']; + } + + $filter_id = self::get_filter_id_from_preset( $preset ); + + return 'url(#' . $filter_id . ')'; + } } From 035a10060d256c05e1ef7864b1260f175dff3aee Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Thu, 15 Jun 2023 16:49:25 +0200 Subject: [PATCH 08/47] BP - partially: Selectors API: Fix for global styles hook, style variations, and duotone #49393 --- src/wp-includes/class-wp-duotone.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index 38d2bbd4c8b9f..e02757e0c4ad2 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -755,9 +755,11 @@ public static function register_duotone_support( $block_type ) { public static function render_duotone_support( $block_content, $block ) { $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] ); - $duotone_support = false; - if ( $block_type && property_exists( $block_type, 'supports' ) ) { - $duotone_support = _wp_array_get( $block_type->supports, array( 'color', '__experimentalDuotone' ), false ); + $duotone_support = false; + $duotone_selector = null; + if ( $block_type ) { + $duotone_selector = wp_get_block_css_selector( $block_type, 'filter.duotone' ); + $duotone_support = (bool) $duotone_selector; } // The block should have a duotone attribute or have duotone defined in its theme.json to be processed. @@ -828,7 +830,7 @@ public static function render_duotone_support( $block_content, $block ) { $filter_id = self::get_filter_id_from_preset( array( 'slug' => $slug ) ); // Build the CSS selectors to which the filter will be applied. - $selector = WP_Theme_JSON::scope_selector( '.' . $filter_id, $duotone_support ); + $selector = WP_Theme_JSON::scope_selector( '.' . $filter_id, $duotone_selector ); // We only want to add the selector if we have it in the output already, essentially skipping 'unset'. if ( array_key_exists( $slug, self::$output ) ) { From 83e3c2a8731cbb674751b052fdb8fd52253080a3 Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Thu, 15 Jun 2023 16:56:02 +0200 Subject: [PATCH 09/47] BP - partially: Selectors API: Make duotone selectors fallback and be scoped #4942 --- src/wp-includes/class-wp-duotone.php | 78 ++++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 10 deletions(-) diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index e02757e0c4ad2..364675d93e8f6 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -745,6 +745,42 @@ public static function register_duotone_support( $block_type ) { } } + /** + * Get the CSS selector for a block type. + * + * @param string $block_name The block name. + * + * @return string The CSS selector or null if there is no support. + */ + private static function get_selector( $block_name ) { + $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block_name ); + + if ( $block_type && property_exists( $block_type, 'supports' ) ) { + // Backwards compatibility with `supports.color.__experimentalDuotone` + // is provided via the `block_type_metadata_settings` filter. If + // `supports.filter.duotone` has not been set and the experimental + // property has been, the experimental property value is copied into + // `supports.filter.duotone`. + $duotone_support = _wp_array_get( $block_type->supports, array( 'filter', 'duotone' ), false ); + if ( ! $duotone_support ) { + return null; + } + + // If the experimental duotone support was set, that value is to be + // treated as a selector and requires scoping. + $experimental_duotone = _wp_array_get( $block_type->supports, array( 'color', '__experimentalDuotone' ), false ); + if ( $experimental_duotone ) { + $root_selector = wp_get_block_css_selector( $block_type ); + return is_string( $experimental_duotone ) + ? WP_Theme_JSON::scope_selector( $root_selector, $experimental_duotone ) + : $root_selector; + } + + // Regular filter.duotone support uses filter.duotone selectors with fallbacks. + return wp_get_block_css_selector( $block_type, array( 'filter', 'duotone' ), true ); + } + } + /** * Render out the duotone CSS styles and SVG. * @@ -753,14 +789,7 @@ public static function register_duotone_support( $block_type ) { * @return string Filtered block content. */ public static function render_duotone_support( $block_content, $block ) { - $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] ); - - $duotone_support = false; - $duotone_selector = null; - if ( $block_type ) { - $duotone_selector = wp_get_block_css_selector( $block_type, 'filter.duotone' ); - $duotone_support = (bool) $duotone_selector; - } + $duotone_selector = self::get_selector( $block['blockName'] ); // 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'] ); @@ -768,7 +797,7 @@ public static function render_duotone_support( $block_content, $block ) { if ( empty( $block_content ) || - ! $duotone_support || + ! $duotone_selector || ( ! $has_duotone_attribute && ! $has_global_styles_duotone ) ) { return $block_content; @@ -830,7 +859,17 @@ public static function render_duotone_support( $block_content, $block ) { $filter_id = self::get_filter_id_from_preset( array( 'slug' => $slug ) ); // Build the CSS selectors to which the filter will be applied. - $selector = WP_Theme_JSON::scope_selector( '.' . $filter_id, $duotone_selector ); + $selectors = explode( ',', $duotone_selector ); + + $selectors_scoped = array(); + foreach ( $selectors as $selector_part ) { + // Assuming the selector part is a subclass selector (not a tag name) + // so we can prepend the filter id class. If we want to support elements + // such as `img` or namespaces, we'll need to add a case for that here. + $selectors_scoped[] = '.' . $filter_id . trim( $selector_part ); + } + + $selector = implode( ', ', $selectors_scoped ); // We only want to add the selector if we have it in the output already, essentially skipping 'unset'. if ( array_key_exists( $slug, self::$output ) ) { @@ -866,6 +905,25 @@ public static function render_duotone_support( $block_content, $block ) { } return $tags->get_updated_html(); } + + /** + * Migrate the old experimental duotone support flag to its stabilized location + * under `supports.filter.duotone` and sets. + * + * @param array $settings Current block type settings. + * @param array $metadata Block metadata as read in via block.json. + * + * @return array Filtered block type settings. + */ + public static function migrate_experimental_duotone_support_flag( $settings, $metadata ) { + $duotone_support = _wp_array_get( $metadata, array( 'supports', 'color', '__experimentalDuotone' ), null ); + + if ( ! isset( $settings['supports']['filter']['duotone'] ) && null !== $duotone_support ) { + _wp_array_set( $settings, array( 'supports', 'filter', 'duotone' ), (bool) $duotone_support ); + } + + return $settings; + } /** * Gets the CSS filter property value from a preset. From 3777e20cf050eb8fc09254fa5e4b98e82f20ef49 Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Thu, 15 Jun 2023 17:04:07 +0200 Subject: [PATCH 10/47] BP: Group duotone outputs and refactor rendering #49705 --- src/wp-includes/block-supports/duotone.php | 2 + src/wp-includes/class-wp-duotone.php | 360 +++++++++++++-------- 2 files changed, 229 insertions(+), 133 deletions(-) diff --git a/src/wp-includes/block-supports/duotone.php b/src/wp-includes/block-supports/duotone.php index 5265f7f3287b4..f13798cdd2ed4 100644 --- a/src/wp-includes/block-supports/duotone.php +++ b/src/wp-includes/block-supports/duotone.php @@ -49,7 +49,9 @@ add_filter( 'render_block', array( 'WP_Duotone', 'render_duotone_support' ), 10, 2 ); // Enqueue styles. +// Block styles (core-block-supports-inline-css) before the style engine (wp_enqueue_stored_styles). // Global styles (global-styles-inline-css) after the other global styles (wp_enqueue_global_styles). +add_action( 'wp_enqueue_scripts', array( 'WP_Duotone', 'output_block_styles' ), 9 ); add_action( 'wp_enqueue_scripts', array( 'WP_Duotone', 'output_global_styles' ), 11 ); // Add SVG filters to the footer. Also, for classic themes, output block styles (core-block-supports-inline-css). diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index 364675d93e8f6..91ad5b7962d64 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -74,17 +74,17 @@ class WP_Duotone { /** * An array of Duotone SVG and CSS output needed for the frontend duotone rendering based on what is - * being output on the page. Organized by a slug of the preset/color group and the information needed + * being output on the page. Organized by an id of the preset/color group and the information needed * to generate the SVG and CSS at render. * * Example: * [ - * 'blue-orange' => [ + * 'wp-duotone-blue-orange' => [ * 'slug' => 'blue-orange', * 'colors' => [ '#0000ff', '#ffcc00' ], * ], * 'wp-duotone-000000-ffffff-2' => [ - * 'slug' => 'wp-duotone-000000-ffffff-2', + * 'slug' => '000000-ffffff-2', * 'colors' => [ '#000000', '#ffffff' ], * ], * ] @@ -92,7 +92,42 @@ class WP_Duotone { * @since 6.3.0 * @var array */ - private static $output = array(); + private static $used_svg_filter_data = array(); + + /** + * All of the duotone filter data from presets for CSS custom properties on + * the page. + * + * Example: + * [ + * 'wp-duotone-blue-orange' => [ + * 'slug' => 'blue-orange', + * 'colors' => [ '#0000ff', '#ffcc00' ], + * ], + * … + * ] + * + * @var array + */ + private static $used_global_styles_presets = array(); + + /** + * All of the block CSS declarations for styles on the page. + * + * Example: + * [ + * [ + * 'selector' => '.wp-duotone-000000-ffffff-2.wp-block-image img', + * 'declarations' => [ + * 'filter' => 'url(#wp-duotone-000000-ffffff-2)', + * ], + * ], + * … + * ] + * + * @var array + */ + private static $block_css_declarations = array(); /** * Prefix used for generating and referencing duotone CSS custom properties. @@ -430,10 +465,8 @@ public static function set_global_styles_presets() { 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'], - ); + $filter_id = self::get_filter_id( _wp_to_kebab_case( $preset['slug'] ) ); + self::$global_styles_presets[ $filter_id ] = $preset; } } } @@ -491,9 +524,10 @@ private static function wp_get_slug_from_attr( $duotone_attr ) { * @return bool True if the duotone preset present and valid. */ private static function is_preset( $duotone_attr ) { - $slug = self::wp_get_slug_from_attr( $duotone_attr ); + $slug = self::wp_get_slug_from_attr( $duotone_attr ); + $filter_id = self::get_filter_id( $slug ); - return array_key_exists( $slug, self::$global_styles_presets ); + return array_key_exists( $filter_id, self::$global_styles_presets ); } /** @@ -516,6 +550,16 @@ private static function get_filter_id( $slug ) { return self::FILTER_ID_PREFIX . $slug; } + /** + * Get the URL for a duotone filter. + * + * @param string $filter_id The ID of the filter. + * @return string The URL for the duotone filter. + */ + private static function get_filter_url( $filter_id ) { + return 'url(#' . $filter_id . ')'; + } + /** * Gets the SVG for the duotone filter definition. * @@ -600,34 +644,17 @@ private static function get_css_var( $slug ) { return 'var(' . self::get_css_custom_property_name( $slug ) . ')'; } - /** - * Get the CSS declaration for a duotone preset. - * Example: --wp--preset--duotone--blue-orange: url('#wp-duotone-blue-orange'); - * - * @param array $filter_data The duotone data for presets and custom filters. - * @return string The CSS declaration. - */ - private static function get_css_custom_property_declaration( $filter_data ) { - $declaration_value = self::get_filter_css_property_value_from_preset( $filter_data ); - $duotone_preset_css_property_name = self::get_css_custom_property_name( $filter_data['slug'] ); - return $duotone_preset_css_property_name . ': ' . $declaration_value . ';'; - } - /** * Outputs all necessary SVG for duotone filters, CSS for classic themes. */ public static function output_footer_assets() { - foreach ( self::$output as $filter_data ) { - - // SVG will be output on the page later. - $filter_svg = self::get_filter_svg_from_preset( $filter_data ); - - echo $filter_svg; + if ( ! empty( self::$used_svg_filter_data ) ) { + echo self::get_svg_definitions( self::$used_svg_filter_data ); + } - // This is for classic themes - in block themes, the CSS is added in the head via wp_add_inline_style in the wp_enqueue_scripts action. - if ( ! wp_is_block_theme() ) { - wp_add_inline_style( 'core-block-supports', 'body{' . self::get_css_custom_property_declaration( $filter_data ) . '}' ); - } + // This is for classic themes - in block themes, the CSS is added in the head via wp_add_inline_style in the wp_enqueue_scripts action. + if ( ! wp_is_block_theme() && ! empty( self::$used_global_styles_presets ) ) { + wp_add_inline_style( 'core-block-supports', self::get_global_styles_presets( self::$used_global_styles_presets ) ); } } @@ -640,32 +667,29 @@ public static function output_footer_assets() { * @return array The editor settings with duotone SVGs and CSS custom properties. */ public static function add_editor_settings( $settings ) { - $duotone_svgs = ''; - $duotone_css = 'body{'; - foreach ( self::$global_styles_presets as $filter_data ) { - $duotone_svgs .= self::get_filter_svg_from_preset( $filter_data ); - $duotone_css .= self::get_css_custom_property_declaration( $filter_data ); - } - $duotone_css .= '}'; - - if ( ! isset( $settings['styles'] ) ) { - $settings['styles'] = array(); - } + if ( ! empty( self::$global_styles_presets ) ) { + if ( ! isset( $settings['styles'] ) ) { + $settings['styles'] = array(); + } - $settings['styles'][] = array( - 'assets' => $duotone_svgs, - // The 'svgs' type is new in 6.3 and requires the corresponding JS changes in the EditorStyles component to work. - '__unstableType' => 'svgs', - 'isGlobalStyles' => false, - ); + $settings['styles'][] = array( + // For the editor we can add all of the presets by default. + 'assets' => self::get_svg_definitions( self::$global_styles_presets ), + // The 'svgs' type is new in 6.3 and requires the corresponding JS changes in the EditorStyles component to work. + '__unstableType' => 'svgs', + // These styles not generated by global styles, so this must be false or they will be stripped out in wp_get_block_editor_settings. + 'isGlobalStyles' => false, + ); - $settings['styles'][] = array( - 'css' => $duotone_css, - // This must be set and must be something other than 'theme' or they will be stripped out in the post editor component. - '__unstableType' => 'presets', - // These styles are no longer generated by global styles, so this must be false or they will be stripped out in get_block_editor_settings. - 'isGlobalStyles' => false, - ); + $settings['styles'][] = array( + // For the editor we can add all of the presets by default. + 'css' => self::get_global_styles_presets( self::$global_styles_presets ), + // This must be set and must be something other than 'theme' or they will be stripped out in the post editor component. + '__unstableType' => 'presets', + // These styles are no longer generated by global styles, so this must be false or they will be stripped out in wp_get_block_editor_settings. + 'isGlobalStyles' => false, + ); + } return $settings; } @@ -673,10 +697,17 @@ public static function add_editor_settings( $settings ) { /** * Returns the prefixed id for the duotone filter for use as a CSS id. * + * Exported for the deprecated function wp_get_duotone_filter_id(). + * + * @since 6.3.0 + * @deprecated 6.3.0 + * * @param array $preset Duotone preset value as seen in theme.json. * @return string Duotone filter CSS id. */ public static function get_filter_id_from_preset( $preset ) { + _deprecated_function( __FUNCTION__, '6.3.0' ); + $filter_id = ''; if ( isset( $preset['slug'] ) ) { $filter_id = self::get_filter_id( $preset['slug'] ); @@ -687,10 +718,17 @@ public static function get_filter_id_from_preset( $preset ) { /** * Gets the SVG for the duotone filter definition from a preset. * + * Exported for the deprecated function wp_get_duotone_filter_property(). + * + * @since 6.3.0 + * @deprecated 6.3.0 + * * @param array $preset The duotone preset. * @return string The SVG for the filter definition. */ public static function get_filter_svg_from_preset( $preset ) { + _deprecated_function( __FUNCTION__, '6.3.0' ); + $filter_id = self::get_filter_id_from_preset( $preset ); return self::get_filter_svg( $filter_id, $preset['colors'] ); } @@ -700,23 +738,117 @@ public static function get_filter_svg_from_preset( $preset ) { */ public static function output_global_styles() { - if ( empty( self::$output ) ) { - return; + if ( ! empty( self::$used_global_styles_presets ) ) { + wp_add_inline_style( 'global-styles', self::get_global_styles_presets( self::$used_global_styles_presets ) ); } + } - $duotone_css_vars = ''; + /** + * Appends the used block duotone filter declarations to the inline block supports CSS. + */ + public static function output_block_styles() { + if ( ! empty( self::$block_css_declarations ) ) { + wp_style_engine_get_stylesheet_from_css_rules( + self::$block_css_declarations, + array( + 'context' => 'block-supports', + ) + ); + } + } - foreach ( self::$output as $filter_data ) { - if ( ! array_key_exists( $filter_data['slug'], self::$global_styles_presets ) ) { - continue; - } + /** + * Get the SVGs for the duotone filters. + * + * Example output: + * + * + * @param array $sources The duotone presets. + * @return string The SVGs for the duotone filters. + */ + private static function get_svg_definitions( $sources ) { + $svgs = ''; + foreach ( $sources as $filter_id => $filter_data ) { + $colors = $filter_data['colors']; + $svgs .= self::get_filter_svg( $filter_id, $colors ); + } + return $svgs; + } - $duotone_css_vars .= self::get_css_custom_property_declaration( $filter_data ); + /** + * Get the CSS for global styles. + * + * Example output: + * body{--wp--preset--duotone--blue-orange:url('#wp-duotone-blue-orange');} + * + * @param array $sources The duotone presets. + * @return string The CSS for global styles. + */ + private static function get_global_styles_presets( $sources ) { + $css = 'body{'; + foreach ( $sources as $filter_id => $filter_data ) { + $slug = $filter_data['slug']; + $colors = $filter_data['colors']; + $css_property_name = self::get_css_custom_property_name( $slug ); + $declaration_value = is_string( $colors ) ? $colors : self::get_filter_url( $filter_id ); + $css .= $css_property_name . ':' . $declaration_value . ';'; } + $css .= '}'; + return $css; + } + + /** + * Enqueue a block CSS declaration for the page. + * + * @param string $filter_id The filter ID. e.g. 'wp-duotone-000000-ffffff-2'. + * @param string $duotone_selector The block's duotone selector. e.g. '.wp-block-image img'. + * @param string $filter_value The filter CSS value. e.g. 'url(#wp-duotone-000000-ffffff-2)' or 'unset'. + */ + private static function enqueue_block_css( $filter_id, $duotone_selector, $filter_value ) { + // Build the CSS selectors to which the filter will be applied. + $selectors = explode( ',', $duotone_selector ); - if ( ! empty( $duotone_css_vars ) ) { - wp_add_inline_style( 'global-styles', 'body{' . $duotone_css_vars . '}' ); + $selectors_scoped = array(); + foreach ( $selectors as $selector_part ) { + // Assuming the selector part is a subclass selector (not a tag name) + // so we can prepend the filter id class. If we want to support elements + // such as `img` or namespaces, we'll need to add a case for that here. + $selectors_scoped[] = '.' . $filter_id . trim( $selector_part ); } + + $selector = implode( ', ', $selectors_scoped ); + + self::$block_css_declarations[] = array( + 'selector' => $selector, + 'declarations' => array( + 'filter' => $filter_value, + ), + ); + } + + /** + * Enqueue custom filter assets for the page. Includes an SVG filter and block CSS declaration. + * + * @param string $filter_id The filter ID. e.g. 'wp-duotone-000000-ffffff-2'. + * @param string $duotone_selector The block's duotone selector. e.g. '.wp-block-image img'. + * @param string $filter_value The filter CSS value. e.g. 'url(#wp-duotone-000000-ffffff-2)' or 'unset'. + * @param array $filter_data Duotone filter data with 'slug' and 'colors' keys. + */ + private static function enqueue_custom_filter( $filter_id, $duotone_selector, $filter_value, $filter_data ) { + self::$used_svg_filter_data[ $filter_id ] = $filter_data; + self::enqueue_block_css( $filter_id, $duotone_selector, $filter_value ); + } + + /** + * Enqueue preset assets for the page. Includes a CSS custom property, SVG filter, and block CSS declaration. + * + * @param string $filter_id The filter ID. e.g. 'wp-duotone-blue-orange'. + * @param string $duotone_selector The block's duotone selector. e.g. '.wp-block-image img'. + * @param string $filter_value The filter CSS value. e.g. 'url(#wp-duotone-blue-orange)' or 'unset'. + */ + private static function enqueue_global_styles_preset( $filter_id, $duotone_selector, $filter_value ) { + self::$used_global_styles_presets[ $filter_id ] = self::$global_styles_presets[ $filter_id ]; + self::enqueue_custom_filter( $filter_id, $duotone_selector, $filter_value, self::$global_styles_presets[ $filter_id ] ); } /** @@ -818,86 +950,41 @@ public static function render_duotone_support( $block_content, $block ) { if ( $is_preset ) { - // Extract the slug from the preset variable string. - $slug = self::wp_get_slug_from_attr( $duotone_attr ); + $slug = self::wp_get_slug_from_attr( $duotone_attr ); // e.g. 'green-blue'. + $filter_id = self::get_filter_id( $slug ); // e.g. 'wp-duotone-filter-green-blue'. + $filter_value = self::get_css_var( $slug ); // e.g. 'var(--wp--preset--duotone--green-blue)'. - // Utilize existing preset CSS custom property. - $declaration_value = self::get_css_var( $slug ); - - self::$output[ $slug ] = self::$global_styles_presets[ $slug ]; + // CSS custom property, SVG filter, and block CSS. + self::enqueue_global_styles_preset( $filter_id, $duotone_selector, $filter_value ); } elseif ( $is_css ) { - // Build a unique slug for the filter based on the CSS value. - $slug = wp_unique_id( sanitize_key( $duotone_attr . '-' ) ); + $slug = wp_unique_id( sanitize_key( $duotone_attr . '-' ) ); // e.g. 'unset-1'. + $filter_id = self::get_filter_id( $slug ); // e.g. 'wp-duotone-filter-unset-1'. + $filter_value = $duotone_attr; // e.g. 'unset'. - // Pass through the CSS value. - $declaration_value = $duotone_attr; + // Just block CSS. + self::enqueue_block_css( $filter_id, $duotone_selector, $filter_value ); } 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 = wp_unique_id( sanitize_key( implode( '-', $duotone_attr ) . '-' ) ); // e.g. '000000-ffffff-2'. + $filter_id = self::get_filter_id( $slug ); // e.g. 'wp-duotone-filter-000000-ffffff-2'. + $filter_value = self::get_filter_url( $filter_id ); // e.g. 'url(#wp-duotone-filter-000000-ffffff-2)'. + $filter_data = array( 'slug' => $slug, 'colors' => $duotone_attr, ); - // Build a customized CSS filter property for unique slug. - $declaration_value = self::get_filter_css_property_value_from_preset( $filter_data ); - self::$output[ $slug ] = $filter_data; + // SVG filter and block CSS. + self::enqueue_custom_filter( $filter_id, $duotone_selector, $filter_value, $filter_data ); } } elseif ( $has_global_styles_duotone ) { - $slug = self::$global_styles_block_names[ $block['blockName'] ]; + $slug = self::$global_styles_block_names[ $block['blockName'] ]; // e.g. 'green-blue'. + $filter_id = self::get_filter_id( $slug ); // e.g. 'wp-duotone-filter-green-blue'. + $filter_value = self::get_css_var( $slug ); // e.g. 'var(--wp--preset--duotone--green-blue)'. - // Utilize existing preset CSS custom property. - $declaration_value = self::get_css_var( $slug ); - - self::$output[ $slug ] = self::$global_styles_presets[ $slug ]; + // CSS custom property, SVG filter, and block CSS. + self::enqueue_global_styles_preset( $filter_id, $duotone_selector, $filter_value ); } - // - Applied as a class attribute to the block wrapper. - // - Used as a selector to apply the filter to the block. - $filter_id = self::get_filter_id_from_preset( array( 'slug' => $slug ) ); - - // Build the CSS selectors to which the filter will be applied. - $selectors = explode( ',', $duotone_selector ); - - $selectors_scoped = array(); - foreach ( $selectors as $selector_part ) { - // Assuming the selector part is a subclass selector (not a tag name) - // so we can prepend the filter id class. If we want to support elements - // such as `img` or namespaces, we'll need to add a case for that here. - $selectors_scoped[] = '.' . $filter_id . trim( $selector_part ); - } - - $selector = implode( ', ', $selectors_scoped ); - - // We only want to add the selector if we have it in the output already, essentially skipping 'unset'. - if ( array_key_exists( $slug, self::$output ) ) { - self::$output[ $slug ]['selector'] = $selector; - } - - // Pass styles to the block-supports stylesheet via the style engine. - // This ensures that Duotone styles are included in a single stylesheet, - // avoiding multiple style tags or multiple stylesheets being output to - // the site frontend. - wp_style_engine_get_stylesheet_from_css_rules( - array( - array( - 'selector' => $selector, - 'declarations' => array( - // !important is needed because these styles - // render before global styles, - // and they should be overriding the duotone - // filters set by global styles. - 'filter' => $declaration_value . ' !important', - ), - ), - ), - array( - 'context' => 'block-supports', - ) - ); - // Like the layout hook, this assumes the hook only applies to blocks with a single wrapper. $tags = new WP_HTML_Tag_Processor( $block_content ); if ( $tags->next_tag() ) { @@ -928,10 +1015,17 @@ public static function migrate_experimental_duotone_support_flag( $settings, $me /** * Gets the CSS filter property value from a preset. * + * Exported for the deprecated function wp_get_duotone_filter_id(). + * + * @since 6.3.0 + * @deprecated 6.3.0 + * * @param array $preset The duotone preset. * @return string The CSS filter property value. */ public static function get_filter_css_property_value_from_preset( $preset ) { + _deprecated_function( __FUNCTION__, '6.3.0' ); + if ( isset( $preset['colors'] ) && is_string( $preset['colors'] ) ) { return $preset['colors']; } From 347145775c233379ffc96090c76f3e984968d8bf Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Thu, 15 Jun 2023 17:21:44 +0200 Subject: [PATCH 11/47] BP: Polish duotone rendering code #49706 --- src/wp-includes/block-supports/duotone.php | 25 +- src/wp-includes/class-wp-duotone.php | 385 +++++++++--------- .../phpunit/tests/block-supports/duotone.php | 8 +- 3 files changed, 202 insertions(+), 216 deletions(-) diff --git a/src/wp-includes/block-supports/duotone.php b/src/wp-includes/block-supports/duotone.php index f13798cdd2ed4..e49e60211a645 100644 --- a/src/wp-includes/block-supports/duotone.php +++ b/src/wp-includes/block-supports/duotone.php @@ -32,7 +32,7 @@ * @since 5.8.0 */ -// Register duotone block supports. +// Register the block support. WP_Block_Supports::get_instance()->register( 'duotone', array( @@ -40,29 +40,6 @@ ) ); -// Set up metadata prior to rendering any blocks. -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 ); - -// Remove WordPress core filter to avoid rendering duplicate support elements. -remove_filter( 'render_block', 'wp_render_duotone_support', 10, 2 ); -add_filter( 'render_block', array( 'WP_Duotone', 'render_duotone_support' ), 10, 2 ); - -// Enqueue styles. -// Block styles (core-block-supports-inline-css) before the style engine (wp_enqueue_stored_styles). -// Global styles (global-styles-inline-css) after the other global styles (wp_enqueue_global_styles). -add_action( 'wp_enqueue_scripts', array( 'WP_Duotone', 'output_block_styles' ), 9 ); -add_action( 'wp_enqueue_scripts', array( 'WP_Duotone', 'output_global_styles' ), 11 ); - -// Add SVG filters to the footer. Also, for classic themes, output block styles (core-block-supports-inline-css). -add_action( 'wp_footer', array( 'WP_Duotone', 'output_footer_assets' ), 10 ); - -// Add styles and SVGs for use in the editor via the EditorStyles component. -add_filter( 'block_editor_settings_all', array( 'WP_Duotone', 'add_editor_settings' ), 10 ); - -// Migrate the old experimental duotone support flag. -add_filter( 'block_type_metadata_settings', array( 'WP_Duotone', 'migrate_experimental_duotone_support_flag' ), 10, 2 ); - /* * Deprecated functions below. All new functions should be added in class-wp-duotone.php. */ diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index 91ad5b7962d64..a8a2895e07653 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -33,33 +33,14 @@ */ /** - * Manages which duotone filters need to be output on the page. + * Manages duotone block supports and global styles. * * @access public */ class WP_Duotone { /** - * An array of Duotone presets from global, theme, and custom styles. - * - * Example: - * [ - * 'blue-orange' => - * [ - * 'slug' => 'blue-orange', - * 'colors' => [ '#0000ff', '#ffcc00' ], - * ] - * ], - * … - * ] - * - * @since 6.3.0 - * @var array - */ - private 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. + * Block names from global, theme, and custom styles that use duotone presets and the slug of + * the preset they are using. * * Example: * [ @@ -67,15 +48,12 @@ class WP_Duotone { * … * ] * - * @since 6.3.0 * @var array */ private static $global_styles_block_names = array(); /** - * An array of Duotone SVG and CSS output needed for the frontend duotone rendering based on what is - * being output on the page. Organized by an id of the preset/color group and the information needed - * to generate the SVG and CSS at render. + * An array of duotone filter data from global, theme, and custom presets. * * Example: * [ @@ -83,16 +61,16 @@ class WP_Duotone { * 'slug' => 'blue-orange', * 'colors' => [ '#0000ff', '#ffcc00' ], * ], - * 'wp-duotone-000000-ffffff-2' => [ - * 'slug' => '000000-ffffff-2', - * 'colors' => [ '#000000', '#ffffff' ], + * 'wp-duotone-red-yellow' => [ + * 'slug' => 'red-yellow', + * 'colors' => [ '#cc0000', '#ffff33' ], * ], - * ] + * … + * ] * - * @since 6.3.0 * @var array */ - private static $used_svg_filter_data = array(); + private static $global_styles_presets = array(); /** * All of the duotone filter data from presets for CSS custom properties on @@ -111,6 +89,27 @@ class WP_Duotone { */ private static $used_global_styles_presets = array(); + /** + * All of the duotone filter data for SVGs on the page. Includes both + * presets and custom filters. + * + * Example: + * [ + * 'wp-duotone-blue-orange' => [ + * 'slug' => 'blue-orange', + * 'colors' => [ '#0000ff', '#ffcc00' ], + * ], + * 'wp-duotone-000000-ffffff-2' => [ + * 'slug' => '000000-ffffff-2', + * 'colors' => [ '#000000', '#ffffff' ], + * ], + * … + * ] + * + * @var array + */ + private static $used_svg_filter_data = array(); + /** * All of the block CSS declarations for styles on the page. * @@ -129,16 +128,6 @@ class WP_Duotone { */ private static $block_css_declarations = array(); - /** - * Prefix used for generating and referencing duotone CSS custom properties. - */ - const CSS_VAR_PREFIX = '--wp--preset--duotone--'; - - /** - * Prefix used for generating and referencing duotone filter IDs. - */ - const FILTER_ID_PREFIX = 'wp-duotone-'; - /** * Direct port of colord's clamp function. Using min/max instead of * nested ternaries. @@ -454,63 +443,15 @@ private static function colord_parse( $input ) { return $result; } - /** - * 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. - */ - public static function set_global_styles_presets() { - // Get the per block settings from the theme.json. - $tree = wp_get_global_settings(); - $presets_by_origin = _wp_array_get( $tree, array( 'color', 'duotone' ), array() ); - - foreach ( $presets_by_origin as $presets ) { - foreach ( $presets as $preset ) { - $filter_id = self::get_filter_id( _wp_to_kebab_case( $preset['slug'] ) ); - self::$global_styles_presets[ $filter_id ] = $preset; - } - } - } - - /** - * Scrape all block names from global styles and store in self::$global_styles_block_names - */ - public 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::wp_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:preset|duotone|blue-orange * 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. */ - private static function wp_get_slug_from_attr( $duotone_attr ) { + private static function get_slug_from_attribute( $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 ); @@ -524,7 +465,7 @@ private static function wp_get_slug_from_attr( $duotone_attr ) { * @return bool True if the duotone preset present and valid. */ private static function is_preset( $duotone_attr ) { - $slug = self::wp_get_slug_from_attr( $duotone_attr ); + $slug = self::get_slug_from_attribute( $duotone_attr ); $filter_id = self::get_filter_id( $slug ); return array_key_exists( $filter_id, self::$global_styles_presets ); @@ -537,7 +478,7 @@ private static function is_preset( $duotone_attr ) { * @return string The CSS variable name. */ private static function get_css_custom_property_name( $slug ) { - return self::CSS_VAR_PREFIX . $slug; + return "--wp--preset--duotone--$slug"; } /** @@ -547,7 +488,18 @@ private static function get_css_custom_property_name( $slug ) { * @return string The ID of the duotone filter. */ private static function get_filter_id( $slug ) { - return self::FILTER_ID_PREFIX . $slug; + return "wp-duotone-$slug"; + } + + /** + * Get the CSS variable for a duotone preset. + * + * @param string $slug The slug of the duotone preset. + * @return string The CSS variable. + */ + private static function get_css_var( $slug ) { + $name = self::get_css_custom_property_name( $slug ); + return "var($name)"; } /** @@ -557,7 +509,7 @@ private static function get_filter_id( $slug ) { * @return string The URL for the duotone filter. */ private static function get_filter_url( $filter_id ) { - return 'url(#' . $filter_id . ')'; + return "url(#$filter_id)"; } /** @@ -634,66 +586,6 @@ private static function get_filter_svg( $filter_id, $colors ) { return $svg; } - /** - * Get the CSS variable for a duotone preset. - * - * @param string $slug The slug of the duotone preset. - * @return string The CSS variable. - */ - private static function get_css_var( $slug ) { - return 'var(' . self::get_css_custom_property_name( $slug ) . ')'; - } - - /** - * Outputs all necessary SVG for duotone filters, CSS for classic themes. - */ - public static function output_footer_assets() { - if ( ! empty( self::$used_svg_filter_data ) ) { - echo self::get_svg_definitions( self::$used_svg_filter_data ); - } - - // This is for classic themes - in block themes, the CSS is added in the head via wp_add_inline_style in the wp_enqueue_scripts action. - if ( ! wp_is_block_theme() && ! empty( self::$used_global_styles_presets ) ) { - wp_add_inline_style( 'core-block-supports', self::get_global_styles_presets( self::$used_global_styles_presets ) ); - } - } - - /** - * Adds the duotone SVGs and CSS custom properties to the editor settings so - * they can be pulled in by the EditorStyles component in JS and rendered in - * the post editor. - * - * @param array $settings The block editor settings from the `block_editor_settings_all` filter. - * @return array The editor settings with duotone SVGs and CSS custom properties. - */ - public static function add_editor_settings( $settings ) { - if ( ! empty( self::$global_styles_presets ) ) { - if ( ! isset( $settings['styles'] ) ) { - $settings['styles'] = array(); - } - - $settings['styles'][] = array( - // For the editor we can add all of the presets by default. - 'assets' => self::get_svg_definitions( self::$global_styles_presets ), - // The 'svgs' type is new in 6.3 and requires the corresponding JS changes in the EditorStyles component to work. - '__unstableType' => 'svgs', - // These styles not generated by global styles, so this must be false or they will be stripped out in wp_get_block_editor_settings. - 'isGlobalStyles' => false, - ); - - $settings['styles'][] = array( - // For the editor we can add all of the presets by default. - 'css' => self::get_global_styles_presets( self::$global_styles_presets ), - // This must be set and must be something other than 'theme' or they will be stripped out in the post editor component. - '__unstableType' => 'presets', - // These styles are no longer generated by global styles, so this must be false or they will be stripped out in wp_get_block_editor_settings. - 'isGlobalStyles' => false, - ); - } - - return $settings; - } - /** * Returns the prefixed id for the duotone filter for use as a CSS id. * @@ -733,30 +625,6 @@ public static function get_filter_svg_from_preset( $preset ) { return self::get_filter_svg( $filter_id, $preset['colors'] ); } - /** - * Appends the used global style duotone filter CSS Vars to the inline global styles CSS - */ - public static function output_global_styles() { - - if ( ! empty( self::$used_global_styles_presets ) ) { - wp_add_inline_style( 'global-styles', self::get_global_styles_presets( self::$used_global_styles_presets ) ); - } - } - - /** - * Appends the used block duotone filter declarations to the inline block supports CSS. - */ - public static function output_block_styles() { - if ( ! empty( self::$block_css_declarations ) ) { - wp_style_engine_get_stylesheet_from_css_rules( - self::$block_css_declarations, - array( - 'context' => 'block-supports', - ) - ); - } - } - /** * Get the SVGs for the duotone filters. * @@ -791,7 +659,7 @@ private static function get_global_styles_presets( $sources ) { $colors = $filter_data['colors']; $css_property_name = self::get_css_custom_property_name( $slug ); $declaration_value = is_string( $colors ) ? $colors : self::get_filter_url( $filter_id ); - $css .= $css_property_name . ':' . $declaration_value . ';'; + $css .= "$css_property_name:$declaration_value;"; } $css .= '}'; return $css; @@ -854,6 +722,8 @@ private static function enqueue_global_styles_preset( $filter_id, $duotone_selec /** * Registers the style and colors block attributes for block types that support it. * + * @since 6.3.0 + * * @param WP_Block_Type $block_type Block Type. */ public static function register_duotone_support( $block_type ) { @@ -913,8 +783,63 @@ private static function get_selector( $block_name ) { } } + /** + * 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. + * + * @since 6.3.0 + */ + public 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 ) { + $filter_id = self::get_filter_id( _wp_to_kebab_case( $preset['slug'] ) ); + + self::$global_styles_presets[ $filter_id ] = $preset; + } + } + } + + /** + * Scrape all block names from global styles and store in self::$global_styles_block_names + * + * @since 6.3.0 + */ + public static function set_global_style_block_names() { + // Get the per block settings from the theme.json. + $tree = WP_Theme_JSON_Resolver_Gutenberg::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|blue-orange'. + $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::get_slug_from_attribute( $duotone_attr ); + + if ( $slug && $slug !== $duotone_attr ) { + self::$global_styles_block_names[ $block_node['name'] ] = $slug; + } + } + } + /** * Render out the duotone CSS styles and SVG. + * + * @since 6.3.0 * * @param string $block_content Rendered block content. * @param array $block Block object. @@ -940,7 +865,7 @@ public static function render_duotone_support( $block_content, $block ) { // 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)'' + // 2. Variable for an existing Duotone preset - e.g. 'var:preset|duotone|blue-orange' or 'var(--wp--preset--duotone--blue-orange)'' // 3. A CSS string - e.g. 'unset' to remove globally applied duotone. $duotone_attr = $block['attrs']['style']['color']['duotone']; @@ -950,9 +875,9 @@ public static function render_duotone_support( $block_content, $block ) { if ( $is_preset ) { - $slug = self::wp_get_slug_from_attr( $duotone_attr ); // e.g. 'green-blue'. - $filter_id = self::get_filter_id( $slug ); // e.g. 'wp-duotone-filter-green-blue'. - $filter_value = self::get_css_var( $slug ); // e.g. 'var(--wp--preset--duotone--green-blue)'. + $slug = self::get_slug_from_attribute( $duotone_attr ); // e.g. 'blue-orange'. + $filter_id = self::get_filter_id( $slug ); // e.g. 'wp-duotone-filter-blue-orange'. + $filter_value = self::get_css_var( $slug ); // e.g. 'var(--wp--preset--duotone--blue-orange)'. // CSS custom property, SVG filter, and block CSS. self::enqueue_global_styles_preset( $filter_id, $duotone_selector, $filter_value ); @@ -977,9 +902,9 @@ public static function render_duotone_support( $block_content, $block ) { self::enqueue_custom_filter( $filter_id, $duotone_selector, $filter_value, $filter_data ); } } elseif ( $has_global_styles_duotone ) { - $slug = self::$global_styles_block_names[ $block['blockName'] ]; // e.g. 'green-blue'. - $filter_id = self::get_filter_id( $slug ); // e.g. 'wp-duotone-filter-green-blue'. - $filter_value = self::get_css_var( $slug ); // e.g. 'var(--wp--preset--duotone--green-blue)'. + $slug = self::$global_styles_block_names[ $block['blockName'] ]; // e.g. 'blue-orange'. + $filter_id = self::get_filter_id( $slug ); // e.g. 'wp-duotone-filter-blue-orange'. + $filter_value = self::get_css_var( $slug ); // e.g. 'var(--wp--preset--duotone--blue-orange)'. // CSS custom property, SVG filter, and block CSS. self::enqueue_global_styles_preset( $filter_id, $duotone_selector, $filter_value ); @@ -993,9 +918,93 @@ public static function render_duotone_support( $block_content, $block ) { return $tags->get_updated_html(); } + /** + * Appends the used block duotone filter declarations to the inline block supports CSS. + * + * @since 6.3.0 + */ + public static function output_block_styles() { + if ( ! empty( self::$block_css_declarations ) ) { + gutenberg_style_engine_get_stylesheet_from_css_rules( + self::$block_css_declarations, + array( + 'context' => 'block-supports', + ) + ); + } + } + + /** + * Appends the used global style duotone filter presets (CSS custom + * properties) to the inline global styles CSS. + * + * @since 6.3.0 + */ + public static function output_global_styles() { + if ( ! empty( self::$used_global_styles_presets ) ) { + wp_add_inline_style( 'global-styles', self::get_global_styles_presets( self::$used_global_styles_presets ) ); + } + } + + /** + * Outputs all necessary SVG for duotone filters, CSS for classic themes. + * + * @since 6.3.0 + */ + public static function output_footer_assets() { + if ( ! empty( self::$used_svg_filter_data ) ) { + echo self::get_svg_definitions( self::$used_svg_filter_data ); + } + + // This is for classic themes - in block themes, the CSS is added in the head via wp_add_inline_style in the wp_enqueue_scripts action. + if ( ! wp_is_block_theme() && ! empty( self::$used_global_styles_presets ) ) { + wp_add_inline_style( 'core-block-supports', self::get_global_styles_presets( self::$used_global_styles_presets ) ); + } + } + + /** + * Adds the duotone SVGs and CSS custom properties to the editor settings so + * they can be pulled in by the EditorStyles component in JS and rendered in + * the post editor. + * + * @since 6.3.0 + * + * @param array $settings The block editor settings from the `block_editor_settings_all` filter. + * @return array The editor settings with duotone SVGs and CSS custom properties. + */ + public static function add_editor_settings( $settings ) { + if ( ! empty( self::$global_styles_presets ) ) { + if ( ! isset( $settings['styles'] ) ) { + $settings['styles'] = array(); + } + + $settings['styles'][] = array( + // For the editor we can add all of the presets by default. + 'assets' => self::get_svg_definitions( self::$global_styles_presets ), + // The 'svgs' type is new in 6.3 and requires the corresponding JS changes in the EditorStyles component to work. + '__unstableType' => 'svgs', + // These styles not generated by global styles, so this must be false or they will be stripped out in gutenberg_get_block_editor_settings. + 'isGlobalStyles' => false, + ); + + $settings['styles'][] = array( + // For the editor we can add all of the presets by default. + 'css' => self::get_global_styles_presets( self::$global_styles_presets ), + // This must be set and must be something other than 'theme' or they will be stripped out in the post editor component. + '__unstableType' => 'presets', + // These styles are no longer generated by global styles, so this must be false or they will be stripped out in gutenberg_get_block_editor_settings. + 'isGlobalStyles' => false, + ); + } + + return $settings; + } + /** * Migrate the old experimental duotone support flag to its stabilized location * under `supports.filter.duotone` and sets. + * + * @since 6.3.0 * * @param array $settings Current block type settings. * @param array $metadata Block metadata as read in via block.json. diff --git a/tests/phpunit/tests/block-supports/duotone.php b/tests/phpunit/tests/block-supports/duotone.php index 5ce1788c20fc4..b7f61493ec182 100644 --- a/tests/phpunit/tests/block-supports/duotone.php +++ b/tests/phpunit/tests/block-supports/duotone.php @@ -45,7 +45,7 @@ public function test_render_duotone_support_custom() { $this->assertMatchesRegularExpression( $expected, WP_Duotone::render_duotone_support( $block_content, $block ) ); } - public function data_get_slug_from_attr() { + public function data_get_slug_from_attribute() { return array( 'pipe-slug' => array( 'var:preset|duotone|blue-orange', 'blue-orange' ), 'css-var' => array( 'var(--wp--preset--duotone--blue-orange)', 'blue-orange' ), @@ -60,11 +60,11 @@ public function data_get_slug_from_attr() { } /** - * @dataProvider data_get_slug_from_attr + * @dataProvider data_get_slug_from_attribute */ - public function test_get_slug_from_attr( $data_attr, $expected ) { + public function test_get_slug_from_attribute( $data_attr, $expected ) { - $reflection = new ReflectionMethod( 'WP_Duotone', 'get_slug_from_attr' ); + $reflection = new ReflectionMethod( 'WP_Duotone', 'get_slug_from_attribute' ); $reflection->setAccessible( true ); $this->assertSame( $expected, $reflection->invoke( null, $data_attr ) ); From e82e5da5a0a65f15166bb7ab17305ae997a81a68 Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Thu, 15 Jun 2023 17:29:53 +0200 Subject: [PATCH 12/47] BP: Better error message when theme.json styles use a duotone preset not in settings #50714 --- src/wp-includes/class-wp-duotone.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index a8a2895e07653..6857b720a5527 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -715,6 +715,15 @@ private static function enqueue_custom_filter( $filter_id, $duotone_selector, $f * @param string $filter_value The filter CSS value. e.g. 'url(#wp-duotone-blue-orange)' or 'unset'. */ private static function enqueue_global_styles_preset( $filter_id, $duotone_selector, $filter_value ) { + if ( ! array_key_exists( $filter_id, self::$global_styles_presets ) ) { + $error_message = sprintf( + /* translators: %s: duotone filter ID */ + __( 'The duotone id "%s" is not registered in theme.json settings', 'gutenberg' ), + $filter_id + ); + _doing_it_wrong( __METHOD__, $error_message, '6.3.0' ); + return; + } self::$used_global_styles_presets[ $filter_id ] = self::$global_styles_presets[ $filter_id ]; self::enqueue_custom_filter( $filter_id, $duotone_selector, $filter_value, self::$global_styles_presets[ $filter_id ] ); } From 89d1c7ae5b1fb0ad2ba348edec0eeb9b06178d91 Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Thu, 15 Jun 2023 17:31:24 +0200 Subject: [PATCH 13/47] BP: Clarify error message if duotone color values is incorrect #51397 --- src/wp-includes/class-wp-duotone.php | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index 6857b720a5527..e798ec50c6cfd 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -530,10 +530,19 @@ private static function get_filter_svg( $filter_id, $colors ) { foreach ( $colors as $color_str ) { $color = self::colord_parse( $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']; + if ( null === $color ) { + $error_message = sprintf( + /* translators: %s: duotone colors */ + __( '"%s" in theme.json settings.color.duotone is not a hex or rgb string.', 'gutenberg' ), + $color_str + ); + _doing_it_wrong( __METHOD__, $error_message, '6.3.0' ); + } else { + $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(); From 8efbc43e5cf81e612cd4c39e9e216fe4678fa022 Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Thu, 15 Jun 2023 17:49:15 +0200 Subject: [PATCH 14/47] run linter --- src/wp-includes/block-supports/duotone.php | 15 ++++++++------- src/wp-includes/class-wp-duotone.php | 12 ++++++------ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/wp-includes/block-supports/duotone.php b/src/wp-includes/block-supports/duotone.php index e49e60211a645..5eabe8d0d2df9 100644 --- a/src/wp-includes/block-supports/duotone.php +++ b/src/wp-includes/block-supports/duotone.php @@ -116,7 +116,7 @@ function _wp_tinycolor_bound_alpha( $n ) { * consistency with TinyColor. * * @see https://github.com/bgrins/TinyColor - * + * * @deprecated 6.3.0 * * @since 5.8.0 @@ -142,7 +142,7 @@ function wp_tinycolor_rgb_to_rgb( $rgb_color ) { * consistency with TinyColor. * * @see https://github.com/bgrins/TinyColor - * + * * @deprecated 6.3.0 * * @since 5.8.0 @@ -392,7 +392,7 @@ function wp_tinycolor_string_to_rgb( $color_str ) { * * @since 5.9.1 * @access private - * + * * @deprecated 6.3.0 * * @param array $preset Duotone preset value as seen in theme.json. @@ -409,7 +409,7 @@ function wp_get_duotone_filter_id( $preset ) { * @since 5.9.0 * @since 6.1.0 Allow unset for preset colors. * @access private - * + * * @deprecated 6.3.0 * * @param array $preset Duotone preset value as seen in theme.json. @@ -431,7 +431,8 @@ function wp_get_duotone_filter_property( $preset ) { * @param array $preset Duotone preset value as seen in theme.json. * @return string Duotone SVG filter. */ -function wp_get_duotone_filter_svg( $preset ) {_deprecated_function( __FUNCTION__, '6.3.0' ); +function wp_get_duotone_filter_svg( $preset ) { + _deprecated_function( __FUNCTION__, '6.3.0' ); return WP_Duotone::get_filter_svg_from_preset( $preset ); } @@ -440,7 +441,7 @@ function wp_get_duotone_filter_svg( $preset ) {_deprecated_function( __FUNCTION_ * * @since 5.8.0 * @access private - * + * * @deprecated 6.3.0 Use WP_Duotone::register_duotone_support() instead. * * @param WP_Block_Type $block_type Block Type. @@ -456,7 +457,7 @@ function wp_register_duotone_support( $block_type ) { * @since 5.8.0 * @since 6.1.0 Allow unset for preset colors. * @access private - * + * * @deprecated 6.3.0 Use WP_Duotone::render_duotone_support() instead. * * @param string $block_content Rendered block content. diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index e798ec50c6cfd..0b3af7aa0d70b 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -478,7 +478,7 @@ private static function is_preset( $duotone_attr ) { * @return string The CSS variable name. */ private static function get_css_custom_property_name( $slug ) { - return "--wp--preset--duotone--$slug"; + return "--wp--preset--duotone--$slug"; } /** @@ -488,7 +488,7 @@ private static function get_css_custom_property_name( $slug ) { * @return string The ID of the duotone filter. */ private static function get_filter_id( $slug ) { - return "wp-duotone-$slug"; + return "wp-duotone-$slug"; } /** @@ -668,7 +668,7 @@ private static function get_global_styles_presets( $sources ) { $colors = $filter_data['colors']; $css_property_name = self::get_css_custom_property_name( $slug ); $declaration_value = is_string( $colors ) ? $colors : self::get_filter_url( $filter_id ); - $css .= "$css_property_name:$declaration_value;"; + $css .= "$css_property_name:$declaration_value;"; } $css .= '}'; return $css; @@ -856,7 +856,7 @@ public static function set_global_style_block_names() { /** * Render out the duotone CSS styles and SVG. - * + * * @since 6.3.0 * * @param string $block_content Rendered block content. @@ -1021,7 +1021,7 @@ public static function add_editor_settings( $settings ) { /** * Migrate the old experimental duotone support flag to its stabilized location * under `supports.filter.duotone` and sets. - * + * * @since 6.3.0 * * @param array $settings Current block type settings. @@ -1038,7 +1038,7 @@ public static function migrate_experimental_duotone_support_flag( $settings, $me return $settings; } - + /** * Gets the CSS filter property value from a preset. * From 8dc7158147762ca375d77e0d9681b2553eeddd8f Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Thu, 15 Jun 2023 14:09:20 -0500 Subject: [PATCH 15/47] Add duotone hooks --- src/wp-includes/block-supports/duotone.php | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/wp-includes/block-supports/duotone.php b/src/wp-includes/block-supports/duotone.php index 5eabe8d0d2df9..bbb32dcba83ee 100644 --- a/src/wp-includes/block-supports/duotone.php +++ b/src/wp-includes/block-supports/duotone.php @@ -40,6 +40,28 @@ ) ); +// Set up metadata prior to rendering any blocks. +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 ); + +// Add classnames to blocks using duotone support. +add_filter( 'render_block', array( 'WP_Duotone', 'render_duotone_support' ), 10, 2 ); + +// Enqueue styles. +// Block styles (core-block-supports-inline-css) before the style engine (gutenberg_enqueue_stored_styles). +// Global styles (global-styles-inline-css) after the other global styles (gutenberg_enqueue_global_styles). +add_action( 'wp_enqueue_scripts', array( 'WP_Duotone', 'output_block_styles' ), 9 ); +add_action( 'wp_enqueue_scripts', array( 'WP_Duotone', 'output_global_styles' ), 11 ); + +// Add SVG filters to the footer. Also, for classic themes, output block styles (core-block-supports-inline-css). +add_action( 'wp_footer', array( 'WP_Duotone', 'output_footer_assets' ), 10 ); + +// Add styles and SVGs for use in the editor via the EditorStyles component. +add_filter( 'block_editor_settings_all', array( 'WP_Duotone', 'add_editor_settings' ), 10 ); + +// Migrate the old experimental duotone support flag. +add_filter( 'block_type_metadata_settings', array( 'WP_Duotone', 'migrate_experimental_duotone_support_flag' ), 10, 2 ); + /* * Deprecated functions below. All new functions should be added in class-wp-duotone.php. */ From 9774f6cba2eae5102c4cf2b6625a08ea69723f70 Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Thu, 15 Jun 2023 14:33:53 -0500 Subject: [PATCH 16/47] Fix comments to reference core versions of functions --- 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 bbb32dcba83ee..71c7eddcfca43 100644 --- a/src/wp-includes/block-supports/duotone.php +++ b/src/wp-includes/block-supports/duotone.php @@ -48,8 +48,8 @@ add_filter( 'render_block', array( 'WP_Duotone', 'render_duotone_support' ), 10, 2 ); // Enqueue styles. -// Block styles (core-block-supports-inline-css) before the style engine (gutenberg_enqueue_stored_styles). -// Global styles (global-styles-inline-css) after the other global styles (gutenberg_enqueue_global_styles). +// Block styles (core-block-supports-inline-css) before the style engine (wp_enqueue_stored_styles). +// Global styles (global-styles-inline-css) after the other global styles (wp_enqueue_global_styles). add_action( 'wp_enqueue_scripts', array( 'WP_Duotone', 'output_block_styles' ), 9 ); add_action( 'wp_enqueue_scripts', array( 'WP_Duotone', 'output_global_styles' ), 11 ); From ee7741c82b1bb1b60776f46d61fe50e39d6dded0 Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Thu, 15 Jun 2023 14:37:32 -0500 Subject: [PATCH 17/47] Fix more comments to reference core versions of functions --- src/wp-includes/class-wp-duotone.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index 0b3af7aa0d70b..8679ec7d0d2e4 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -1001,7 +1001,7 @@ public static function add_editor_settings( $settings ) { 'assets' => self::get_svg_definitions( self::$global_styles_presets ), // The 'svgs' type is new in 6.3 and requires the corresponding JS changes in the EditorStyles component to work. '__unstableType' => 'svgs', - // These styles not generated by global styles, so this must be false or they will be stripped out in gutenberg_get_block_editor_settings. + // These styles not generated by global styles, so this must be false or they will be stripped out in wp_get_block_editor_settings. 'isGlobalStyles' => false, ); @@ -1010,7 +1010,7 @@ public static function add_editor_settings( $settings ) { 'css' => self::get_global_styles_presets( self::$global_styles_presets ), // This must be set and must be something other than 'theme' or they will be stripped out in the post editor component. '__unstableType' => 'presets', - // These styles are no longer generated by global styles, so this must be false or they will be stripped out in gutenberg_get_block_editor_settings. + // These styles are no longer generated by global styles, so this must be false or they will be stripped out in wp_get_block_editor_settings. 'isGlobalStyles' => false, ); } From 4d1d9aa0866b171fe8d9f45203658f323085821f Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Thu, 15 Jun 2023 14:40:24 -0500 Subject: [PATCH 18/47] Use core versions of classes/functions --- src/wp-includes/class-wp-duotone.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index 8679ec7d0d2e4..463023a38401b 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -809,7 +809,7 @@ private static function get_selector( $block_name ) { */ public static function set_global_styles_presets() { // Get the per block settings from the theme.json. - $tree = gutenberg_get_global_settings(); + $tree = wp_get_global_settings(); $presets_by_origin = _wp_array_get( $tree, array( 'color', 'duotone' ), array() ); foreach ( $presets_by_origin as $presets ) { @@ -828,7 +828,7 @@ public static function set_global_styles_presets() { */ public static function set_global_style_block_names() { // Get the per block settings from the theme.json. - $tree = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data(); + $tree = WP_Theme_JSON_Resolver::get_merged_data(); $block_nodes = $tree->get_styles_block_nodes(); $theme_json = $tree->get_raw_data(); @@ -943,7 +943,7 @@ public static function render_duotone_support( $block_content, $block ) { */ public static function output_block_styles() { if ( ! empty( self::$block_css_declarations ) ) { - gutenberg_style_engine_get_stylesheet_from_css_rules( + wp_style_engine_get_stylesheet_from_css_rules( self::$block_css_declarations, array( 'context' => 'block-supports', From 9ebb0d34f6f1181997a10dc866f8c69f01dc83c2 Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Thu, 15 Jun 2023 14:41:39 -0500 Subject: [PATCH 19/47] Remove gutenberg translation domains --- src/wp-includes/class-wp-duotone.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index 463023a38401b..031d299e9ac7a 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -533,7 +533,7 @@ private static function get_filter_svg( $filter_id, $colors ) { if ( null === $color ) { $error_message = sprintf( /* translators: %s: duotone colors */ - __( '"%s" in theme.json settings.color.duotone is not a hex or rgb string.', 'gutenberg' ), + __( '"%s" in theme.json settings.color.duotone is not a hex or rgb string.' ), $color_str ); _doing_it_wrong( __METHOD__, $error_message, '6.3.0' ); @@ -727,7 +727,7 @@ private static function enqueue_global_styles_preset( $filter_id, $duotone_selec if ( ! array_key_exists( $filter_id, self::$global_styles_presets ) ) { $error_message = sprintf( /* translators: %s: duotone filter ID */ - __( 'The duotone id "%s" is not registered in theme.json settings', 'gutenberg' ), + __( 'The duotone id "%s" is not registered in theme.json settings' ), $filter_id ); _doing_it_wrong( __METHOD__, $error_message, '6.3.0' ); From 2a90a43bd6dfec3dafd8cb526d90d2525e562b9c Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Fri, 16 Jun 2023 11:21:05 +0200 Subject: [PATCH 20/47] added docs or fixed them --- src/wp-includes/block-supports/duotone.php | 2 -- src/wp-includes/class-wp-duotone.php | 4 ++-- tests/phpunit/tests/block-supports/duotone.php | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/wp-includes/block-supports/duotone.php b/src/wp-includes/block-supports/duotone.php index 71c7eddcfca43..52c4ac0374584 100644 --- a/src/wp-includes/block-supports/duotone.php +++ b/src/wp-includes/block-supports/duotone.php @@ -480,8 +480,6 @@ function wp_register_duotone_support( $block_type ) { * @since 6.1.0 Allow unset for preset colors. * @access private * - * @deprecated 6.3.0 Use WP_Duotone::render_duotone_support() instead. - * * @param string $block_content Rendered block content. * @param array $block Block object. * @deprecated 6.3.0 Use WP_Duotone::render_duotone_support() instead. diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index 031d299e9ac7a..7a4da5a137a93 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -444,7 +444,7 @@ private static function colord_parse( $input ) { } /** - * Take the inline CSS duotone variable from a block and return the slug. Handles styles slugs like: + * Takes the inline CSS duotone variable from a block and return the slug. Handles styles slugs like: * var:preset|duotone|blue-orange * var(--wp--preset--duotone--blue-orange) * @@ -459,7 +459,7 @@ private static function get_slug_from_attribute( $duotone_attr ) { } /** - * Check if we have a valid duotone preset. + * Checks 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. diff --git a/tests/phpunit/tests/block-supports/duotone.php b/tests/phpunit/tests/block-supports/duotone.php index b7f61493ec182..7059693986dfa 100644 --- a/tests/phpunit/tests/block-supports/duotone.php +++ b/tests/phpunit/tests/block-supports/duotone.php @@ -15,6 +15,11 @@ public static function wpTearDownAfterClass() { WP_Style_Engine_CSS_Rules_Store::remove_all_stores(); } + /** + * Tests whether the duotone preset class is added to the block. + * + * @covers ::render_duotone_support + */ public function test_render_duotone_support_preset() { $block = array( 'blockName' => 'core/image', @@ -25,6 +30,11 @@ public function test_render_duotone_support_preset() { $this->assertSame( $expected, WP_Duotone::render_duotone_support( $block_content, $block ) ); } + /** + * Tests whether the duotone unset class is added to the block. + * + * @covers ::render_duotone_support + */ public function test_render_duotone_support_css() { $block = array( 'blockName' => 'core/image', @@ -35,6 +45,11 @@ public function test_render_duotone_support_css() { $this->assertMatchesRegularExpression( $expected, WP_Duotone::render_duotone_support( $block_content, $block ) ); } + /** + * Tests whether the duotone custom class is added to the block. + * + * @covers ::render_duotone_support + */ public function test_render_duotone_support_custom() { $block = array( 'blockName' => 'core/image', @@ -60,7 +75,10 @@ public function data_get_slug_from_attribute() { } /** + * Tests whether the slug is extracted from the attribute. + * * @dataProvider data_get_slug_from_attribute + * @covers ::get_slug_from_attribute */ public function test_get_slug_from_attribute( $data_attr, $expected ) { From 2fd1bf9766c598b8c7002d699d4ed590c48ff38c Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Wed, 21 Jun 2023 09:55:09 +0200 Subject: [PATCH 21/47] Fixed more docblocks --- src/wp-includes/class-wp-duotone.php | 2 +- tests/phpunit/tests/block-supports/duotone.php | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index 7a4da5a137a93..debb1869bfcc6 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -472,7 +472,7 @@ private static function is_preset( $duotone_attr ) { } /** - * Get the CSS variable name for a duotone preset. + * Gets the CSS variable name for a duotone preset. * * @param string $slug The slug of the duotone preset. * @return string The CSS variable name. diff --git a/tests/phpunit/tests/block-supports/duotone.php b/tests/phpunit/tests/block-supports/duotone.php index 7059693986dfa..8706af5af87bc 100644 --- a/tests/phpunit/tests/block-supports/duotone.php +++ b/tests/phpunit/tests/block-supports/duotone.php @@ -18,6 +18,8 @@ public static function wpTearDownAfterClass() { /** * Tests whether the duotone preset class is added to the block. * + * @ticket 58555 + * * @covers ::render_duotone_support */ public function test_render_duotone_support_preset() { @@ -33,6 +35,8 @@ public function test_render_duotone_support_preset() { /** * Tests whether the duotone unset class is added to the block. * + * @ticket 58555 + * * @covers ::render_duotone_support */ public function test_render_duotone_support_css() { @@ -76,7 +80,7 @@ public function data_get_slug_from_attribute() { /** * Tests whether the slug is extracted from the attribute. - * + * * @dataProvider data_get_slug_from_attribute * @covers ::get_slug_from_attribute */ From d2306db4912469a0c898f4d181b5aacc42eb606a Mon Sep 17 00:00:00 2001 From: Maggie Date: Mon, 26 Jun 2023 16:28:02 +0200 Subject: [PATCH 22/47] Update src/wp-includes/class-wp-duotone.php Co-authored-by: Peter Wilson <519727+peterwilsoncc@users.noreply.github.com> --- src/wp-includes/class-wp-duotone.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index debb1869bfcc6..bce5456a1e7f9 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -981,8 +981,10 @@ public static function output_footer_assets() { } /** - * Adds the duotone SVGs and CSS custom properties to the editor settings so - * they can be pulled in by the EditorStyles component in JS and rendered in + * Adds the duotone SVGs and CSS custom properties to the editor settings. + * + * This allows the properties to be + * pulled in by the EditorStyles component in JS and rendered in * the post editor. * * @since 6.3.0 From fb7534433461440ba3f2a4c385b2472611c69643 Mon Sep 17 00:00:00 2001 From: Maggie Date: Mon, 26 Jun 2023 16:28:14 +0200 Subject: [PATCH 23/47] Update src/wp-includes/class-wp-duotone.php Co-authored-by: Peter Wilson <519727+peterwilsoncc@users.noreply.github.com> --- src/wp-includes/class-wp-duotone.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index bce5456a1e7f9..fb60e545dc5c6 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -802,7 +802,9 @@ private static function get_selector( $block_name ) { } /** - * Get all possible duotone presets from global and theme styles and store as slug => [ colors array ] + * Get all possible duotone presets from global and theme styles. + * + * Store each item 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. * * @since 6.3.0 From f78d01bc6321a8070a32e9dc9996a1d6e386e737 Mon Sep 17 00:00:00 2001 From: Maggie Date: Mon, 26 Jun 2023 16:28:23 +0200 Subject: [PATCH 24/47] Update tests/phpunit/tests/block-supports/duotone.php Co-authored-by: Peter Wilson <519727+peterwilsoncc@users.noreply.github.com> --- tests/phpunit/tests/block-supports/duotone.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/phpunit/tests/block-supports/duotone.php b/tests/phpunit/tests/block-supports/duotone.php index 8706af5af87bc..2271c7e6831b0 100644 --- a/tests/phpunit/tests/block-supports/duotone.php +++ b/tests/phpunit/tests/block-supports/duotone.php @@ -6,7 +6,7 @@ * @package WordPress */ -class WP_Duotone_Test extends WP_UnitTestCase { +class Tests_Block_Supports_DuoTones extends WP_UnitTestCase { /** * Cleans up CSS added to block-supports from duotone styles. We neeed to do this * in order to avoid impacting other tests. From 7106f33de4e409ad1f385985525fbc1b61b3759b Mon Sep 17 00:00:00 2001 From: Maggie Date: Mon, 26 Jun 2023 16:28:39 +0200 Subject: [PATCH 25/47] Update src/wp-includes/class-wp-duotone.php Co-authored-by: Peter Wilson <519727+peterwilsoncc@users.noreply.github.com> --- src/wp-includes/class-wp-duotone.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index fb60e545dc5c6..337c2bb982909 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -129,8 +129,7 @@ class WP_Duotone { private static $block_css_declarations = array(); /** - * Direct port of colord's clamp function. Using min/max instead of - * nested ternaries. + * Clamps a value between an upper and lower bound. * * @see https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/helpers.ts#L23 * From 4530c53cd796b184e728f666e2c972f28e6bb073 Mon Sep 17 00:00:00 2001 From: Maggie Date: Mon, 26 Jun 2023 16:28:54 +0200 Subject: [PATCH 26/47] Update src/wp-includes/class-wp-duotone.php Co-authored-by: Peter Wilson <519727+peterwilsoncc@users.noreply.github.com> --- src/wp-includes/class-wp-duotone.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index 337c2bb982909..32354c3f3b56a 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -131,7 +131,7 @@ class WP_Duotone { /** * Clamps a value between an upper and lower bound. * - * @see https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/helpers.ts#L23 + * @link https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/helpers.ts#L23 Sourced from colord. * * @param float $number The number to clamp. * @param float $min The minimum value. From 071e09333edfdfb011a21a2015dfaa80730c2630 Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Mon, 26 Jun 2023 16:34:24 +0200 Subject: [PATCH 27/47] fix docblocks for tests --- .../phpunit/tests/block-supports/duotone.php | 44 ++++++++++++------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/tests/phpunit/tests/block-supports/duotone.php b/tests/phpunit/tests/block-supports/duotone.php index 2271c7e6831b0..672e91c00bc6a 100644 --- a/tests/phpunit/tests/block-supports/duotone.php +++ b/tests/phpunit/tests/block-supports/duotone.php @@ -64,6 +64,25 @@ public function test_render_duotone_support_custom() { $this->assertMatchesRegularExpression( $expected, WP_Duotone::render_duotone_support( $block_content, $block ) ); } + /** + * Tests whether the slug is extracted from the attribute. + * + * @dataProvider data_get_slug_from_attribute + * @covers ::get_slug_from_attribute + */ + public function test_get_slug_from_attribute( $data_attr, $expected ) { + + $reflection = new ReflectionMethod( 'WP_Duotone', 'get_slug_from_attribute' ); + $reflection->setAccessible( true ); + + $this->assertSame( $expected, $reflection->invoke( null, $data_attr ) ); + } + + /** + * Data provider. + * + * @return array[]. + */ public function data_get_slug_from_attribute() { return array( 'pipe-slug' => array( 'var:preset|duotone|blue-orange', 'blue-orange' ), @@ -79,19 +98,20 @@ public function data_get_slug_from_attribute() { } /** - * Tests whether the slug is extracted from the attribute. - * - * @dataProvider data_get_slug_from_attribute - * @covers ::get_slug_from_attribute + * @dataProvider data_is_preset */ - public function test_get_slug_from_attribute( $data_attr, $expected ) { - - $reflection = new ReflectionMethod( 'WP_Duotone', 'get_slug_from_attribute' ); + public function test_is_preset( $data_attr, $expected ) { + $reflection = new ReflectionMethod( 'WP_Duotone', 'is_preset' ); $reflection->setAccessible( true ); $this->assertSame( $expected, $reflection->invoke( null, $data_attr ) ); } + /** + * Data provider. + * + * @return array[]. + */ public function data_is_preset() { return array( 'pipe-slug' => array( 'var:preset|duotone|blue-orange', true ), @@ -101,14 +121,4 @@ public function data_is_preset() { 'invalid' => array( 'not a valid attribute', false ), ); } - - /** - * @dataProvider data_is_preset - */ - public function test_is_preset( $data_attr, $expected ) { - $reflection = new ReflectionMethod( 'WP_Duotone', 'is_preset' ); - $reflection->setAccessible( true ); - - $this->assertSame( $expected, $reflection->invoke( null, $data_attr ) ); - } } From eb1c12e900e1a91ab84133c6f32b5293bd160a8a Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Mon, 26 Jun 2023 16:41:08 +0200 Subject: [PATCH 28/47] fix multiline comments --- src/wp-includes/class-wp-duotone.php | 54 +++++++++++++++++----------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index 32354c3f3b56a..37e77d42cce01 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -267,8 +267,10 @@ private static function colord_parse_rgba_string( $input ) { return null; } - // For some reason, preg_match doesn't include empty matches at the end - // of the array, so we add them manually to make things easier later. + /* + * For some reason, preg_match doesn't include empty matches at the end + * of the array, so we add them manually to make things easier later. + */ for ( $i = 1; $i <= 8; $i++ ) { if ( ! isset( $match[ $i ] ) ) { $match[ $i ] = ''; @@ -399,8 +401,10 @@ private static function colord_parse_hsla_string( $input ) { return null; } - // For some reason, preg_match doesn't include empty matches at the end - // of the array, so we add them manually to make things easier later. + /* + * For some reason, preg_match doesn't include empty matches at the end + * of the array, so we add them manually to make things easier later. + */ for ( $i = 1; $i <= 6; $i++ ) { if ( ! isset( $match[ $i ] ) ) { $match[ $i ] = ''; @@ -686,9 +690,11 @@ private static function enqueue_block_css( $filter_id, $duotone_selector, $filte $selectors_scoped = array(); foreach ( $selectors as $selector_part ) { - // Assuming the selector part is a subclass selector (not a tag name) - // so we can prepend the filter id class. If we want to support elements - // such as `img` or namespaces, we'll need to add a case for that here. + /* + * Assuming the selector part is a subclass selector (not a tag name) + * so we can prepend the filter id class. If we want to support elements + * such as `img` or namespaces, we'll need to add a case for that here. + */ $selectors_scoped[] = '.' . $filter_id . trim( $selector_part ); } @@ -746,8 +752,10 @@ private static function enqueue_global_styles_preset( $filter_id, $duotone_selec public static function register_duotone_support( $block_type ) { $has_duotone_support = false; if ( property_exists( $block_type, 'supports' ) ) { - // Previous `color.__experimentalDuotone` support flag is migrated - // to `filter.duotone` via `block_type_metadata_settings` filter. + /* + * Previous `color.__experimentalDuotone` support flag is migrated + * to `filter.duotone` via `block_type_metadata_settings` filter. + */ $has_duotone_support = _wp_array_get( $block_type->supports, array( 'filter', 'duotone' ), null ); } @@ -775,18 +783,22 @@ private static function get_selector( $block_name ) { $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block_name ); if ( $block_type && property_exists( $block_type, 'supports' ) ) { - // Backwards compatibility with `supports.color.__experimentalDuotone` - // is provided via the `block_type_metadata_settings` filter. If - // `supports.filter.duotone` has not been set and the experimental - // property has been, the experimental property value is copied into - // `supports.filter.duotone`. + /* + * Backwards compatibility with `supports.color.__experimentalDuotone` + * is provided via the `block_type_metadata_settings` filter. If + * `supports.filter.duotone` has not been set and the experimental + * property has been, the experimental property value is copied into + * `supports.filter.duotone`. + */ $duotone_support = _wp_array_get( $block_type->supports, array( 'filter', 'duotone' ), false ); if ( ! $duotone_support ) { return null; } - // If the experimental duotone support was set, that value is to be - // treated as a selector and requires scoping. + /* + * If the experimental duotone support was set, that value is to be + * treated as a selector and requires scoping. + */ $experimental_duotone = _wp_array_get( $block_type->supports, array( 'color', '__experimentalDuotone' ), false ); if ( $experimental_duotone ) { $root_selector = wp_get_block_css_selector( $block_type ); @@ -882,10 +894,12 @@ public static function render_duotone_support( $block_content, $block ) { // 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|blue-orange' or 'var(--wp--preset--duotone--blue-orange)'' - // 3. A CSS string - e.g. 'unset' to remove globally applied duotone. + /* + * 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|blue-orange' or 'var(--wp--preset--duotone--blue-orange)'' + * 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 ) && self::is_preset( $duotone_attr ); From 956e65c67550e4469448888d0a73c09448f18932 Mon Sep 17 00:00:00 2001 From: Maggie Date: Mon, 26 Jun 2023 16:42:05 +0200 Subject: [PATCH 29/47] Update src/wp-includes/class-wp-duotone.php Co-authored-by: Peter Wilson <519727+peterwilsoncc@users.noreply.github.com> --- src/wp-includes/class-wp-duotone.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index 37e77d42cce01..2313e924cce31 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -134,8 +134,8 @@ class WP_Duotone { * @link https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/helpers.ts#L23 Sourced from colord. * * @param float $number The number to clamp. - * @param float $min The minimum value. - * @param float $max The maximum value. + * @param float $min The minimum value. + * @param float $max The maximum value. * @return float The clamped value. */ private static function colord_clamp( $number, $min = 0, $max = 1 ) { From 6dad8db896f332ef680594b184c9fb894fc04837 Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Mon, 26 Jun 2023 16:52:49 +0200 Subject: [PATCH 30/47] fix colord functions docblocks --- src/wp-includes/class-wp-duotone.php | 51 ++++++++++++++-------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index 2313e924cce31..6500efb2c27e2 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -143,9 +143,9 @@ private static function colord_clamp( $number, $min = 0, $max = 1 ) { } /** - * Direct port of colord's clampHue function. + * Processes and clamps a degree (angle) value properly. * - * @see https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/helpers.ts#L32 + * @link https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/helpers.ts#L32 Sourced from colord. * * @param float $degrees The hue to clamp. * @return float The clamped hue. @@ -156,9 +156,9 @@ private static function colord_clamp_hue( $degrees ) { } /** - * Direct port of colord's parseHue function. + * Converts a hue value to degrees from 0 to 360 inclusive. * - * @see https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/helpers.ts#L40 + * @link https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/helpers.ts#L40 Sourced from colord. * * @param float $value The hue value to parse. * @param string $unit The unit of the hue value. @@ -180,9 +180,9 @@ private static function colord_parse_hue( $value, $unit = 'deg' ) { } /** - * Direct port of colord's parseHex function. + * Parses any valid Hex3, Hex4, Hex6 or Hex8 string and converts it to an RGBA object * - * @see https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colorModels/hex.ts#L8 + * @link https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colorModels/hex.ts#L8 Sourced from colord. * * @param string $hex The hex string to parse. * @return array|null An array of RGBA values or null if the hex string is invalid. @@ -222,9 +222,9 @@ private static function colord_parse_hex( $hex ) { } /** - * Direct port of colord's clampRgba function. + * Clamps an array of RGBA values. * - * @see https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colorModels/rgb.ts#L5 + * @link https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colorModels/rgb.ts#L5 Sourced from colord. * * @param array $rgba The RGBA array to clamp. * @return array The clamped RGBA array. @@ -239,9 +239,9 @@ private static function colord_clamp_rgba( $rgba ) { } /** - * Direct port of colord's parseRgbaString function. + * Parses a valid RGB[A] CSS color function/string * - * @see https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colorModels/rgbString.ts#L18 + * @link https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colorModels/rgbString.ts#L18 Sourced from colord. * * @param string $input The RGBA string to parse. * @return array|null An array of RGBA values or null if the RGB string is invalid. @@ -292,9 +292,9 @@ private static function colord_parse_rgba_string( $input ) { } /** - * Direct port of colord's clampHsla function. + * Clamps an array of HSLA values. * - * @see https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colorModels/hsl.ts#L6 + * @link https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colorModels/hsl.ts#L6 Sourced from colord. * * @param array $hsla The HSLA array to clamp. * @return array The clamped HSLA array. @@ -309,9 +309,9 @@ private static function colord_clamp_hsla( $hsla ) { } /** - * Direct port of colord's hsvaToRgba function. + * Converts an HSVA array to RGBA. * - * @see https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colorModels/hsv.ts#L52 + * @link https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colorModels/hsv.ts#L52 Sourced from colord. * * @param array $hsva The HSVA array to convert. * @return array The RGBA array. @@ -337,9 +337,9 @@ private static function colord_hsva_to_rgba( $hsva ) { } /** - * Direct port of colord's hslaToHsva function. + * Converts an HSLA array to HSVA. * - * @see https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colorModels/hsl.ts#L33 + * @link https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colorModels/hsl.ts#L33 Sourced from colord. * * @param array $hsla The HSLA array to convert. * @return array The HSVA array. @@ -361,9 +361,9 @@ private static function colord_hsla_to_hsva( $hsla ) { } /** - * Direct port of colord's hslaToRgba function. + * Converts an HSLA array to RGBA. * - * @see https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colorModels/hsl.ts#L55 + * @link https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colorModels/hsl.ts#L55 Sourced from colord. * * @param array $hsla The HSLA array to convert. * @return array The RGBA array. @@ -373,9 +373,9 @@ private static function colord_hsla_to_rgba( $hsla ) { } /** - * Direct port of colord's parseHslaString function. + * Parses a valid HSL[A] CSS color function/string. * - * @see https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colorModels/hslString.ts#L17 + * @link https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colorModels/hslString.ts#L17 Sourced from colord. * * @param string $input The HSLA string to parse. * @return array|null An array of RGBA values or null if the RGB string is invalid. @@ -401,7 +401,7 @@ private static function colord_parse_hsla_string( $input ) { return null; } - /* + /* * For some reason, preg_match doesn't include empty matches at the end * of the array, so we add them manually to make things easier later. */ @@ -424,10 +424,9 @@ private static function colord_parse_hsla_string( $input ) { } /** - * Direct port of colord's parse function simplified for our use case. This - * version only supports string parsing and only returns RGBA values. + * Tries to convert an incoming string into RGBA values. * - * @see https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/parse.ts#L37 + * @link https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/parse.ts#L37 Sourced from colord. * * @param string $input The string to parse. * @return array|null An array of RGBA values or null if the string is invalid. @@ -783,7 +782,7 @@ private static function get_selector( $block_name ) { $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block_name ); if ( $block_type && property_exists( $block_type, 'supports' ) ) { - /* + /* * Backwards compatibility with `supports.color.__experimentalDuotone` * is provided via the `block_type_metadata_settings` filter. If * `supports.filter.duotone` has not been set and the experimental @@ -795,7 +794,7 @@ private static function get_selector( $block_name ) { return null; } - /* + /* * If the experimental duotone support was set, that value is to be * treated as a selector and requires scoping. */ From f1c26eabc91dfa6b14f6ba6fe87152720257c885 Mon Sep 17 00:00:00 2001 From: Maggie Date: Mon, 26 Jun 2023 16:54:09 +0200 Subject: [PATCH 31/47] Update src/wp-includes/class-wp-duotone.php Co-authored-by: Peter Wilson <519727+peterwilsoncc@users.noreply.github.com> --- src/wp-includes/class-wp-duotone.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index 6500efb2c27e2..7b6d72602b27f 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -446,7 +446,9 @@ private static function colord_parse( $input ) { } /** - * Takes the inline CSS duotone variable from a block and return the slug. Handles styles slugs like: + * Takes the inline CSS duotone variable from a block and return the slug. + * + * Handles styles slugs like: * var:preset|duotone|blue-orange * var(--wp--preset--duotone--blue-orange) * From 49f0630d66b8c85527d4f23351418e4b3465cf6a Mon Sep 17 00:00:00 2001 From: Maggie Date: Mon, 26 Jun 2023 16:54:27 +0200 Subject: [PATCH 32/47] Update src/wp-includes/class-wp-duotone.php Co-authored-by: Peter Wilson <519727+peterwilsoncc@users.noreply.github.com> --- src/wp-includes/class-wp-duotone.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index 7b6d72602b27f..b5df3e0b1e804 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -710,7 +710,9 @@ private static function enqueue_block_css( $filter_id, $duotone_selector, $filte } /** - * Enqueue custom filter assets for the page. Includes an SVG filter and block CSS declaration. + * Enqueue custom filter assets for the page. + * + * Includes an SVG filter and block CSS declaration. * * @param string $filter_id The filter ID. e.g. 'wp-duotone-000000-ffffff-2'. * @param string $duotone_selector The block's duotone selector. e.g. '.wp-block-image img'. From 7d296b486e2620ddaca12c3eef6430cf95de4eb2 Mon Sep 17 00:00:00 2001 From: Maggie Date: Mon, 26 Jun 2023 16:54:47 +0200 Subject: [PATCH 33/47] Update src/wp-includes/class-wp-duotone.php Co-authored-by: Peter Wilson <519727+peterwilsoncc@users.noreply.github.com> --- src/wp-includes/class-wp-duotone.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index b5df3e0b1e804..c8a2348e3c8de 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -725,7 +725,9 @@ private static function enqueue_custom_filter( $filter_id, $duotone_selector, $f } /** - * Enqueue preset assets for the page. Includes a CSS custom property, SVG filter, and block CSS declaration. + * Enqueue preset assets for the page. + * + * Includes a CSS custom property, SVG filter, and block CSS declaration. * * @param string $filter_id The filter ID. e.g. 'wp-duotone-blue-orange'. * @param string $duotone_selector The block's duotone selector. e.g. '.wp-block-image img'. From e18f0ae13ce0ef9efc300e70001fc5285aaa61d7 Mon Sep 17 00:00:00 2001 From: MaggieCabrera Date: Mon, 26 Jun 2023 16:57:32 +0200 Subject: [PATCH 34/47] moved deprecated functions to the correct file --- src/wp-includes/block-supports/duotone.php | 428 --------------------- src/wp-includes/deprecated.php | 424 ++++++++++++++++++++ 2 files changed, 424 insertions(+), 428 deletions(-) diff --git a/src/wp-includes/block-supports/duotone.php b/src/wp-includes/block-supports/duotone.php index 52c4ac0374584..b7964aa47809b 100644 --- a/src/wp-includes/block-supports/duotone.php +++ b/src/wp-includes/block-supports/duotone.php @@ -61,431 +61,3 @@ // Migrate the old experimental duotone support flag. add_filter( 'block_type_metadata_settings', array( 'WP_Duotone', 'migrate_experimental_duotone_support_flag' ), 10, 2 ); - -/* - * Deprecated functions below. All new functions should be added in class-wp-duotone.php. - */ - -/** - * Takes input from [0, n] and returns it as [0, 1]. - * - * Direct port of TinyColor's function, lightly simplified to maintain - * consistency with TinyColor. - * - * @see https://github.com/bgrins/TinyColor - * - * @deprecated 6.3.0 - * - * @since 5.8.0 - * @access private - * - * @param mixed $n Number of unknown type. - * @param int $max Upper value of the range to bound to. - * @return float Value in the range [0, 1]. - */ -function wp_tinycolor_bound01( $n, $max ) { - _deprecated_function( __FUNCTION__, '6.3.0' ); - if ( 'string' === gettype( $n ) && str_contains( $n, '.' ) && 1 === (float) $n ) { - $n = '100%'; - } - - $n = min( $max, max( 0, (float) $n ) ); - - // Automatically convert percentage into number. - if ( 'string' === gettype( $n ) && str_contains( $n, '%' ) ) { - $n = (int) ( $n * $max ) / 100; - } - - // Handle floating point rounding errors. - if ( ( abs( $n - $max ) < 0.000001 ) ) { - return 1.0; - } - - // Convert into [0, 1] range if it isn't already. - return ( $n % $max ) / (float) $max; -} - -/** - * Direct port of tinycolor's boundAlpha function to maintain consistency with - * how tinycolor works. - * - * @see https://github.com/bgrins/TinyColor - * - * @deprecated 6.3.0 - * - * @since 5.9.0 - * @access private - * - * @param mixed $n Number of unknown type. - * @return float Value in the range [0,1]. - */ -function _wp_tinycolor_bound_alpha( $n ) { - _deprecated_function( __FUNCTION__, '6.3.0' ); - - if ( is_numeric( $n ) ) { - $n = (float) $n; - if ( $n >= 0 && $n <= 1 ) { - return $n; - } - } - return 1; -} - -/** - * Rounds and converts values of an RGB object. - * - * Direct port of TinyColor's function, lightly simplified to maintain - * consistency with TinyColor. - * - * @see https://github.com/bgrins/TinyColor - * - * @deprecated 6.3.0 - * - * @since 5.8.0 - * @access private - * - * @param array $rgb_color RGB object. - * @return array Rounded and converted RGB object. - */ -function wp_tinycolor_rgb_to_rgb( $rgb_color ) { - _deprecated_function( __FUNCTION__, '6.3.0' ); - - return array( - 'r' => wp_tinycolor_bound01( $rgb_color['r'], 255 ) * 255, - 'g' => wp_tinycolor_bound01( $rgb_color['g'], 255 ) * 255, - 'b' => wp_tinycolor_bound01( $rgb_color['b'], 255 ) * 255, - ); -} - -/** - * Helper function for hsl to rgb conversion. - * - * Direct port of TinyColor's function, lightly simplified to maintain - * consistency with TinyColor. - * - * @see https://github.com/bgrins/TinyColor - * - * @deprecated 6.3.0 - * - * @since 5.8.0 - * @access private - * - * @param float $p first component. - * @param float $q second component. - * @param float $t third component. - * @return float R, G, or B component. - */ -function wp_tinycolor_hue_to_rgb( $p, $q, $t ) { - _deprecated_function( __FUNCTION__, '6.3.0' ); - - if ( $t < 0 ) { - ++$t; - } - if ( $t > 1 ) { - --$t; - } - if ( $t < 1 / 6 ) { - return $p + ( $q - $p ) * 6 * $t; - } - if ( $t < 1 / 2 ) { - return $q; - } - if ( $t < 2 / 3 ) { - return $p + ( $q - $p ) * ( 2 / 3 - $t ) * 6; - } - return $p; -} - -/** - * Converts an HSL object to an RGB object with converted and rounded values. - * - * Direct port of TinyColor's function, lightly simplified to maintain - * consistency with TinyColor. - * - * @see https://github.com/bgrins/TinyColor - * - * @deprecated 6.3.0 - * - * @since 5.8.0 - * @access private - * - * @param array $hsl_color HSL object. - * @return array Rounded and converted RGB object. - */ -function wp_tinycolor_hsl_to_rgb( $hsl_color ) { - _deprecated_function( __FUNCTION__, '6.3.0' ); - - $h = wp_tinycolor_bound01( $hsl_color['h'], 360 ); - $s = wp_tinycolor_bound01( $hsl_color['s'], 100 ); - $l = wp_tinycolor_bound01( $hsl_color['l'], 100 ); - - if ( 0 === $s ) { - // Achromatic. - $r = $l; - $g = $l; - $b = $l; - } else { - $q = $l < 0.5 ? $l * ( 1 + $s ) : $l + $s - $l * $s; - $p = 2 * $l - $q; - $r = wp_tinycolor_hue_to_rgb( $p, $q, $h + 1 / 3 ); - $g = wp_tinycolor_hue_to_rgb( $p, $q, $h ); - $b = wp_tinycolor_hue_to_rgb( $p, $q, $h - 1 / 3 ); - } - - return array( - 'r' => $r * 255, - 'g' => $g * 255, - 'b' => $b * 255, - ); -} - -/** - * Parses hex, hsl, and rgb CSS strings using the same regex as TinyColor v1.4.2 - * used in the JavaScript. Only colors output from react-color are implemented. - * - * Direct port of TinyColor's function, lightly simplified to maintain - * consistency with TinyColor. - * - * @see https://github.com/bgrins/TinyColor - * @see https://github.com/casesandberg/react-color/ - * - * @deprecated 6.3.0 - * - * @since 5.8.0 - * @since 5.9.0 Added alpha processing. - * @access private - * - * @param string $color_str CSS color string. - * @return array RGB object. - */ -function wp_tinycolor_string_to_rgb( $color_str ) { - _deprecated_function( __FUNCTION__, '6.3.0' ); - - $color_str = strtolower( trim( $color_str ) ); - - $css_integer = '[-\\+]?\\d+%?'; - $css_number = '[-\\+]?\\d*\\.\\d+%?'; - - $css_unit = '(?:' . $css_number . ')|(?:' . $css_integer . ')'; - - $permissive_match3 = '[\\s|\\(]+(' . $css_unit . ')[,|\\s]+(' . $css_unit . ')[,|\\s]+(' . $css_unit . ')\\s*\\)?'; - $permissive_match4 = '[\\s|\\(]+(' . $css_unit . ')[,|\\s]+(' . $css_unit . ')[,|\\s]+(' . $css_unit . ')[,|\\s]+(' . $css_unit . ')\\s*\\)?'; - - $rgb_regexp = '/^rgb' . $permissive_match3 . '$/'; - if ( preg_match( $rgb_regexp, $color_str, $match ) ) { - $rgb = wp_tinycolor_rgb_to_rgb( - array( - 'r' => $match[1], - 'g' => $match[2], - 'b' => $match[3], - ) - ); - - $rgb['a'] = 1; - - return $rgb; - } - - $rgba_regexp = '/^rgba' . $permissive_match4 . '$/'; - if ( preg_match( $rgba_regexp, $color_str, $match ) ) { - $rgb = wp_tinycolor_rgb_to_rgb( - array( - 'r' => $match[1], - 'g' => $match[2], - 'b' => $match[3], - ) - ); - - $rgb['a'] = _wp_tinycolor_bound_alpha( $match[4] ); - - return $rgb; - } - - $hsl_regexp = '/^hsl' . $permissive_match3 . '$/'; - if ( preg_match( $hsl_regexp, $color_str, $match ) ) { - $rgb = wp_tinycolor_hsl_to_rgb( - array( - 'h' => $match[1], - 's' => $match[2], - 'l' => $match[3], - ) - ); - - $rgb['a'] = 1; - - return $rgb; - } - - $hsla_regexp = '/^hsla' . $permissive_match4 . '$/'; - if ( preg_match( $hsla_regexp, $color_str, $match ) ) { - $rgb = wp_tinycolor_hsl_to_rgb( - array( - 'h' => $match[1], - 's' => $match[2], - 'l' => $match[3], - ) - ); - - $rgb['a'] = _wp_tinycolor_bound_alpha( $match[4] ); - - return $rgb; - } - - $hex8_regexp = '/^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/'; - if ( preg_match( $hex8_regexp, $color_str, $match ) ) { - $rgb = wp_tinycolor_rgb_to_rgb( - array( - 'r' => base_convert( $match[1], 16, 10 ), - 'g' => base_convert( $match[2], 16, 10 ), - 'b' => base_convert( $match[3], 16, 10 ), - ) - ); - - $rgb['a'] = _wp_tinycolor_bound_alpha( - base_convert( $match[4], 16, 10 ) / 255 - ); - - return $rgb; - } - - $hex6_regexp = '/^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/'; - if ( preg_match( $hex6_regexp, $color_str, $match ) ) { - $rgb = wp_tinycolor_rgb_to_rgb( - array( - 'r' => base_convert( $match[1], 16, 10 ), - 'g' => base_convert( $match[2], 16, 10 ), - 'b' => base_convert( $match[3], 16, 10 ), - ) - ); - - $rgb['a'] = 1; - - return $rgb; - } - - $hex4_regexp = '/^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/'; - if ( preg_match( $hex4_regexp, $color_str, $match ) ) { - $rgb = wp_tinycolor_rgb_to_rgb( - array( - 'r' => base_convert( $match[1] . $match[1], 16, 10 ), - 'g' => base_convert( $match[2] . $match[2], 16, 10 ), - 'b' => base_convert( $match[3] . $match[3], 16, 10 ), - ) - ); - - $rgb['a'] = _wp_tinycolor_bound_alpha( - base_convert( $match[4] . $match[4], 16, 10 ) / 255 - ); - - return $rgb; - } - - $hex3_regexp = '/^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/'; - if ( preg_match( $hex3_regexp, $color_str, $match ) ) { - $rgb = wp_tinycolor_rgb_to_rgb( - array( - 'r' => base_convert( $match[1] . $match[1], 16, 10 ), - 'g' => base_convert( $match[2] . $match[2], 16, 10 ), - 'b' => base_convert( $match[3] . $match[3], 16, 10 ), - ) - ); - - $rgb['a'] = 1; - - return $rgb; - } - - /* - * The JS color picker considers the string "transparent" to be a hex value, - * so we need to handle it here as a special case. - */ - if ( 'transparent' === $color_str ) { - return array( - 'r' => 0, - 'g' => 0, - 'b' => 0, - 'a' => 0, - ); - } -} - -/** - * Returns the prefixed id for the duotone filter for use as a CSS id. - * - * @since 5.9.1 - * @access private - * - * @deprecated 6.3.0 - * - * @param array $preset Duotone preset value as seen in theme.json. - * @return string Duotone filter CSS id. - */ -function wp_get_duotone_filter_id( $preset ) { - _deprecated_function( __FUNCTION__, '6.3.0' ); - return WP_Duotone::get_filter_id_from_preset( $preset ); -} - -/** - * Returns the CSS filter property url to reference the rendered SVG. - * - * @since 5.9.0 - * @since 6.1.0 Allow unset for preset colors. - * @access private - * - * @deprecated 6.3.0 - * - * @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 ) { - _deprecated_function( __FUNCTION__, '6.3.0' ); - return WP_Duotone::get_filter_css_property_value_from_preset( $preset ); -} - -/** - * Returns the duotone filter SVG string for the preset. - * - * @since 5.9.1 - * @access private - * - * @deprecated 6.3.0 - * - * @param array $preset Duotone preset value as seen in theme.json. - * @return string Duotone SVG filter. - */ -function wp_get_duotone_filter_svg( $preset ) { - _deprecated_function( __FUNCTION__, '6.3.0' ); - return WP_Duotone::get_filter_svg_from_preset( $preset ); -} - -/** - * Registers the style and colors block attributes for block types that support it. - * - * @since 5.8.0 - * @access private - * - * @deprecated 6.3.0 Use WP_Duotone::register_duotone_support() instead. - * - * @param WP_Block_Type $block_type Block Type. - */ -function wp_register_duotone_support( $block_type ) { - _deprecated_function( __FUNCTION__, '6.3.0', 'WP_Duotone::register_duotone_support' ); - return WP_Duotone::register_duotone_support( $block_type ); -} - -/** - * Renders out the duotone stylesheet and SVG. - * - * @since 5.8.0 - * @since 6.1.0 Allow unset for preset colors. - * @access private - * - * @param string $block_content Rendered block content. - * @param array $block Block object. - * @deprecated 6.3.0 Use WP_Duotone::render_duotone_support() instead. - * @return string Filtered block content. - */ -function wp_render_duotone_support( $block_content, $block ) { - _deprecated_function( __FUNCTION__, '6.3.0', 'WP_Duotone::render_duotone_support' ); - return WP_Duotone::render_duotone_support( $block_content, $block ); -} diff --git a/src/wp-includes/deprecated.php b/src/wp-includes/deprecated.php index 1626995290d24..2887a6474eb3b 100644 --- a/src/wp-includes/deprecated.php +++ b/src/wp-includes/deprecated.php @@ -4804,3 +4804,427 @@ function wp_img_tag_add_loading_attr( $image, $context ) { return $image; } + +/** + * Takes input from [0, n] and returns it as [0, 1]. + * + * Direct port of TinyColor's function, lightly simplified to maintain + * consistency with TinyColor. + * + * @see https://github.com/bgrins/TinyColor + * + * @deprecated 6.3.0 + * + * @since 5.8.0 + * @access private + * + * @param mixed $n Number of unknown type. + * @param int $max Upper value of the range to bound to. + * @return float Value in the range [0, 1]. + */ +function wp_tinycolor_bound01( $n, $max ) { + _deprecated_function( __FUNCTION__, '6.3.0' ); + if ( 'string' === gettype( $n ) && str_contains( $n, '.' ) && 1 === (float) $n ) { + $n = '100%'; + } + + $n = min( $max, max( 0, (float) $n ) ); + + // Automatically convert percentage into number. + if ( 'string' === gettype( $n ) && str_contains( $n, '%' ) ) { + $n = (int) ( $n * $max ) / 100; + } + + // Handle floating point rounding errors. + if ( ( abs( $n - $max ) < 0.000001 ) ) { + return 1.0; + } + + // Convert into [0, 1] range if it isn't already. + return ( $n % $max ) / (float) $max; +} + +/** + * Direct port of tinycolor's boundAlpha function to maintain consistency with + * how tinycolor works. + * + * @see https://github.com/bgrins/TinyColor + * + * @deprecated 6.3.0 + * + * @since 5.9.0 + * @access private + * + * @param mixed $n Number of unknown type. + * @return float Value in the range [0,1]. + */ +function _wp_tinycolor_bound_alpha( $n ) { + _deprecated_function( __FUNCTION__, '6.3.0' ); + + if ( is_numeric( $n ) ) { + $n = (float) $n; + if ( $n >= 0 && $n <= 1 ) { + return $n; + } + } + return 1; +} + +/** + * Rounds and converts values of an RGB object. + * + * Direct port of TinyColor's function, lightly simplified to maintain + * consistency with TinyColor. + * + * @see https://github.com/bgrins/TinyColor + * + * @deprecated 6.3.0 + * + * @since 5.8.0 + * @access private + * + * @param array $rgb_color RGB object. + * @return array Rounded and converted RGB object. + */ +function wp_tinycolor_rgb_to_rgb( $rgb_color ) { + _deprecated_function( __FUNCTION__, '6.3.0' ); + + return array( + 'r' => wp_tinycolor_bound01( $rgb_color['r'], 255 ) * 255, + 'g' => wp_tinycolor_bound01( $rgb_color['g'], 255 ) * 255, + 'b' => wp_tinycolor_bound01( $rgb_color['b'], 255 ) * 255, + ); +} + +/** + * Helper function for hsl to rgb conversion. + * + * Direct port of TinyColor's function, lightly simplified to maintain + * consistency with TinyColor. + * + * @see https://github.com/bgrins/TinyColor + * + * @deprecated 6.3.0 + * + * @since 5.8.0 + * @access private + * + * @param float $p first component. + * @param float $q second component. + * @param float $t third component. + * @return float R, G, or B component. + */ +function wp_tinycolor_hue_to_rgb( $p, $q, $t ) { + _deprecated_function( __FUNCTION__, '6.3.0' ); + + if ( $t < 0 ) { + ++$t; + } + if ( $t > 1 ) { + --$t; + } + if ( $t < 1 / 6 ) { + return $p + ( $q - $p ) * 6 * $t; + } + if ( $t < 1 / 2 ) { + return $q; + } + if ( $t < 2 / 3 ) { + return $p + ( $q - $p ) * ( 2 / 3 - $t ) * 6; + } + return $p; +} + +/** + * Converts an HSL object to an RGB object with converted and rounded values. + * + * Direct port of TinyColor's function, lightly simplified to maintain + * consistency with TinyColor. + * + * @see https://github.com/bgrins/TinyColor + * + * @deprecated 6.3.0 + * + * @since 5.8.0 + * @access private + * + * @param array $hsl_color HSL object. + * @return array Rounded and converted RGB object. + */ +function wp_tinycolor_hsl_to_rgb( $hsl_color ) { + _deprecated_function( __FUNCTION__, '6.3.0' ); + + $h = wp_tinycolor_bound01( $hsl_color['h'], 360 ); + $s = wp_tinycolor_bound01( $hsl_color['s'], 100 ); + $l = wp_tinycolor_bound01( $hsl_color['l'], 100 ); + + if ( 0 === $s ) { + // Achromatic. + $r = $l; + $g = $l; + $b = $l; + } else { + $q = $l < 0.5 ? $l * ( 1 + $s ) : $l + $s - $l * $s; + $p = 2 * $l - $q; + $r = wp_tinycolor_hue_to_rgb( $p, $q, $h + 1 / 3 ); + $g = wp_tinycolor_hue_to_rgb( $p, $q, $h ); + $b = wp_tinycolor_hue_to_rgb( $p, $q, $h - 1 / 3 ); + } + + return array( + 'r' => $r * 255, + 'g' => $g * 255, + 'b' => $b * 255, + ); +} + +/** + * Parses hex, hsl, and rgb CSS strings using the same regex as TinyColor v1.4.2 + * used in the JavaScript. Only colors output from react-color are implemented. + * + * Direct port of TinyColor's function, lightly simplified to maintain + * consistency with TinyColor. + * + * @see https://github.com/bgrins/TinyColor + * @see https://github.com/casesandberg/react-color/ + * + * @deprecated 6.3.0 + * + * @since 5.8.0 + * @since 5.9.0 Added alpha processing. + * @access private + * + * @param string $color_str CSS color string. + * @return array RGB object. + */ +function wp_tinycolor_string_to_rgb( $color_str ) { + _deprecated_function( __FUNCTION__, '6.3.0' ); + + $color_str = strtolower( trim( $color_str ) ); + + $css_integer = '[-\\+]?\\d+%?'; + $css_number = '[-\\+]?\\d*\\.\\d+%?'; + + $css_unit = '(?:' . $css_number . ')|(?:' . $css_integer . ')'; + + $permissive_match3 = '[\\s|\\(]+(' . $css_unit . ')[,|\\s]+(' . $css_unit . ')[,|\\s]+(' . $css_unit . ')\\s*\\)?'; + $permissive_match4 = '[\\s|\\(]+(' . $css_unit . ')[,|\\s]+(' . $css_unit . ')[,|\\s]+(' . $css_unit . ')[,|\\s]+(' . $css_unit . ')\\s*\\)?'; + + $rgb_regexp = '/^rgb' . $permissive_match3 . '$/'; + if ( preg_match( $rgb_regexp, $color_str, $match ) ) { + $rgb = wp_tinycolor_rgb_to_rgb( + array( + 'r' => $match[1], + 'g' => $match[2], + 'b' => $match[3], + ) + ); + + $rgb['a'] = 1; + + return $rgb; + } + + $rgba_regexp = '/^rgba' . $permissive_match4 . '$/'; + if ( preg_match( $rgba_regexp, $color_str, $match ) ) { + $rgb = wp_tinycolor_rgb_to_rgb( + array( + 'r' => $match[1], + 'g' => $match[2], + 'b' => $match[3], + ) + ); + + $rgb['a'] = _wp_tinycolor_bound_alpha( $match[4] ); + + return $rgb; + } + + $hsl_regexp = '/^hsl' . $permissive_match3 . '$/'; + if ( preg_match( $hsl_regexp, $color_str, $match ) ) { + $rgb = wp_tinycolor_hsl_to_rgb( + array( + 'h' => $match[1], + 's' => $match[2], + 'l' => $match[3], + ) + ); + + $rgb['a'] = 1; + + return $rgb; + } + + $hsla_regexp = '/^hsla' . $permissive_match4 . '$/'; + if ( preg_match( $hsla_regexp, $color_str, $match ) ) { + $rgb = wp_tinycolor_hsl_to_rgb( + array( + 'h' => $match[1], + 's' => $match[2], + 'l' => $match[3], + ) + ); + + $rgb['a'] = _wp_tinycolor_bound_alpha( $match[4] ); + + return $rgb; + } + + $hex8_regexp = '/^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/'; + if ( preg_match( $hex8_regexp, $color_str, $match ) ) { + $rgb = wp_tinycolor_rgb_to_rgb( + array( + 'r' => base_convert( $match[1], 16, 10 ), + 'g' => base_convert( $match[2], 16, 10 ), + 'b' => base_convert( $match[3], 16, 10 ), + ) + ); + + $rgb['a'] = _wp_tinycolor_bound_alpha( + base_convert( $match[4], 16, 10 ) / 255 + ); + + return $rgb; + } + + $hex6_regexp = '/^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/'; + if ( preg_match( $hex6_regexp, $color_str, $match ) ) { + $rgb = wp_tinycolor_rgb_to_rgb( + array( + 'r' => base_convert( $match[1], 16, 10 ), + 'g' => base_convert( $match[2], 16, 10 ), + 'b' => base_convert( $match[3], 16, 10 ), + ) + ); + + $rgb['a'] = 1; + + return $rgb; + } + + $hex4_regexp = '/^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/'; + if ( preg_match( $hex4_regexp, $color_str, $match ) ) { + $rgb = wp_tinycolor_rgb_to_rgb( + array( + 'r' => base_convert( $match[1] . $match[1], 16, 10 ), + 'g' => base_convert( $match[2] . $match[2], 16, 10 ), + 'b' => base_convert( $match[3] . $match[3], 16, 10 ), + ) + ); + + $rgb['a'] = _wp_tinycolor_bound_alpha( + base_convert( $match[4] . $match[4], 16, 10 ) / 255 + ); + + return $rgb; + } + + $hex3_regexp = '/^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/'; + if ( preg_match( $hex3_regexp, $color_str, $match ) ) { + $rgb = wp_tinycolor_rgb_to_rgb( + array( + 'r' => base_convert( $match[1] . $match[1], 16, 10 ), + 'g' => base_convert( $match[2] . $match[2], 16, 10 ), + 'b' => base_convert( $match[3] . $match[3], 16, 10 ), + ) + ); + + $rgb['a'] = 1; + + return $rgb; + } + + /* + * The JS color picker considers the string "transparent" to be a hex value, + * so we need to handle it here as a special case. + */ + if ( 'transparent' === $color_str ) { + return array( + 'r' => 0, + 'g' => 0, + 'b' => 0, + 'a' => 0, + ); + } +} + +/** + * Returns the prefixed id for the duotone filter for use as a CSS id. + * + * @since 5.9.1 + * @access private + * + * @deprecated 6.3.0 + * + * @param array $preset Duotone preset value as seen in theme.json. + * @return string Duotone filter CSS id. + */ +function wp_get_duotone_filter_id( $preset ) { + _deprecated_function( __FUNCTION__, '6.3.0' ); + return WP_Duotone::get_filter_id_from_preset( $preset ); +} + +/** + * Returns the CSS filter property url to reference the rendered SVG. + * + * @since 5.9.0 + * @since 6.1.0 Allow unset for preset colors. + * @access private + * + * @deprecated 6.3.0 + * + * @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 ) { + _deprecated_function( __FUNCTION__, '6.3.0' ); + return WP_Duotone::get_filter_css_property_value_from_preset( $preset ); +} + +/** + * Returns the duotone filter SVG string for the preset. + * + * @since 5.9.1 + * @access private + * + * @deprecated 6.3.0 + * + * @param array $preset Duotone preset value as seen in theme.json. + * @return string Duotone SVG filter. + */ +function wp_get_duotone_filter_svg( $preset ) { + _deprecated_function( __FUNCTION__, '6.3.0' ); + return WP_Duotone::get_filter_svg_from_preset( $preset ); +} + +/** + * Registers the style and colors block attributes for block types that support it. + * + * @since 5.8.0 + * @access private + * + * @deprecated 6.3.0 Use WP_Duotone::register_duotone_support() instead. + * + * @param WP_Block_Type $block_type Block Type. + */ +function wp_register_duotone_support( $block_type ) { + _deprecated_function( __FUNCTION__, '6.3.0', 'WP_Duotone::register_duotone_support' ); + return WP_Duotone::register_duotone_support( $block_type ); +} + +/** + * Renders out the duotone stylesheet and SVG. + * + * @since 5.8.0 + * @since 6.1.0 Allow unset for preset colors. + * @access private + * + * @param string $block_content Rendered block content. + * @param array $block Block object. + * @deprecated 6.3.0 Use WP_Duotone::render_duotone_support() instead. + * @return string Filtered block content. + */ +function wp_render_duotone_support( $block_content, $block ) { + _deprecated_function( __FUNCTION__, '6.3.0', 'WP_Duotone::render_duotone_support' ); + return WP_Duotone::render_duotone_support( $block_content, $block ); +} From ae122dafb097640a49e88f690a7f6a52367933a0 Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Mon, 26 Jun 2023 12:31:52 -0500 Subject: [PATCH 35/47] Mark private and new deprecated methods as internal --- src/wp-includes/class-wp-duotone.php | 91 ++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index c8a2348e3c8de..f0a7b33f78951 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -48,6 +48,8 @@ class WP_Duotone { * … * ] * + * @internal + * * @var array */ private static $global_styles_block_names = array(); @@ -68,6 +70,8 @@ class WP_Duotone { * … * ] * + * @internal + * * @var array */ private static $global_styles_presets = array(); @@ -85,6 +89,8 @@ class WP_Duotone { * … * ] * + * @internal + * * @var array */ private static $used_global_styles_presets = array(); @@ -106,6 +112,8 @@ class WP_Duotone { * … * ] * + * @internal + * * @var array */ private static $used_svg_filter_data = array(); @@ -124,15 +132,21 @@ class WP_Duotone { * … * ] * + * @internal + * * @var array */ private static $block_css_declarations = array(); /** * Clamps a value between an upper and lower bound. + * + * Direct port of colord's clamp function. * * @link https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/helpers.ts#L23 Sourced from colord. * + * @internal + * * @param float $number The number to clamp. * @param float $min The minimum value. * @param float $max The maximum value. @@ -145,8 +159,12 @@ private static function colord_clamp( $number, $min = 0, $max = 1 ) { /** * Processes and clamps a degree (angle) value properly. * + * Direct port of colord's clampHue function. + * * @link https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/helpers.ts#L32 Sourced from colord. * + * @internal + * * @param float $degrees The hue to clamp. * @return float The clamped hue. */ @@ -158,8 +176,12 @@ private static function colord_clamp_hue( $degrees ) { /** * Converts a hue value to degrees from 0 to 360 inclusive. * + * Direct port of colord's parseHue function. + * * @link https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/helpers.ts#L40 Sourced from colord. * + * @internal + * * @param float $value The hue value to parse. * @param string $unit The unit of the hue value. * @return float The parsed hue value. @@ -182,8 +204,12 @@ private static function colord_parse_hue( $value, $unit = 'deg' ) { /** * Parses any valid Hex3, Hex4, Hex6 or Hex8 string and converts it to an RGBA object * + * Direct port of colord's parseHex function. + * * @link https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colorModels/hex.ts#L8 Sourced from colord. * + * @internal + * * @param string $hex The hex string to parse. * @return array|null An array of RGBA values or null if the hex string is invalid. */ @@ -224,8 +250,12 @@ private static function colord_parse_hex( $hex ) { /** * Clamps an array of RGBA values. * + * Direct port of colord's clampRgba function. + * * @link https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colorModels/rgb.ts#L5 Sourced from colord. * + * @internal + * * @param array $rgba The RGBA array to clamp. * @return array The clamped RGBA array. */ @@ -241,8 +271,12 @@ private static function colord_clamp_rgba( $rgba ) { /** * Parses a valid RGB[A] CSS color function/string * + * Direct port of colord's parseRgbaString function. + * * @link https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colorModels/rgbString.ts#L18 Sourced from colord. * + * @internal + * * @param string $input The RGBA string to parse. * @return array|null An array of RGBA values or null if the RGB string is invalid. */ @@ -294,8 +328,12 @@ private static function colord_parse_rgba_string( $input ) { /** * Clamps an array of HSLA values. * + * Direct port of colord's clampHsla function. + * * @link https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colorModels/hsl.ts#L6 Sourced from colord. * + * @internal + * * @param array $hsla The HSLA array to clamp. * @return array The clamped HSLA array. */ @@ -311,8 +349,12 @@ private static function colord_clamp_hsla( $hsla ) { /** * Converts an HSVA array to RGBA. * + * Direct port of colord's hsvaToRgba function. + * * @link https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colorModels/hsv.ts#L52 Sourced from colord. * + * @internal + * * @param array $hsva The HSVA array to convert. * @return array The RGBA array. */ @@ -339,8 +381,12 @@ private static function colord_hsva_to_rgba( $hsva ) { /** * Converts an HSLA array to HSVA. * + * Direct port of colord's hslaToHsva function. + * * @link https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colorModels/hsl.ts#L33 Sourced from colord. * + * @internal + * * @param array $hsla The HSLA array to convert. * @return array The HSVA array. */ @@ -363,8 +409,12 @@ private static function colord_hsla_to_hsva( $hsla ) { /** * Converts an HSLA array to RGBA. * + * Direct port of colord's hslaToRgba function. + * * @link https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colorModels/hsl.ts#L55 Sourced from colord. * + * @internal + * * @param array $hsla The HSLA array to convert. * @return array The RGBA array. */ @@ -375,8 +425,12 @@ private static function colord_hsla_to_rgba( $hsla ) { /** * Parses a valid HSL[A] CSS color function/string. * + * Direct port of colord's parseHslaString function. + * * @link https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/colorModels/hslString.ts#L17 Sourced from colord. * + * @internal + * * @param string $input The HSLA string to parse. * @return array|null An array of RGBA values or null if the RGB string is invalid. */ @@ -426,8 +480,13 @@ private static function colord_parse_hsla_string( $input ) { /** * Tries to convert an incoming string into RGBA values. * + * Direct port of colord's parse function simplified for our use case. This + * version only supports string parsing and only returns RGBA values. + * * @link https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/parse.ts#L37 Sourced from colord. * + * @internal + * * @param string $input The string to parse. * @return array|null An array of RGBA values or null if the string is invalid. */ @@ -452,6 +511,8 @@ private static function colord_parse( $input ) { * var:preset|duotone|blue-orange * var(--wp--preset--duotone--blue-orange) * + * @internal + * * @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. */ @@ -465,6 +526,8 @@ private static function get_slug_from_attribute( $duotone_attr ) { /** * Checks if we have a valid duotone preset. * + * @internal + * * @param string $duotone_attr The duotone attribute from a block. * @return bool True if the duotone preset present and valid. */ @@ -478,6 +541,8 @@ private static function is_preset( $duotone_attr ) { /** * Gets the CSS variable name for a duotone preset. * + * @internal + * * @param string $slug The slug of the duotone preset. * @return string The CSS variable name. */ @@ -488,6 +553,8 @@ private static function get_css_custom_property_name( $slug ) { /** * Get the ID of the duotone filter. * + * @internal + * * @param string $slug The slug of the duotone preset. * @return string The ID of the duotone filter. */ @@ -498,6 +565,8 @@ private static function get_filter_id( $slug ) { /** * Get the CSS variable for a duotone preset. * + * @internal + * * @param string $slug The slug of the duotone preset. * @return string The CSS variable. */ @@ -509,6 +578,8 @@ private static function get_css_var( $slug ) { /** * Get the URL for a duotone filter. * + * @internal + * * @param string $filter_id The ID of the filter. * @return string The URL for the duotone filter. */ @@ -519,6 +590,8 @@ private static function get_filter_url( $filter_id ) { /** * Gets the SVG for the duotone filter definition. * + * @internal + * * @param string $filter_id The ID of the filter. * @param array $colors An array of color strings. * @return string An SVG with a duotone filter definition. @@ -604,6 +677,8 @@ private static function get_filter_svg( $filter_id, $colors ) { * * Exported for the deprecated function wp_get_duotone_filter_id(). * + * @internal + * * @since 6.3.0 * @deprecated 6.3.0 * @@ -625,6 +700,8 @@ public static function get_filter_id_from_preset( $preset ) { * * Exported for the deprecated function wp_get_duotone_filter_property(). * + * @internal + * * @since 6.3.0 * @deprecated 6.3.0 * @@ -644,6 +721,8 @@ public static function get_filter_svg_from_preset( $preset ) { * Example output: * * + * @internal + * * @param array $sources The duotone presets. * @return string The SVGs for the duotone filters. */ @@ -662,6 +741,8 @@ private static function get_svg_definitions( $sources ) { * Example output: * body{--wp--preset--duotone--blue-orange:url('#wp-duotone-blue-orange');} * + * @internal + * * @param array $sources The duotone presets. * @return string The CSS for global styles. */ @@ -681,6 +762,8 @@ private static function get_global_styles_presets( $sources ) { /** * Enqueue a block CSS declaration for the page. * + * @internal + * * @param string $filter_id The filter ID. e.g. 'wp-duotone-000000-ffffff-2'. * @param string $duotone_selector The block's duotone selector. e.g. '.wp-block-image img'. * @param string $filter_value The filter CSS value. e.g. 'url(#wp-duotone-000000-ffffff-2)' or 'unset'. @@ -714,6 +797,8 @@ private static function enqueue_block_css( $filter_id, $duotone_selector, $filte * * Includes an SVG filter and block CSS declaration. * + * @internal + * * @param string $filter_id The filter ID. e.g. 'wp-duotone-000000-ffffff-2'. * @param string $duotone_selector The block's duotone selector. e.g. '.wp-block-image img'. * @param string $filter_value The filter CSS value. e.g. 'url(#wp-duotone-000000-ffffff-2)' or 'unset'. @@ -729,6 +814,8 @@ private static function enqueue_custom_filter( $filter_id, $duotone_selector, $f * * Includes a CSS custom property, SVG filter, and block CSS declaration. * + * @internal + * * @param string $filter_id The filter ID. e.g. 'wp-duotone-blue-orange'. * @param string $duotone_selector The block's duotone selector. e.g. '.wp-block-image img'. * @param string $filter_value The filter CSS value. e.g. 'url(#wp-duotone-blue-orange)' or 'unset'. @@ -782,6 +869,8 @@ public static function register_duotone_support( $block_type ) { * * @param string $block_name The block name. * + * @internal + * * @return string The CSS selector or null if there is no support. */ private static function get_selector( $block_name ) { @@ -1066,6 +1155,8 @@ public static function migrate_experimental_duotone_support_flag( $settings, $me * * Exported for the deprecated function wp_get_duotone_filter_id(). * + * @internal + * * @since 6.3.0 * @deprecated 6.3.0 * From 6a91d9383a48885a92994ae5a13b1c64cfc34197 Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Mon, 26 Jun 2023 12:37:30 -0500 Subject: [PATCH 36/47] Format line wrapping in comment --- src/wp-includes/class-wp-duotone.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index f0a7b33f78951..e74e7d518ce5d 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -1092,9 +1092,8 @@ public static function output_footer_assets() { /** * Adds the duotone SVGs and CSS custom properties to the editor settings. * - * This allows the properties to be - * pulled in by the EditorStyles component in JS and rendered in - * the post editor. + * This allows the properties to be pulled in by the EditorStyles component + * in JS and rendered in the post editor. * * @since 6.3.0 * From 5141c6a07a3bf6b1e3178059bdc2e60946f3211a Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Mon, 26 Jun 2023 12:46:52 -0500 Subject: [PATCH 37/47] Update deprecated function docblock link and order --- src/wp-includes/deprecated.php | 47 +++++++++++++++++----------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/src/wp-includes/deprecated.php b/src/wp-includes/deprecated.php index 2887a6474eb3b..60ecd3a02c84e 100644 --- a/src/wp-includes/deprecated.php +++ b/src/wp-includes/deprecated.php @@ -4811,11 +4811,11 @@ function wp_img_tag_add_loading_attr( $image, $context ) { * Direct port of TinyColor's function, lightly simplified to maintain * consistency with TinyColor. * - * @see https://github.com/bgrins/TinyColor + * @link https://github.com/bgrins/TinyColor * + * @since 5.8.0 * @deprecated 6.3.0 * - * @since 5.8.0 * @access private * * @param mixed $n Number of unknown type. @@ -4848,11 +4848,11 @@ function wp_tinycolor_bound01( $n, $max ) { * Direct port of tinycolor's boundAlpha function to maintain consistency with * how tinycolor works. * - * @see https://github.com/bgrins/TinyColor + * @link https://github.com/bgrins/TinyColor * + * @since 5.9.0 * @deprecated 6.3.0 * - * @since 5.9.0 * @access private * * @param mixed $n Number of unknown type. @@ -4876,11 +4876,11 @@ function _wp_tinycolor_bound_alpha( $n ) { * Direct port of TinyColor's function, lightly simplified to maintain * consistency with TinyColor. * - * @see https://github.com/bgrins/TinyColor + * @link https://github.com/bgrins/TinyColor * + * @since 5.8.0 * @deprecated 6.3.0 * - * @since 5.8.0 * @access private * * @param array $rgb_color RGB object. @@ -4902,11 +4902,11 @@ function wp_tinycolor_rgb_to_rgb( $rgb_color ) { * Direct port of TinyColor's function, lightly simplified to maintain * consistency with TinyColor. * - * @see https://github.com/bgrins/TinyColor + * @link https://github.com/bgrins/TinyColor * + * @since 5.8.0 * @deprecated 6.3.0 * - * @since 5.8.0 * @access private * * @param float $p first component. @@ -4941,11 +4941,11 @@ function wp_tinycolor_hue_to_rgb( $p, $q, $t ) { * Direct port of TinyColor's function, lightly simplified to maintain * consistency with TinyColor. * - * @see https://github.com/bgrins/TinyColor + * @link https://github.com/bgrins/TinyColor * + * @since 5.8.0 * @deprecated 6.3.0 * - * @since 5.8.0 * @access private * * @param array $hsl_color HSL object. @@ -4985,13 +4985,13 @@ function wp_tinycolor_hsl_to_rgb( $hsl_color ) { * Direct port of TinyColor's function, lightly simplified to maintain * consistency with TinyColor. * - * @see https://github.com/bgrins/TinyColor - * @see https://github.com/casesandberg/react-color/ - * - * @deprecated 6.3.0 + * @link https://github.com/bgrins/TinyColor + * @link https://github.com/casesandberg/react-color/ * * @since 5.8.0 * @since 5.9.0 Added alpha processing. + * @deprecated 6.3.0 + * * @access private * * @param string $color_str CSS color string. @@ -5152,9 +5152,9 @@ 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.1 - * @access private + * @deprecated 6.3.0 * - * @deprecated 6.3.0 + * @access private * * @param array $preset Duotone preset value as seen in theme.json. * @return string Duotone filter CSS id. @@ -5169,10 +5169,10 @@ function wp_get_duotone_filter_id( $preset ) { * * @since 5.9.0 * @since 6.1.0 Allow unset for preset colors. - * @access private - * * @deprecated 6.3.0 * + * @access private + * * @param array $preset Duotone preset value as seen in theme.json. * @return string Duotone CSS filter property url value. */ @@ -5185,10 +5185,10 @@ function wp_get_duotone_filter_property( $preset ) { * Returns the duotone filter SVG string for the preset. * * @since 5.9.1 - * @access private - * * @deprecated 6.3.0 * + * @access private + * * @param array $preset Duotone preset value as seen in theme.json. * @return string Duotone SVG filter. */ @@ -5201,10 +5201,10 @@ function wp_get_duotone_filter_svg( $preset ) { * Registers the style and colors block attributes for block types that support it. * * @since 5.8.0 - * @access private - * * @deprecated 6.3.0 Use WP_Duotone::register_duotone_support() instead. * + * @access private + * * @param WP_Block_Type $block_type Block Type. */ function wp_register_duotone_support( $block_type ) { @@ -5217,11 +5217,12 @@ function wp_register_duotone_support( $block_type ) { * * @since 5.8.0 * @since 6.1.0 Allow unset for preset colors. + * @deprecated 6.3.0 Use WP_Duotone::render_duotone_support() instead. + * * @access private * * @param string $block_content Rendered block content. * @param array $block Block object. - * @deprecated 6.3.0 Use WP_Duotone::render_duotone_support() instead. * @return string Filtered block content. */ function wp_render_duotone_support( $block_content, $block ) { From ec248c2081225db4fbd317c84e9daf74c1e167c0 Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Mon, 26 Jun 2023 13:11:23 -0500 Subject: [PATCH 38/47] Fix trailing space --- src/wp-includes/class-wp-duotone.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index e74e7d518ce5d..b735d24cbcea7 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -140,7 +140,7 @@ class WP_Duotone { /** * Clamps a value between an upper and lower bound. - * + * * Direct port of colord's clamp function. * * @link https://github.com/omgovich/colord/blob/3f859e03b0ca622eb15480f611371a0f15c9427f/src/helpers.ts#L23 Sourced from colord. From 375ce417874aec78615b791c3f728dd492da20e2 Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Mon, 26 Jun 2023 13:53:59 -0500 Subject: [PATCH 39/47] Add more description to the WP_Duotone methods --- src/wp-includes/class-wp-duotone.php | 50 ++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index b735d24cbcea7..241a92d96c824 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -526,6 +526,8 @@ private static function get_slug_from_attribute( $duotone_attr ) { /** * Checks if we have a valid duotone preset. * + * Valid presets are defined in the $global_styles_presets array. + * * @internal * * @param string $duotone_attr The duotone attribute from a block. @@ -541,6 +543,9 @@ private static function is_preset( $duotone_attr ) { /** * Gets the CSS variable name for a duotone preset. * + * Example output: + * --wp--preset--duotone--blue-orange + * * @internal * * @param string $slug The slug of the duotone preset. @@ -553,6 +558,9 @@ private static function get_css_custom_property_name( $slug ) { /** * Get the ID of the duotone filter. * + * Example output: + * wp-duotone-blue-orange + * * @internal * * @param string $slug The slug of the duotone preset. @@ -565,6 +573,9 @@ private static function get_filter_id( $slug ) { /** * Get the CSS variable for a duotone preset. * + * Example output: + * var(--wp--preset--duotone--blue-orange) + * * @internal * * @param string $slug The slug of the duotone preset. @@ -578,6 +589,9 @@ private static function get_css_var( $slug ) { /** * Get the URL for a duotone filter. * + * Example output: + * url(#wp-duotone-blue-orange) + * * @internal * * @param string $filter_id The ID of the filter. @@ -590,6 +604,8 @@ private static function get_filter_url( $filter_id ) { /** * Gets the SVG for the duotone filter definition. * + * Whitespace is removed when SCRIPT_DEBUG is not enabled. + * * @internal * * @param string $filter_id The ID of the filter. @@ -762,6 +778,8 @@ private static function get_global_styles_presets( $sources ) { /** * Enqueue a block CSS declaration for the page. * + * This does not include any SVGs. + * * @internal * * @param string $filter_id The filter ID. e.g. 'wp-duotone-000000-ffffff-2'. @@ -837,6 +855,8 @@ private static function enqueue_global_styles_preset( $filter_id, $duotone_selec /** * Registers the style and colors block attributes for block types that support it. * + * Block support is added with `supports.filter.duotone` in block.json. + * * @since 6.3.0 * * @param WP_Block_Type $block_type Block Type. @@ -867,6 +887,9 @@ public static function register_duotone_support( $block_type ) { /** * Get the CSS selector for a block type. * + * This handles selectors defined in `color.__experimentalDuotone` support + * if `filter.duotone` support is not defined. + * * @param string $block_name The block name. * * @internal @@ -907,10 +930,11 @@ private static function get_selector( $block_name ) { } /** - * Get all possible duotone presets from global and theme styles. + * Scrape all possible duotone presets from global and theme styles and + * store them in self::$global_styles_presets. * - * Store each item 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. + * Used in conjunction with self::render_duotone_support for blocks that + * use duotone preset filters. * * @since 6.3.0 */ @@ -929,7 +953,10 @@ public static function set_global_styles_presets() { } /** - * Scrape all block names from global styles and store in self::$global_styles_block_names + * Scrape all block names from global styles and store in self::$global_styles_block_names. + * + * Used in conjunction with self::render_duotone_support to output the + * duotone filters defined in the theme.json global styles. * * @since 6.3.0 */ @@ -964,6 +991,9 @@ public static function set_global_style_block_names() { /** * Render out the duotone CSS styles and SVG. * + * The hooks self::set_global_style_block_names and self::set_global_styles_presets + * must be called before this function. + * * @since 6.3.0 * * @param string $block_content Rendered block content. @@ -1048,6 +1078,8 @@ public static function render_duotone_support( $block_content, $block ) { /** * Appends the used block duotone filter declarations to the inline block supports CSS. * + * Uses the declarations saved in earlier calls to self::enqueue_block_css. + * * @since 6.3.0 */ public static function output_block_styles() { @@ -1065,6 +1097,8 @@ public static function output_block_styles() { * Appends the used global style duotone filter presets (CSS custom * properties) to the inline global styles CSS. * + * Uses the declarations saved in earlier calls to self::enqueue_global_styles_preset. + * * @since 6.3.0 */ public static function output_global_styles() { @@ -1076,6 +1110,9 @@ public static function output_global_styles() { /** * Outputs all necessary SVG for duotone filters, CSS for classic themes. * + * Uses the declarations saved in earlier calls to self::enqueue_global_styles_preset + * and self::enqueue_custom_filter. + * * @since 6.3.0 */ public static function output_footer_assets() { @@ -1129,8 +1166,9 @@ public static function add_editor_settings( $settings ) { } /** - * Migrate the old experimental duotone support flag to its stabilized location - * under `supports.filter.duotone` and sets. + * Migrates the experimental duotone support flag to the stabilized location. + * + * This moves `supports.color.__experimentalDuotone` to `supports.filter.duotone`. * * @since 6.3.0 * From 895363ac91dabe17d1b03aafcb15e3e17214e8f4 Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Tue, 27 Jun 2023 11:43:38 -0500 Subject: [PATCH 40/47] Deprecate wp_global_styles_render_svg_filters and wp_get_global_styles_svg_filters --- src/wp-includes/global-styles-and-settings.php | 3 +++ src/wp-includes/script-loader.php | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/wp-includes/global-styles-and-settings.php b/src/wp-includes/global-styles-and-settings.php index a921feee07633..480e876cf235a 100644 --- a/src/wp-includes/global-styles-and-settings.php +++ b/src/wp-includes/global-styles-and-settings.php @@ -292,10 +292,13 @@ function wp_get_global_styles_custom_css() { * Returns a string containing the SVGs to be referenced as filters (duotone). * * @since 5.9.1 + * @deprecated 6.3.0 SVG generation is handled on a per-block basis in block supports. * * @return string */ function wp_get_global_styles_svg_filters() { + _deprecated_function( __FUNCTION__, '6.3.0' ); + /* * Ignore cache when the development mode is set to 'theme', so it doesn't interfere with the theme * developer's workflow. diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index b6414350b74cd..6db1b010a9e40 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -2488,8 +2488,11 @@ function wp_enqueue_global_styles_custom_css() { * in the body to satisfy Safari's rendering quirks. * * @since 5.9.1 + * @deprecated 6.3.0 SVG generation is handled on a per-block basis in block supports. */ function wp_global_styles_render_svg_filters() { + _deprecated_function( __FUNCTION__, '6.3.0' ); + /* * When calling via the in_admin_header action, we only want to render the * SVGs on block editor pages. From 5347e2c604795832f02720dad86bd8c1a7494a02 Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Tue, 27 Jun 2023 11:44:32 -0500 Subject: [PATCH 41/47] Remove tests for deprecated functions --- .../theme/wpGetGlobalStylesSvgFilters.php | 62 ------------------- 1 file changed, 62 deletions(-) delete mode 100644 tests/phpunit/tests/theme/wpGetGlobalStylesSvgFilters.php diff --git a/tests/phpunit/tests/theme/wpGetGlobalStylesSvgFilters.php b/tests/phpunit/tests/theme/wpGetGlobalStylesSvgFilters.php deleted file mode 100644 index bac3375b259bb..0000000000000 --- a/tests/phpunit/tests/theme/wpGetGlobalStylesSvgFilters.php +++ /dev/null @@ -1,62 +0,0 @@ -assertStringContainsString( 'assertStringContainsString( 'assertNotSame( $svg_for_default_theme, $svg_for_block_theme, 'Cache value should have changed' ); - } - - /** - * Tests that the function relies on the development mode for whether to use caching. - * - * @ticket 57487 - * - * @covers ::wp_get_global_styles_svg_filters - */ - public function test_caching_is_used_when_developing_theme() { - global $_wp_tests_development_mode; - - switch_theme( 'block-theme' ); - - // Store SVG in cache. - $svg = ''; - wp_cache_set( 'wp_get_global_styles_svg_filters', $svg, 'theme_json' ); - - // By default, caching should be used, so the above value will be returned. - $_wp_tests_development_mode = ''; - $this->assertSame( $svg, wp_get_global_styles_svg_filters(), 'Caching was not used despite development mode disabled' ); - - // When the development mode is set to 'theme', caching should not be used. - $_wp_tests_development_mode = 'theme'; - $this->assertNotSame( $svg, wp_get_global_styles_svg_filters(), 'Caching was used despite theme development mode' ); - } -} From 1476cffc308ccc27b383340d1ccedf3db1700f78 Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Tue, 27 Jun 2023 11:45:42 -0500 Subject: [PATCH 42/47] Move newly deprecated functions to deprecated.php --- src/wp-includes/deprecated.php | 73 +++++++++++++++++++ .../global-styles-and-settings.php | 42 ----------- src/wp-includes/script-loader.php | 31 -------- 3 files changed, 73 insertions(+), 73 deletions(-) diff --git a/src/wp-includes/deprecated.php b/src/wp-includes/deprecated.php index 60ecd3a02c84e..05630d6f2f9a5 100644 --- a/src/wp-includes/deprecated.php +++ b/src/wp-includes/deprecated.php @@ -5229,3 +5229,76 @@ function wp_render_duotone_support( $block_content, $block ) { _deprecated_function( __FUNCTION__, '6.3.0', 'WP_Duotone::render_duotone_support' ); return WP_Duotone::render_duotone_support( $block_content, $block ); } + +/** + * Returns a string containing the SVGs to be referenced as filters (duotone). + * + * @since 5.9.1 + * @deprecated 6.3.0 SVG generation is handled on a per-block basis in block supports. + * + * @return string + */ +function wp_get_global_styles_svg_filters() { + _deprecated_function( __FUNCTION__, '6.3.0' ); + + /* + * Ignore cache when the development mode is set to 'theme', so it doesn't interfere with the theme + * developer's workflow. + */ + $can_use_cached = wp_get_development_mode() !== 'theme'; + $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::get_merged_data(); + $svgs = $tree->get_svg_filters( $origins ); + + if ( $can_use_cached ) { + wp_cache_set( $cache_key, $svgs, $cache_group ); + } + + return $svgs; +} + +/** + * 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 + * @deprecated 6.3.0 SVG generation is handled on a per-block basis in block supports. + */ +function wp_global_styles_render_svg_filters() { + _deprecated_function( __FUNCTION__, '6.3.0' ); + + /* + * 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 = wp_get_global_styles_svg_filters(); + if ( ! empty( $filters ) ) { + echo $filters; + } +} diff --git a/src/wp-includes/global-styles-and-settings.php b/src/wp-includes/global-styles-and-settings.php index 480e876cf235a..c352f0d7c6a88 100644 --- a/src/wp-includes/global-styles-and-settings.php +++ b/src/wp-includes/global-styles-and-settings.php @@ -288,48 +288,6 @@ function wp_get_global_styles_custom_css() { return $stylesheet; } -/** - * Returns a string containing the SVGs to be referenced as filters (duotone). - * - * @since 5.9.1 - * @deprecated 6.3.0 SVG generation is handled on a per-block basis in block supports. - * - * @return string - */ -function wp_get_global_styles_svg_filters() { - _deprecated_function( __FUNCTION__, '6.3.0' ); - - /* - * Ignore cache when the development mode is set to 'theme', so it doesn't interfere with the theme - * developer's workflow. - */ - $can_use_cached = wp_get_development_mode() !== 'theme'; - $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::get_merged_data(); - $svgs = $tree->get_svg_filters( $origins ); - - if ( $can_use_cached ) { - wp_cache_set( $cache_key, $svgs, $cache_group ); - } - - return $svgs; -} - /** * Adds global style rules to the inline style for each block. * diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index 6db1b010a9e40..3de06605f1977 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -2479,37 +2479,6 @@ function wp_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 - * @deprecated 6.3.0 SVG generation is handled on a per-block basis in block supports. - */ -function wp_global_styles_render_svg_filters() { - _deprecated_function( __FUNCTION__, '6.3.0' ); - - /* - * 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 = wp_get_global_styles_svg_filters(); - if ( ! empty( $filters ) ) { - echo $filters; - } -} - /** * Checks if the editor scripts and styles for all registered block types * should be enqueued on the current screen. From d74a917e22dc878ba10be2924e762fa9a8d469e5 Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Tue, 27 Jun 2023 16:26:57 -0500 Subject: [PATCH 43/47] Add changelog to PRESETS_METADATA --- src/wp-includes/class-wp-theme-json.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 0091496f3013e..75665d271c725 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -114,6 +114,7 @@ class WP_Theme_JSON { * @since 6.0.0 Replaced `override` with `prevent_override` and updated the * `prevent_override` value for `color.duotone` to use `color.defaultDuotone`. * @since 6.2.0 Added 'shadow' presets. + * @since 6.3.0 Replaced value_func for duotone with `null`. Custom properties are handled by class-wp-duotone.php. * @var array */ const PRESETS_METADATA = array( From 710858d48505626dfdad50678181d3ef4e23fd67 Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Tue, 27 Jun 2023 16:30:02 -0500 Subject: [PATCH 44/47] Add @since 6.3.0 to all duotone methods --- src/wp-includes/class-wp-duotone.php | 60 ++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index 241a92d96c824..c75bd1fa286a8 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -50,6 +50,8 @@ class WP_Duotone { * * @internal * + * @since 6.3.0 + * * @var array */ private static $global_styles_block_names = array(); @@ -72,6 +74,8 @@ class WP_Duotone { * * @internal * + * @since 6.3.0 + * * @var array */ private static $global_styles_presets = array(); @@ -91,6 +95,8 @@ class WP_Duotone { * * @internal * + * @since 6.3.0 + * * @var array */ private static $used_global_styles_presets = array(); @@ -114,6 +120,8 @@ class WP_Duotone { * * @internal * + * @since 6.3.0 + * * @var array */ private static $used_svg_filter_data = array(); @@ -134,6 +142,8 @@ class WP_Duotone { * * @internal * + * @since 6.3.0 + * * @var array */ private static $block_css_declarations = array(); @@ -147,6 +157,8 @@ class WP_Duotone { * * @internal * + * @since 6.3.0 + * * @param float $number The number to clamp. * @param float $min The minimum value. * @param float $max The maximum value. @@ -165,6 +177,8 @@ private static function colord_clamp( $number, $min = 0, $max = 1 ) { * * @internal * + * @since 6.3.0 + * * @param float $degrees The hue to clamp. * @return float The clamped hue. */ @@ -182,6 +196,8 @@ private static function colord_clamp_hue( $degrees ) { * * @internal * + * @since 6.3.0 + * * @param float $value The hue value to parse. * @param string $unit The unit of the hue value. * @return float The parsed hue value. @@ -210,6 +226,8 @@ private static function colord_parse_hue( $value, $unit = 'deg' ) { * * @internal * + * @since 6.3.0 + * * @param string $hex The hex string to parse. * @return array|null An array of RGBA values or null if the hex string is invalid. */ @@ -256,6 +274,8 @@ private static function colord_parse_hex( $hex ) { * * @internal * + * @since 6.3.0 + * * @param array $rgba The RGBA array to clamp. * @return array The clamped RGBA array. */ @@ -277,6 +297,8 @@ private static function colord_clamp_rgba( $rgba ) { * * @internal * + * @since 6.3.0 + * * @param string $input The RGBA string to parse. * @return array|null An array of RGBA values or null if the RGB string is invalid. */ @@ -334,6 +356,8 @@ private static function colord_parse_rgba_string( $input ) { * * @internal * + * @since 6.3.0 + * * @param array $hsla The HSLA array to clamp. * @return array The clamped HSLA array. */ @@ -355,6 +379,8 @@ private static function colord_clamp_hsla( $hsla ) { * * @internal * + * @since 6.3.0 + * * @param array $hsva The HSVA array to convert. * @return array The RGBA array. */ @@ -387,6 +413,8 @@ private static function colord_hsva_to_rgba( $hsva ) { * * @internal * + * @since 6.3.0 + * * @param array $hsla The HSLA array to convert. * @return array The HSVA array. */ @@ -415,6 +443,8 @@ private static function colord_hsla_to_hsva( $hsla ) { * * @internal * + * @since 6.3.0 + * * @param array $hsla The HSLA array to convert. * @return array The RGBA array. */ @@ -431,6 +461,8 @@ private static function colord_hsla_to_rgba( $hsla ) { * * @internal * + * @since 6.3.0 + * * @param string $input The HSLA string to parse. * @return array|null An array of RGBA values or null if the RGB string is invalid. */ @@ -487,6 +519,8 @@ private static function colord_parse_hsla_string( $input ) { * * @internal * + * @since 6.3.0 + * * @param string $input The string to parse. * @return array|null An array of RGBA values or null if the string is invalid. */ @@ -513,6 +547,8 @@ private static function colord_parse( $input ) { * * @internal * + * @since 6.3.0 + * * @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. */ @@ -530,6 +566,8 @@ private static function get_slug_from_attribute( $duotone_attr ) { * * @internal * + * @since 6.3.0 + * * @param string $duotone_attr The duotone attribute from a block. * @return bool True if the duotone preset present and valid. */ @@ -548,6 +586,8 @@ private static function is_preset( $duotone_attr ) { * * @internal * + * @since 6.3.0 + * * @param string $slug The slug of the duotone preset. * @return string The CSS variable name. */ @@ -563,6 +603,8 @@ private static function get_css_custom_property_name( $slug ) { * * @internal * + * @since 6.3.0 + * * @param string $slug The slug of the duotone preset. * @return string The ID of the duotone filter. */ @@ -578,6 +620,8 @@ private static function get_filter_id( $slug ) { * * @internal * + * @since 6.3.0 + * * @param string $slug The slug of the duotone preset. * @return string The CSS variable. */ @@ -594,6 +638,8 @@ private static function get_css_var( $slug ) { * * @internal * + * @since 6.3.0 + * * @param string $filter_id The ID of the filter. * @return string The URL for the duotone filter. */ @@ -608,6 +654,8 @@ private static function get_filter_url( $filter_id ) { * * @internal * + * @since 6.3.0 + * * @param string $filter_id The ID of the filter. * @param array $colors An array of color strings. * @return string An SVG with a duotone filter definition. @@ -739,6 +787,8 @@ public static function get_filter_svg_from_preset( $preset ) { * * @internal * + * @since 6.3.0 + * * @param array $sources The duotone presets. * @return string The SVGs for the duotone filters. */ @@ -759,6 +809,8 @@ private static function get_svg_definitions( $sources ) { * * @internal * + * @since 6.3.0 + * * @param array $sources The duotone presets. * @return string The CSS for global styles. */ @@ -782,6 +834,8 @@ private static function get_global_styles_presets( $sources ) { * * @internal * + * @since 6.3.0 + * * @param string $filter_id The filter ID. e.g. 'wp-duotone-000000-ffffff-2'. * @param string $duotone_selector The block's duotone selector. e.g. '.wp-block-image img'. * @param string $filter_value The filter CSS value. e.g. 'url(#wp-duotone-000000-ffffff-2)' or 'unset'. @@ -817,6 +871,8 @@ private static function enqueue_block_css( $filter_id, $duotone_selector, $filte * * @internal * + * @since 6.3.0 + * * @param string $filter_id The filter ID. e.g. 'wp-duotone-000000-ffffff-2'. * @param string $duotone_selector The block's duotone selector. e.g. '.wp-block-image img'. * @param string $filter_value The filter CSS value. e.g. 'url(#wp-duotone-000000-ffffff-2)' or 'unset'. @@ -834,6 +890,8 @@ private static function enqueue_custom_filter( $filter_id, $duotone_selector, $f * * @internal * + * @since 6.3.0 + * * @param string $filter_id The filter ID. e.g. 'wp-duotone-blue-orange'. * @param string $duotone_selector The block's duotone selector. e.g. '.wp-block-image img'. * @param string $filter_value The filter CSS value. e.g. 'url(#wp-duotone-blue-orange)' or 'unset'. @@ -894,6 +952,8 @@ public static function register_duotone_support( $block_type ) { * * @internal * + * @since 6.3.0 + * * @return string The CSS selector or null if there is no support. */ private static function get_selector( $block_name ) { From a114db17ba4a0957dd876d0da324107d69435183 Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Tue, 27 Jun 2023 16:45:59 -0500 Subject: [PATCH 45/47] Mark class WP_Duotone as @access private --- src/wp-includes/class-wp-duotone.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index c75bd1fa286a8..99da521f06619 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -35,7 +35,7 @@ /** * Manages duotone block supports and global styles. * - * @access public + * @access private */ class WP_Duotone { /** From 105bd9ef20cbf82662ab2e7de8a3596132d72968 Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Wed, 28 Jun 2023 17:57:14 +1000 Subject: [PATCH 46/47] Fix theme json test string --- tests/phpunit/tests/theme/wpThemeJson.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/phpunit/tests/theme/wpThemeJson.php b/tests/phpunit/tests/theme/wpThemeJson.php index c2be6b54be416..60a2ab9d028d6 100644 --- a/tests/phpunit/tests/theme/wpThemeJson.php +++ b/tests/phpunit/tests/theme/wpThemeJson.php @@ -636,7 +636,7 @@ public function test_get_stylesheet() { ) ); - $variables = "body{--wp--preset--color--grey: grey;--wp--preset--gradient--custom-gradient: linear-gradient(135deg,rgba(0,0,0) 0%,rgb(0,0,0) 100%);--wp--preset--duotone--custom-duotone: url('#wp-duotone-custom-duotone');--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}.wp-block-group{--wp--custom--base-font: 16;--wp--custom--line-height--small: 1.2;--wp--custom--line-height--medium: 1.4;--wp--custom--line-height--large: 1.8;}"; + $variables = "body{--wp--preset--color--grey: grey;--wp--preset--gradient--custom-gradient: linear-gradient(135deg,rgba(0,0,0) 0%,rgb(0,0,0) 100%);--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}.wp-block-group{--wp--custom--base-font: 16;--wp--custom--line-height--small: 1.2;--wp--custom--line-height--medium: 1.4;--wp--custom--line-height--large: 1.8;}"; $styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}body{color: var(--wp--preset--color--grey);}a:where(:not(.wp-element-button)){background-color: #333;color: #111;}.wp-element-button, .wp-block-button__link{box-shadow: 10px 10px 5px 0px rgba(0,0,0,0.66);}.wp-block-group{background: var(--wp--preset--gradient--custom-gradient);border-radius: 10px;padding: 24px;}.wp-block-group a:where(:not(.wp-element-button)){color: #111;}.wp-block-heading{color: #123456;}.wp-block-heading a:where(:not(.wp-element-button)){background-color: #333;color: #111;font-size: 60px;}.wp-block-post-date{color: #123456;}.wp-block-post-date a:where(:not(.wp-element-button)){background-color: #777;color: #555;}.wp-block-post-excerpt{column-count: 2;}.wp-block-image{margin-bottom: 30px;}.wp-block-image img, .wp-block-image .wp-block-image__crop-area, .wp-block-image .components-placeholder{border-top-left-radius: 10px;border-bottom-right-radius: 1em;}.wp-block-image img, .wp-block-image .components-placeholder{filter: var(--wp--preset--duotone--custom-duotone);}'; $presets = '.has-grey-color{color: var(--wp--preset--color--grey) !important;}.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}.has-custom-gradient-gradient-background{background: var(--wp--preset--gradient--custom-gradient) !important;}.has-small-font-family{font-family: var(--wp--preset--font-family--small) !important;}.has-big-font-family{font-family: var(--wp--preset--font-family--big) !important;}'; $all = $variables . $styles . $presets; From 2541786e2e5736d9d41b5d2370f2a2c097e47306 Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Wed, 28 Jun 2023 18:00:43 +1000 Subject: [PATCH 47/47] Fix lint error --- tests/phpunit/tests/theme/wpThemeJson.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/phpunit/tests/theme/wpThemeJson.php b/tests/phpunit/tests/theme/wpThemeJson.php index 60a2ab9d028d6..3388272a0b8e6 100644 --- a/tests/phpunit/tests/theme/wpThemeJson.php +++ b/tests/phpunit/tests/theme/wpThemeJson.php @@ -636,7 +636,7 @@ public function test_get_stylesheet() { ) ); - $variables = "body{--wp--preset--color--grey: grey;--wp--preset--gradient--custom-gradient: linear-gradient(135deg,rgba(0,0,0) 0%,rgb(0,0,0) 100%);--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}.wp-block-group{--wp--custom--base-font: 16;--wp--custom--line-height--small: 1.2;--wp--custom--line-height--medium: 1.4;--wp--custom--line-height--large: 1.8;}"; + $variables = 'body{--wp--preset--color--grey: grey;--wp--preset--gradient--custom-gradient: linear-gradient(135deg,rgba(0,0,0) 0%,rgb(0,0,0) 100%);--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}.wp-block-group{--wp--custom--base-font: 16;--wp--custom--line-height--small: 1.2;--wp--custom--line-height--medium: 1.4;--wp--custom--line-height--large: 1.8;}'; $styles = 'body { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}body{color: var(--wp--preset--color--grey);}a:where(:not(.wp-element-button)){background-color: #333;color: #111;}.wp-element-button, .wp-block-button__link{box-shadow: 10px 10px 5px 0px rgba(0,0,0,0.66);}.wp-block-group{background: var(--wp--preset--gradient--custom-gradient);border-radius: 10px;padding: 24px;}.wp-block-group a:where(:not(.wp-element-button)){color: #111;}.wp-block-heading{color: #123456;}.wp-block-heading a:where(:not(.wp-element-button)){background-color: #333;color: #111;font-size: 60px;}.wp-block-post-date{color: #123456;}.wp-block-post-date a:where(:not(.wp-element-button)){background-color: #777;color: #555;}.wp-block-post-excerpt{column-count: 2;}.wp-block-image{margin-bottom: 30px;}.wp-block-image img, .wp-block-image .wp-block-image__crop-area, .wp-block-image .components-placeholder{border-top-left-radius: 10px;border-bottom-right-radius: 1em;}.wp-block-image img, .wp-block-image .components-placeholder{filter: var(--wp--preset--duotone--custom-duotone);}'; $presets = '.has-grey-color{color: var(--wp--preset--color--grey) !important;}.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}.has-custom-gradient-gradient-background{background: var(--wp--preset--gradient--custom-gradient) !important;}.has-small-font-family{font-family: var(--wp--preset--font-family--small) !important;}.has-big-font-family{font-family: var(--wp--preset--font-family--big) !important;}'; $all = $variables . $styles . $presets;