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

Webfonts API: Output only used fonts #39099

Closed
wants to merge 9 commits into from
Closed

Conversation

zaguiini
Copy link
Member

@zaguiini zaguiini commented Feb 25, 2022

What

In #37140, we finally introduced the Webfonts API. The initial implementation has a pitfall: it includes every registered font, even if it's not being used, to the output.

This PR addresses exactly that: it introduces a mechanism to remove webfonts that are not used by the providers when emitting inline CSS that's sent to the front-end.

Why

A single @font-face declaration could add up to 2kb to every request. Imagine someone registering 100 fonts to a provider so one single font could be picked up in FSE. Without this filtering mechanism, we'd add a lot of useless information per request. It can -- and probably will -- become a problem very quickly.

How

I'm looking up the contents of the current template for every request and saving its used webfonts as an option. This happens for every template, lazily.

Fonts used in the global styles settings are also cached. We're caching because this is an expensive operation.

The cache is invalidated on every update of:

  • template;
  • template part;
  • global styles...

And also when the current theme changes.

The content (post/page content) is also processed, per request, to include webfonts used by the blocks inside the current post or page. There is no cache for this type of content, but there might be if someone requests it.

It also includes a filter called gutenberg_used_webfonts so one can override the decision of the mechanism, either by adding or removing fonts as needed. This is a concern raised by @justintadlock regarding a few blocks that do not have the font-family attribute yet. It's a workaround until all blocks get the possibility to change the font family inside the block editor instead of working around it by using additional CSS classes.

Testing

You should check only the used fonts are included as inline CSS when the webfont is picked as:

  • an element, block, or typography setting in global styles;
  • the font family on any block that supports it in any active template;
  • the font family on any block that supports it in any template part and that template part is used by any active template;
  • the font family on any block that supports it in any post or page in the block editor.

TODO

  • Use WP Cache instead of option to save stuff?

@zaguiini zaguiini force-pushed the try/cache-used-webfonts branch from 58ed84d to afe1b56 Compare February 25, 2022 20:09
Base automatically changed from add/webfonts-simplified-api to trunk February 28, 2022 12:55
@zaguiini zaguiini force-pushed the try/cache-used-webfonts branch 2 times, most recently from 5582859 to 64c912f Compare February 28, 2022 22:17
@zaguiini zaguiini force-pushed the try/cache-used-webfonts branch from 8825187 to 6a5d8ae Compare March 2, 2022 21:34
@zaguiini
Copy link
Member Author

zaguiini commented Mar 2, 2022

@justintadlock I'm going the filter route in this PR.

I'm thinking of creating an issue regarding exposing the fontFamily attribute to all blocks. It's out of the scope of this PR, that's why I thought of adding the filter here as a temporary solution until 3rd-party block maintainers edit their plugins to take fontFamily attribute into consideration instead of classes. Any concerns/suggestions?

@zaguiini zaguiini self-assigned this Mar 2, 2022
@zaguiini zaguiini force-pushed the try/cache-used-webfonts branch 3 times, most recently from b3ce575 to 23a8205 Compare March 3, 2022 16:39
@zaguiini zaguiini marked this pull request as ready for review March 3, 2022 16:39
@mtias mtias added the [Type] Performance Related to performance efforts label Mar 3, 2022
@zaguiini zaguiini force-pushed the try/cache-used-webfonts branch from 23a8205 to a0e8182 Compare March 3, 2022 17:01
@zaguiini zaguiini changed the title Cache used webfonts instead of querying on every page load Webfonts API: Filter out unused fonts from the output Mar 3, 2022
@zaguiini zaguiini changed the title Webfonts API: Filter out unused fonts from the output Webfonts API: Output only used fonts Mar 3, 2022
@justintadlock
Copy link
Contributor

I'm going the filter route in this PR.

I'm thinking of creating an issue regarding exposing the fontFamily attribute to all blocks. It's out of the scope of this PR, that's why I thought of adding the filter here as a temporary solution until 3rd-party block maintainers edit their plugins to take fontFamily attribute into consideration instead of classes. Any concerns/suggestions?

@zaguiini I think that should work.

There are probably some other cases with supporting non-block content, such as plain HTML elements from classic posts. But, again, out of scope. WP really needs to allow theme devs to style all HTML elements via theme.json, too.

return $response;
}

$this->invalidate_globally_used_webfonts_cache();
Copy link
Member Author

Choose a reason for hiding this comment

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

This is unnecessary. Solely updating the option as I'm doing in the next line is enough.

Comment on lines 146 to 180
public function register_current_template_filter() {
$templates = get_block_templates( array(), 'wp_template' );

foreach ( $templates as $template ) {
add_filter(
$template->slug . '_template',
function() use ( $template ) {
$this->register_used_webfonts_by_template( $template );
}
);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

@creativecoder Do you happen to know if there's a single hook that returns the current template instead of what we're doing here?

Copy link
Member

Choose a reason for hiding this comment

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

The $template_html global is available in wp_head, and contains all the HTML of the page if that helps (in block themes)

Copy link
Member Author

Choose a reason for hiding this comment

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

Does it contain the slug too?

Copy link
Member

Choose a reason for hiding this comment

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

Does it contain the slug too?

No, $template_html is set in the template-canvas.php file when building the page, and only contains the HTML for the page:

$template_html = gutenberg_get_the_template_html();

Copy link
Member Author

Choose a reason for hiding this comment

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

Got it, so it won't really work for our use case since we need the slug too.

@zaguiini zaguiini force-pushed the try/cache-used-webfonts branch from a0e8182 to 3fcd821 Compare March 8, 2022 23:02
@creativecoder
Copy link
Contributor

This is a really important step forward for the Webfonts API, thank you for tackling it, @zaguiini !

While this change largely works for removing unused font-face declarations, a couple things worry me about the approach. The first is that the initial Webfont API we have now can be used in many different (and possibly unexpected) ways that might feel broken if we filter out fonts by default (unless they are used in a very specific way). For example, any css files included in a theme, or custom css from a plugin that registers a specific font would not be detected here, the font-face rule removed, and the font not loaded.

It seems like it would be better if the Webfonts API had an explicit way to differentiate between

  1. Fonts that are registered so they show up in the font-family settings for block and global styles
  2. Fonts that are used by those settings or are declared necessary by a theme/plugin that causes the @font-face rules to be printed out

My second concern is the complexity of caching what fonts are used for what templates when they are saved. This seems like it might be fragile if something unexpected happens between saving and outputting the templates, and that it would be better to check what fonts are used as the page is loaded, if at all possible.

Since I anticipate continuing to iterate on this approach, I created #39332 as a hub for discussing and tracking work on this area.

@zaguiini
Copy link
Member Author

zaguiini commented Mar 11, 2022

We're closing this PR since it's not going to be merged because of the implementation. However, as pointed above, there's an issue for it now: #39332.

@zaguiini zaguiini closed this Mar 11, 2022
@zaguiini zaguiini deleted the try/cache-used-webfonts branch March 22, 2022 15:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Type] Performance Related to performance efforts
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants