diff --git a/src/wp-includes/block-supports/duotone.php b/src/wp-includes/block-supports/duotone.php index d2b0df4496572..5a3bfd568fd5e 100644 --- a/src/wp-includes/block-supports/duotone.php +++ b/src/wp-includes/block-supports/duotone.php @@ -591,21 +591,3 @@ static function () use ( $filter_svg, $selector ) { ) ); add_filter( 'render_block', 'wp_render_duotone_support', 10, 2 ); - -/** - * Render the SVG filters supplied by theme.json. - * - * Note that this doesn't render the per-block user-defined - * filters which are handled by wp_render_duotone_support, - * but it should be rendered in the same location as those to satisfy - * Safari's rendering quirks. - * - * @since 5.9.0 - */ -function wp_global_styles_render_svg_filters() { - $filters = wp_get_global_styles_svg_filters(); - if ( ! empty( $filters ) ) { - echo $filters; - } -} -add_action( 'wp_body_open', 'wp_global_styles_render_svg_filters' ); diff --git a/src/wp-includes/class-wp-theme-json-resolver.php b/src/wp-includes/class-wp-theme-json-resolver.php index b9a3819d403a7..bf9add2ee9c15 100644 --- a/src/wp-includes/class-wp-theme-json-resolver.php +++ b/src/wp-includes/class-wp-theme-json-resolver.php @@ -208,6 +208,8 @@ public static function get_theme_data( $deprecated = array() ) { $default_gradients = true; } $theme_support_data['settings']['color']['defaultGradients'] = $default_gradients; + + $theme_support_data['settings']['color']['defaultDuotone'] = false; } $with_theme_supports = new WP_Theme_JSON( $theme_support_data ); $with_theme_supports->merge( self::$theme ); diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 9ed88ddf22854..6a4214be8d061 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -74,31 +74,38 @@ class WP_Theme_JSON { * * This contains the necessary metadata to process them: * - * - path => where to find the preset within the settings section - * - override => whether a theme preset with the same slug as a default preset - * can override it - * - use_default_names => whether to use the default names - * - value_key => the key that represents the value - * - value_func => optionally, instead of value_key, a function to generate - * the value that takes a preset as an argument - * (either value_key or value_func should be present) - * - css_vars => template string to use in generating the CSS Custom Property. - * Example output: "--wp--preset--duotone--blue: " will generate - * as many CSS Custom Properties as presets defined - * substituting the $slug for the slug's value for each preset value. - * - classes => array containing a structure with the classes to - * generate for the presets, where for each array item - * the key is the class name and the value the property name. - * The "$slug" substring will be replaced by the slug of each preset. - * For example: - * 'classes' => array( - * '.has-$slug-color' => 'color', - * '.has-$slug-background-color' => 'background-color', - * '.has-$slug-border-color' => 'border-color', - * ) - * - properties => array of CSS properties to be used by kses to - * validate the content of each preset - * by means of the remove_insecure_properties method. + * - path => Where to find the preset within the settings section. + * - prevent_override => Whether a theme preset with the same slug as a default preset + * should not override it or the path to a setting for the same + * When defaults. + * The relationship between whether to override the defaults + * and whether the defaults are enabled is inverse: + * - If defaults are enabled => theme presets should not be overriden + * - If defaults are disabled => theme presets should be overriden + * For example, a theme sets defaultPalette to false, + * making the default palette hidden from the user. + * In that case, we want all the theme presets to be present, + * so they should override the defaults by setting this false. + * - value_key => the key that represents the value + * - value_func => optionally, instead of value_key, a function to generate + * the value that takes a preset as an argument + * (either value_key or value_func should be present) + * - css_vars => template string to use in generating the CSS Custom Property. + * Example output: "--wp--preset--duotone--blue: " will generate as many CSS Custom Properties as presets defined + * substituting the $slug for the slug's value for each preset value. + * - classes => array containing a structure with the classes to + * generate for the presets, where for each array item + * the key is the class name and the value the property name. + * The "$slug" substring will be replaced by the slug of each preset. + * For example: + * 'classes' => array( + * '.has-$slug-color' => 'color', + * '.has-$slug-background-color' => 'background-color', + * '.has-$slug-border-color' => 'border-color', + * ) + * - properties => array of CSS properties to be used by kses to + * validate the content of each preset + * by means of the remove_insecure_properties method. * * @since 5.8.0 * @since 5.9.0 Added the `color.duotone` and `typography.fontFamilies` presets, @@ -107,53 +114,58 @@ class WP_Theme_JSON { */ const PRESETS_METADATA = array( array( - 'path' => array( 'color', 'palette' ), - 'override' => array( 'color', 'defaultPalette' ), - 'use_default_names' => false, - 'value_key' => 'color', - 'css_vars' => '--wp--preset--color--$slug', - 'classes' => array( + 'path' => array( 'color', 'palette' ), + 'prevent_override' => array( 'color', 'defaultPalette' ), + 'use_default_presets' => array( 'color', 'defaultPalette' ), + 'use_default_names' => false, + 'value_key' => 'color', + 'css_vars' => '--wp--preset--color--$slug', + 'classes' => array( '.has-$slug-color' => 'color', '.has-$slug-background-color' => 'background-color', '.has-$slug-border-color' => 'border-color', ), - 'properties' => array( 'color', 'background-color', 'border-color' ), + 'properties' => array( 'color', 'background-color', 'border-color' ), ), array( - 'path' => array( 'color', 'gradients' ), - 'override' => array( 'color', 'defaultGradients' ), - 'use_default_names' => false, - 'value_key' => 'gradient', - 'css_vars' => '--wp--preset--gradient--$slug', - 'classes' => array( '.has-$slug-gradient-background' => 'background' ), - 'properties' => array( 'background' ), + 'path' => array( 'color', 'gradients' ), + 'prevent_override' => array( 'color', 'defaultGradients' ), + 'use_default_presets' => array( 'color', 'defaultGradients' ), + 'use_default_names' => false, + 'value_key' => 'gradient', + 'css_vars' => '--wp--preset--gradient--$slug', + 'classes' => array( '.has-$slug-gradient-background' => 'background' ), + 'properties' => array( 'background' ), ), array( - 'path' => array( 'color', 'duotone' ), - 'override' => true, - 'use_default_names' => false, - 'value_func' => 'wp_get_duotone_filter_property', - 'css_vars' => '--wp--preset--duotone--$slug', - 'classes' => array(), - 'properties' => array( 'filter' ), + 'path' => array( 'color', 'duotone' ), + 'prevent_override' => array( 'color', 'defaultDuotone' ), + 'use_default_presets' => array( 'color', 'defaultDuotone' ), + 'use_default_names' => false, + 'value_func' => 'gutenberg_get_duotone_filter_property', + 'css_vars' => '--wp--preset--duotone--$slug', + 'classes' => array(), + 'properties' => array( 'filter' ), ), array( - 'path' => array( 'typography', 'fontSizes' ), - 'override' => true, - 'use_default_names' => true, - 'value_key' => 'size', - 'css_vars' => '--wp--preset--font-size--$slug', - 'classes' => array( '.has-$slug-font-size' => 'font-size' ), - 'properties' => array( 'font-size' ), + 'path' => array( 'typography', 'fontSizes' ), + 'prevent_override' => false, + 'use_default_presets' => true, + 'use_default_names' => true, + 'value_key' => 'size', + 'css_vars' => '--wp--preset--font-size--$slug', + 'classes' => array( '.has-$slug-font-size' => 'font-size' ), + 'properties' => array( 'font-size' ), ), array( - 'path' => array( 'typography', 'fontFamilies' ), - 'override' => true, - 'use_default_names' => false, - 'value_key' => 'fontFamily', - 'css_vars' => '--wp--preset--font-family--$slug', - 'classes' => array( '.has-$slug-font-family' => 'font-family' ), - 'properties' => array( 'font-family' ), + 'path' => array( 'typography', 'fontFamilies' ), + 'prevent_override' => false, + 'use_default_presets' => true, + 'use_default_names' => false, + 'value_key' => 'fontFamily', + 'css_vars' => '--wp--preset--font-family--$slug', + 'classes' => array( '.has-$slug-font-family' => 'font-family' ), + 'properties' => array( 'font-family' ), ), ); @@ -257,6 +269,7 @@ class WP_Theme_JSON { 'custom' => null, 'customDuotone' => null, 'customGradient' => null, + 'defaultDuotone' => null, 'defaultGradients' => null, 'defaultPalette' => null, 'duotone' => null, @@ -1079,9 +1092,14 @@ private static function scope_selector( $scope, $selector ) { private static function get_settings_values_by_slug( $settings, $preset_metadata, $origins ) { $preset_per_origin = _wp_array_get( $settings, $preset_metadata['path'], array() ); + $skip_default_presets = ! self::get_metadata_boolean( $settings, $preset_metadata['use_default_presets'], true ); + $result = array(); foreach ( $origins as $origin ) { - if ( ! isset( $preset_per_origin[ $origin ] ) ) { + if ( + ! isset( $preset_per_origin[ $origin ] ) || + ( 'default' === $origin && $skip_default_presets ) + ) { continue; } foreach ( $preset_per_origin[ $origin ] as $preset ) { @@ -1121,9 +1139,14 @@ private static function get_settings_values_by_slug( $settings, $preset_metadata private static function get_settings_slugs( $settings, $preset_metadata, $origins = self::VALID_ORIGINS ) { $preset_per_origin = _wp_array_get( $settings, $preset_metadata['path'], array() ); + $skip_default_presets = ! self::get_metadata_boolean( $settings, $preset_metadata['use_default_presets'], true ); + $result = array(); foreach ( $origins as $origin ) { - if ( ! isset( $preset_per_origin[ $origin ] ) ) { + if ( + ! isset( $preset_per_origin[ $origin ] ) || + ( 'default' === $origin && $skip_default_presets ) + ) { continue; } foreach ( $preset_per_origin[ $origin ] as $preset ) { @@ -1538,7 +1561,7 @@ public function merge( $incoming ) { // Replace the presets. foreach ( self::PRESETS_METADATA as $preset ) { - $override_preset = self::should_override_preset( $this->theme_json, $node['path'], $preset['override'] ); + $override_preset = ! self::get_metadata_boolean( $this->theme_json['settings'], $preset['prevent_override'], true ); foreach ( self::VALID_ORIGINS as $origin ) { $base_path = array_merge( $node['path'], $preset['path'] ); @@ -1596,7 +1619,10 @@ public function get_svg_filters( $origins ) { $filters = ''; foreach ( $origins as $origin ) { - if ( ! isset( $duotone_presets[ $origin ] ) ) { + if ( + ! isset( $duotone_presets[ $origin ] ) || + ( 'default' === $origin && false === $node['color']['defaultDuotone'] ) + ) { continue; } foreach ( $duotone_presets[ $origin ] as $duotone_preset ) { @@ -1609,46 +1635,42 @@ public function get_svg_filters( $origins ) { } /** - * Returns whether a presets should be overridden or not. + * For metadata values that can either be booleans or paths to booleans, gets the value. * - * @since 5.9.0 + * ```php + * $data = array( + * 'color' => array( + * 'defaultPalette' => true + * ) + * ); + * + * self::get_metadata_boolean( $data, false ); + * // => false * - * @param array $theme_json The theme.json like structure to inspect. - * @param array $path Path to inspect. - * @param bool|array $override Data to compute whether to override the preset. + * self::get_metadata_boolean( $data, array( 'color', 'defaultPalette' ) ); + * // => true + * ``` + * + * @since 5.9.0 + * + * @param array $data The data to inspect. + * @param bool|array $path Boolean or path to a boolean. + * @param bool $default Default value if the referenced path is missing. * @return boolean */ - private static function should_override_preset( $theme_json, $path, $override ) { - if ( is_bool( $override ) ) { - return $override; + private static function get_metadata_boolean( $data, $path, $default = false ) { + if ( is_bool( $path ) ) { + return $path; } - /* - * The relationship between whether to override the defaults - * and whether the defaults are enabled is inverse: - * - * - If defaults are enabled => theme presets should not be overridden - * - If defaults are disabled => theme presets should be overridden - * - * For example, a theme sets defaultPalette to false, - * making the default palette hidden from the user. - * In that case, we want all the theme presets to be present, - * so they should override the defaults. - */ - if ( is_array( $override ) ) { - $value = _wp_array_get( $theme_json, array_merge( $path, $override ) ); - if ( isset( $value ) ) { - return ! $value; - } - - // Search the top-level key if none was found for this node. - $value = _wp_array_get( $theme_json, array_merge( array( 'settings' ), $override ) ); + if ( is_array( $path ) ) { + $value = _wp_array_get( $data, $path ); if ( isset( $value ) ) { - return ! $value; + return $value; } - - return true; } + + return $default; } /** diff --git a/src/wp-includes/default-filters.php b/src/wp-includes/default-filters.php index 20559dd179f9b..182f94eddf5ed 100644 --- a/src/wp-includes/default-filters.php +++ b/src/wp-includes/default-filters.php @@ -574,6 +574,10 @@ add_action( 'wp_enqueue_scripts', 'wp_enqueue_global_styles' ); add_action( 'wp_footer', 'wp_enqueue_global_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-includes/script-loader.php b/src/wp-includes/script-loader.php index a18cc78e2c7c7..11d9c18b085a3 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -2336,6 +2336,35 @@ function wp_enqueue_global_styles() { wp_enqueue_style( 'global-styles' ); } +/** + * Render the SVG filters supplied by theme.json. + * + * Note that this doesn't render the per-block user-defined + * filters which are handled by wp_render_duotone_support, + * but it should be rendered before the filtered content + * in the body to satisfy Safari's rendering quirks. + * + * @since 5.9.0 + */ +function wp_global_styles_render_svg_filters() { + /* + * When calling via the in_admin_header action, we only want to render the + * SVGs on block editor pages. + */ + global $pagenow; + 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. diff --git a/src/wp-includes/theme.json b/src/wp-includes/theme.json index 5c1404ccddb51..5ba62ed33be2e 100644 --- a/src/wp-includes/theme.json +++ b/src/wp-includes/theme.json @@ -13,46 +13,47 @@ "custom": true, "customDuotone": true, "customGradient": true, + "defaultDuotone": true, "defaultGradients": true, "defaultPalette": true, "duotone": [ { - "name": "Dark grayscale" , + "name": "Dark grayscale" , "colors": [ "#000000", "#7f7f7f" ], "slug": "dark-grayscale" }, { - "name": "Grayscale" , + "name": "Grayscale" , "colors": [ "#000000", "#ffffff" ], "slug": "grayscale" }, { - "name": "Purple and yellow" , + "name": "Purple and yellow" , "colors": [ "#8c00b7", "#fcff41" ], "slug": "purple-yellow" }, { - "name": "Blue and red" , + "name": "Blue and red" , "colors": [ "#000097", "#ff4747" ], "slug": "blue-red" }, { - "name": "Midnight" , + "name": "Midnight" , "colors": [ "#000000", "#00a5ff" ], "slug": "midnight" }, { - "name": "Magenta and yellow" , + "name": "Magenta and yellow" , "colors": [ "#c7005a", "#fff278" ], "slug": "magenta-yellow" }, { - "name": "Purple and green" , + "name": "Purple and green" , "colors": [ "#a60072", "#67ff66" ], "slug": "purple-green" }, { - "name": "Blue and orange" , + "name": "Blue and orange" , "colors": [ "#1900d8", "#ffa96b" ], "slug": "blue-orange" }