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 #49103

Merged
merged 55 commits into from
Mar 17, 2023

Conversation

jeryj
Copy link
Contributor

@jeryj jeryj commented Mar 15, 2023

Rework of #48374
Fixes #38299.
Original PR that was reverted: #48995

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 and others added 25 commits March 7, 2023 15:13
This doesn't do anything at the moment. On block render, it checks if the block has duotone filters set via theme.json/global styles/custom styles and returns early if not.
Co-authored-by: scruffian <ben@escruffian.com>
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.
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.
There was some duotone specific code within the theme json class that was only used to build a css declaration for duotone css output. It is now handled manually for speed and simplicity.
@github-actions
Copy link

github-actions bot commented Mar 15, 2023

Flaky tests detected in 1457d58.
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/4449389586
📝 Reported issues:

…_var to be more accurately named

Also used these functions throughout duotone.php to refactor for simplicity/consistency. Renamed some declaration variables as well to be more accurately named.
Comment on lines 602 to 617
/**
* Safari renders elements incorrectly on first paint when the SVG filter comes after the content that it is filtering,
* so we force a repaint with a WebKit hack which solves the issue.
*
* @param string $selector The selector to apply the hack for.
*/
function duotone_safari_rerender_hack( $selector ) {
/*
* Simply accessing el.offsetHeight flushes layout and style
* changes in WebKit without having to wait for setTimeout.
*/
printf(
'<script>( function() { var el = document.querySelector( %s ); var display = el.style.display; el.style.display = "none"; el.offsetHeight; el.style.display = display; } )();</script>',
wp_json_encode( $selector )
);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This needs to move into WP_Duotone_Gutenberg.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As a follow-up, I think it'd be good to run this all at once by passing everything from WP_Duotone_Gutenberg::$output and having one <script> tag that handles rerendering all of them.

It isn't supported in PHP 7.0
@ajlende ajlende enabled auto-merge (squash) March 17, 2023 16:11
*/
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();
Copy link
Member

Choose a reason for hiding this comment

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

@jeryj @ajlende @aaronrobertshaw @andrewserong We need to use the class bundled by Gutenberg instead of the core class. Fix for this at #49199

Copy link
Contributor

Choose a reason for hiding this comment

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

Good catch! Thanks for getting that fix out!

Copy link
Contributor

@aaronrobertshaw aaronrobertshaw Mar 24, 2023

Choose a reason for hiding this comment

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

@oandregal @ajlende @jeryj it appears that the fix in #49199 surfaced an issue with the duotone action added in this PR, that causes theme.json block node data to be cached too soon preventing the editor-only styles introduced by #46496.

While debugging on trunk, I found that global styles duotone filters aren't being applied in either the post editor (#49239) or the frontend. With regards to #49239, that branch works until you rebase it on trunk where it then fails again to apply the duotone filter.

Update: Found that the image/block.json file needs the filters.duotone in the selectors now for the global styles and probably some other tweaks to allow moving away from support.color.__experimentalDutone.

I wasn't able to find another way to detect we're in the editor for editor-only selectors than via get_current_screen and the duotone action here appears to be getting the block node data before that function exists.

I'll create an issue for this but also wanted to flag it within the context of this PR.

Edit: New issue - #49324

@ramonjd ramonjd added the Needs PHP backport Needs PHP backport to Core label Jun 5, 2023
@ramonjd ramonjd removed the Needs PHP backport Needs PHP backport to Core label Jun 30, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Global Styles Anything related to the broader Global Styles efforts, including Styles Engine and theme.json
Projects
None yet
Development

Successfully merging this pull request may close these issues.

WP 5.9 adds default Duotones before closing the body
6 participants