Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Duotone: Limit SVG filter output to used filters #48995

Merged
merged 24 commits into from
Mar 15, 2023

Conversation

jeryj
Copy link
Contributor

@jeryj jeryj commented Mar 10, 2023

Rework of #48374
Fixes #38299.

What?

This PR only adds the needed duotone code to the frontend output if that duotone definition is being used.

Why?

There are currently eight globally defined duotone styles, and all of their CSS and SVG definitions are output on the frontend of a WordPress website, even if no images are using the duotone filters. The base raw HTML from TT3 on the Sherbert theme variation results in a 76.4kb request. Without any SVG or duotone-related code, the same page HTML is 67.4kb, which means there is up to 9kb of unnecessary duotone-related HTML on every request.

raw html view of unnecessary SVG code in html

How?

There's quite a bit of changes required to make this happen. We've gone with a route that adds a new WP_Duotone class that handles what filters need to be added to the page based on what duotone filters, if any, are in use. Here's a general overview of the high-level changes being made, and why:

1. Remove all duotone output from global styles

These are handled by removing the actions related to SVG filters:

remove_action( 'wp_body_open', 'wp_global_styles_render_svg_filters' );
remove_action( 'in_admin_header', 'wp_global_styles_render_svg_filters' );

2. Register all duotone filters from global styles and store in the WP_Duotone class

WP_Duotone::$global_styles_presets is an array that scrapes all of the global styles duotone filters. These could be defined from theme.json globally, per theme, or in custom global styles. We need to do this to have quick access to the duotone filter definitions if we come across a block that needs to access these styles.

3. Register all block-level duotone filters from global styles and store in the WP_Duotone class

WP_Duotone::$global_styles_block_names is an array that scrapes all of the blocks that use a duotone filter from global styles, and stores the slug of the duotone filter it uses, such as default-filter, blue-orange, etc. We need to do this in order to decide if a block being rendered has a duotone filter we need to apply to it.

4. Process all blocks to determine the correct duotone output needed

This is the same as before, but we're only outputting the duotone code if needed. On the 'render_block' filter, we process every block and determine:

  • Is there a duotone filter we need to apply on this block
  • If not, return early
  • If we do, decide which duotone filter we need and how to build it
  • Add the duotone info we need to WP_Duotone::$output

5. Output the CSS

On the 'wp_enqueue_scripts' action, output all the necessary CSS for duotone filters collected from WP_Duotone::$output`.

6. Output the SVG

On the 'wp_footer' action, output all necessary SVG for duotone filters from WP_Duotone::$output`.

Testing Instructions

These are the different types of Duotone that need testing:

  1. Set the duotone in Global Styles to all blocks of a certain type.
  2. Set the duotone on a per blocks basis.

For each of these it possible to set the duotone to a preset value, a custom value, or unset.
For presets, it is possible to set them using two different formats: var:preset|duotone|blue-orange or var(--wp--preset--duotone--blue-orange).

It is also important to test that only the SVG filters and CSS that is needed on the page is output - rather than outputting all the presets even if they aren't used.

To test an individual block:

  1. Add an image to a post
  2. Click on the "filter" option in the block toolbar
  3. Select a Duotone option
  4. Save the post
  5. Open the post in the frontend and check that the correct Duotone filter has been applied

To test Global Styles

  1. Open the Global Styles interface in the Site Editor
  2. Open "Blocks"
  3. Find the image block
  4. Click on "filter"
  5. Select a Duotone filter
  6. Save the Global Styles settings
  7. Open the site in the frontend and check that all image blocks have the filter applied (unless they specify their own filters)

Testing Instructions for Keyboard

Screenshots or screencast

@jeryj jeryj self-assigned this Mar 10, 2023
@github-actions
Copy link

github-actions bot commented Mar 10, 2023

Flaky tests detected in f5499b4.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/4420262538
📝 Reported issues:

Refactored out duotone specific code from theme json gutenberg globla styles. Switched theme_json_register_declarations from action to filter.
Doesn't seem like a legitimately useful filter at the moment. Only for us to be able to use global styles in our duotone-specific output.
We were already getting the presets via the global settings, so the filter was unnecessary.
The filter isn't necesary for us to access what we need. I've removed the refactor as it would be a larger change that can be done in a different PR if needed.
@@ -144,7 +144,7 @@ class WP_Theme_JSON_Gutenberg {
'path' => array( 'color', 'duotone' ),
'prevent_override' => array( 'color', 'defaultDuotone' ),
'use_default_names' => false,
'value_func' => 'gutenberg_get_duotone_filter_property',
'value_func' => null, // Don't output CSS Custom Properties for duotone.
'css_vars' => '--wp--preset--duotone--$slug',
'classes' => array(),
'properties' => array( 'filter' ),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure the entire duotone section of PRESETS_METADATA can be removed since generating the preset is done by duotone.php now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, it looks like the constructor still uses it for keying presets by origin which we need later. That being said, I still think we can remove the css_vars key and have that solely defined in duotone.php as part of the cleanup.

Also, I noticed that the theme.json styles.blocks['core/block'].filter.duotone filters are being applied on the frontend, but not the editor, so there are also likely changes that need to be done in the block-editor duotone.js hook and use-global-styles-output.js as well.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The properties key is also probably redundant now since we're no longer generating properties here.

return array(
'pipe-slug' => array( 'var:preset|duotone|blue-orange', 'blue-orange' ),
'css-var' => array( 'var(--wp--preset--duotone--blue-orange)', 'blue-orange' ),
'css-var-weird-chars' => array( 'var(--wp--preset--duotone--.)', '.' ),
Copy link
Contributor

@ajlende ajlende Mar 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

. isn't a valid identifier token according to the CSS spec.

CSS custom properties always take the first -- branch of this railroad diagram and then allow for [a-zA-Z0-9_-] and a set of non-ascii code points.

ident-token railroad diagram

It looks like slugs in WordPress are handled by sanitize_title_with_dashes() according to this Stack Exchange answer.

So I would be inclined to further restrict the non-ascii section to characters that get output from that function as well.

And I think somewhere in the global styles code, we also restrict slugs to not contain consecutive hyphens (--) since those would get converted to pipes (|) in the var: syntax.

For some reason, the render_block filter runs even on blocks that are not included on the page. So, if you have a duotone filter defined in your theme.json, such as for the core/post-featured-image block, it will run the block filter even if no featured image is set. As a result, the duotonen defined in theme.json per block would get output even if that block wasn't in use. The only reliable check I could find to determine if the block was in use or not was to check the block content. By bailing early if no block content, we avoid adding unused SVG to the output.
@scruffian scruffian marked this pull request as ready for review March 15, 2023 10:39
@scruffian scruffian changed the title WIP: Update/svg filter frontend output Duotone: Limit SVG filter output to used filters Mar 15, 2023
@scruffian scruffian added the [Feature] Site Editor Related to the overarching Site Editor (formerly "full site editing") label Mar 15, 2023
Copy link
Contributor

@scruffian scruffian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is looking great, and in my testing its working well.

IMO we should merge this and deal with any more improvements in followups, as this PR is already very large.

@jeryj jeryj merged commit 0bb7a9c into trunk Mar 15, 2023
@jeryj jeryj deleted the update/svg-filter-frontend-output branch March 15, 2023 14:25
@github-actions github-actions bot added this to the Gutenberg 15.4 milestone Mar 15, 2023
ajlende added a commit that referenced this pull request Mar 15, 2023
*
* @access public
*/
class WP_Duotone {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did we figure out if files in the lib folder get the _Gutenberg suffix. If not, this should have that suffix because we want to be able to make changes in Gutenberg without affecting core by referencing the _Gutenberg version.

Comment on lines +3493 to +3496
public static function get_preset_css_var( $path, $slug ) {
$duotone_preset_metadata = static::get_preset_metadata_from_path( $path );
return static::replace_slug_in_string( $duotone_preset_metadata['css_vars'], $slug );
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can get this working without adding this to the public API. The only place the css_vars for frontend duotone is being used is within the block supports now, and we already have it hardcoded a couple times there.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That'd be lovely. For the record, I saw that this PR was reverted at #49102

Copy link
Contributor Author

@jeryj jeryj Mar 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This version of the PR did get reverted, and then was cleaned up and merged in this PR: #49103

We were able to get the PR merged without adding anything to lib/class-wp-theme-json-gutenberg.php

@jeryj jeryj restored the update/svg-filter-frontend-output branch March 15, 2023 16:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Site Editor Related to the overarching Site Editor (formerly "full site editing")
Projects
None yet
Development

Successfully merging this pull request may close these issues.

WP 5.9 adds default Duotones before closing the body
4 participants