WordPress / gutenberg

The Block Editor project for WordPress and beyond. Plugin is available from the official repository.
https://wordpress.org/gutenberg/
Other
10.47k stars 4.18k forks source link

Server-Side Font Face CSS Generation and Printing: Ongoing Roadmap (formerly the Fonts API) #41479

Closed hellofromtonya closed 7 months ago

hellofromtonya commented 2 years ago

This is an epic ticket to share the ongoing roadmap including:

Updates:

Changed to Font Face: to server-side generate and print fonts' @font-face styles

With the introduction of the new Fonts Library, the role of the Fonts API has significantly changed as noted in https://github.com/WordPress/gutenberg/issues/41479#issuecomment-1597915077.

Previously, its roles were:

  • Role 1: Generate and print the @font-face styles for all “enqueued” fonts.
  • Role 2: Provide a means for plugins to present fonts to users, who can then decide whether to use these fonts (i.e. through the Site Editor).

Its new role is:

  • Generate and print the @font-face styles for all theme defined and user activated fonts.

Fonts will be presented to users via the Fonts Library, rather than through the Fonts API.

Plugins will no longer interact with the Fonts API. Instead, they will integrate directly into the Font Library (once that capability exists).

Font Face "gets" the fonts to print from Theme JSON merged data layer. Fonts are no longer registered or enqueued directly with it.

A full API is no longer needed. Thus, Font Face replaces the Fonts API.

Vision

As part of fonts management and Fonts Library,

This API's job is to provide the backend capabilities to support the "font library" to include font management and dynamic building of the @font-face styles.

The "font library" feature will continue to be built, refined, stabilized, and tuned over multiple WordPress releases.

Font Library

See https://github.com/WordPress/gutenberg/pull/50927.

The idea is to have the concept of a font library on a site to

The fonts in the library can come from:

The fonts to be used in the site are saved and available via Theme JSON merged data layer, i.e. WP_Theme_JSON_Resolver_Gutenberg::get_merged_data()->get_settings().

FAQ

What about classic sites?

Yes, supported ✅

Classic themes and plugins can have their @font-face styles generated and printed. How?

Classic themes have 2 options:

Plugins supporting classic sites can use Option 1.

Ongoing work

Architecture

⭐ Required for Core introduction:

Performance

⭐ Required for Core introduction: None

Feature needs

⭐ Required for Core introduction: None

Future enhancements

Bugs

None

Documentation

Backports

Future.

Tracking key

✅ Done ⚪ WIP: work in progress 🟡 Experiment WIP 🍏 in testing or code review 🔴 Danger > immediate action needed 🚫 Blocked

⭐ Needed for WP Core introduction

hellofromtonya commented 2 years ago

The vision for the font management through a formal Webfonts API is now available in the description of this roadmap (ie in the Vision section).

The first priority is to solidify the architecture as all other tasks will be affected by these architectural changes:

Once these 2 tasks are done, then the remaining tasks can be prioritized along with impacts to update each of them to fit within the architectural changes. I removed the priority labels from each of these other tasks.

azaozz commented 2 years ago

This sounds great! A clear and well defined vision makes the tasks ahead much easier to understand.

Trying to get into a bit more details, perhaps "brainstorm" a little more. One of the hard performance related questions would be: What happens when somebody decides to register the whole collection from https://fontsource.org/ (more than 1600 fonts)? It's pretty pointless (will need a dedicated UI and still the users will have a pretty hard time selecting fonts from such a huge list) but that doesn't mean it's not going to happen.

That led to couple of questions:

  1. What is the purpose of registering the webfonts outside of the Global Styles UI. Would registering be needed even there, or a "list of the names of available fonts" (perhaps with preview images for the UI) would be sufficient.
  2. How is that UI going to work with possibly hundreds of fonts?

For the first question, in most cases it seems registering can be done together with the enqueueing only for the fonts that are in use. That will speed things up and perhaps reduce complexity a little. Thinking a bit further implementation-wise: should registering a font be needed for enqueueing it? Seems not. A "prior art" is how scripts can be enqueued without a need to be registered.

The second question is harder. Are we talking about building UI similar to the Google's webfonts picker? Seems anything less may not be enough, perhaps. Not sure what a UI for picking one out of a hundred fonts may be, but thinking it would be best to have an idea about it before deciding on the back-end code, so the requirements of that (and future) UI are met.

adamsilverstein commented 2 years ago

Great to see this overview issue @hellofromtonya - this is super helpful as I've been struggling to keep up with the Fonts API proposals & progress.

I noticed several features I see in other font APIs that aren't mentioned here and wanted to know if these are on your roadmap at all or would be something to propose for a future iteration:

desrosj commented 2 years ago

One thing that's been bugging me is that I feel like "Webfonts" is wrong when I read it. I did some searching around, and my findings seem to point towards "Web fonts" as the preferred way to refer to this. I know this is a nit, but I think it's important to get it right and be consistent. here are some authoritative pages I found pointing to Web Fonts:

Other pages for Webfonts

azaozz commented 2 years ago

Supporting for downloading fonts (to avoid external requests), ideally built in/automatic

@adamsilverstein Yeah, support for preloading is needed, but not sure what "downloading" has to do here? Thought is was decided that this API is for local fonts only. This has numerous advantages as discussed before. Downloading what, and from where? :)

I'd also think that if a plugin wants to use external fonts from a CDN, like Google fonts, it would still consider downloading the open source fonts as available at places like https://github.com/fontsource/fontsource and not trying to capture the CDN's output (which may also have some compatibility or licensing issues as it is closed source).

hellofromtonya commented 2 years ago

@mtias and I discussed this roadmap for both block and classic themes. From that discussion, I've updated the description of this ongoing roadmap including the "font library" vision, technical details, and a new FAQ section.

The changes include publicly exposing enqueue and remove functionality.

hellofromtonya commented 2 years ago

Thought is was decided that this API is for local fonts only. ~ @azaozz

Bundled in the API is a local fonts provider. It does not include remote font foundry handling. It does provide the means for plugin authors to create custom providers, such as to handle (a) an alternative local fonts approach or (b) remotely hosted fonts.

IMO I don't think Core should force only local fonts.

cc @adamsilverstein @azaozz

adamsilverstein commented 2 years ago

Thanks for clarifying @hellofromtonya and @azaozz

was decided that this API is for local fonts only

It does provide the means for plugin authors to create custom providers, such as to handle (a) an alternative local fonts approach or (b) remotely hosted fonts.

🎉 Great!

hellofromtonya commented 2 years ago

I opened a separate issue for renaming consideration per @desrosj suggestion. Let's move the naming discussion to here https://github.com/WordPress/gutenberg/issues/42868

hellofromtonya commented 2 years ago

Tracking the block level typography consistency effort https://github.com/WordPress/gutenberg/issues/43242

hellofromtonya commented 1 year ago

⭐ Status Update:

Status: Blocked by architectural work.

DONE: ✅ The major architectural redesign (See #41481) is now merged. The new architecture is a code rewrite which has breaking changes. Some high level details:

NEXT: ⚪ There are 2 more architectural tasks that need to be completed to unblock the remaining bugs, performance, and feature work can continue.

👉 Where can you help?

hellofromtonya commented 1 year ago

⭐ Status Update ⭐ 18 Jan 2023

Status:

Big Picture

👉 It's a NEW API The API has been completely redesigned with a new architecture and renamed including all publicly available functions, classes, and methods.

👉 BC Layer A backwards-compatibility (BC) layer (with deprecations) was added to ensure sites using this API in production keep running while giving developers time to upgrade to the new API. This BC Layer will NOT be backported to Core.

Who's impacted?

⭐ 👉 Next steps

These 2 issues are must-haves:

All open PRs are impacted. This means each open issue and any of its PRs must be evaluated one-by-one and if still relevant, rebased and rebuilt to apply changes to the new API.

TODO:

  1. [ ] Evaluate each PR to determine:
    • Is it still needed?
    • If yes, how should the changes be introduced into the new API?
    • If yes, what priority level should it be for WP 6.2?
  2. [ ] Rebase and rebuild PRs: Each PR will need to be rebased on top of trunk to bring the new API into its scope. In most cases (if not all), the PR will need to rebuilt.
felixarntz commented 1 year ago

@hellofromtonya Please let me know how I can help with this effort in relation to WP 6.2. Is there already a corresponding Trac ticket for it?

adamsilverstein commented 1 year ago

I'd also think that if a plugin wants to use external fonts from a CDN, like Google fonts, it would still consider downloading the open source fonts as available at places like fontsource/fontsource and not trying to capture the CDN's output (which may also have some compatibility or licensing issues as it is closed source).

@azaozz my question earlier about "Downloading" is around when someone is already using a remotely hosted font, how they would (font license permitting) download that font to serve it locally. It would be amazing if that were handled automatically by the API - although I could also see how this might be plugin territory.

hellofromtonya commented 1 year ago

@felixarntz Thank you! Here's the Trac ticket https://core.trac.wordpress.org/ticket/46370.

shilo-ey commented 1 year ago

Hi, Shilo from Elementor here.

Thank you for sharing these updates regarding Webfonts API. It is a great step toward a unified and improved way of handling web-fonts.

As discussed by @azaozz, @adamsilverstein and @hellofromtonya, there are several performance and privacy benefits to serving the fonts from a local server instead of the remote one. When making this capability native in the Webfonts API, it makes sense not to force the local “downloading” to happen by default, but to allow the API to manage it automatically for a better, unified process of font handling by every contributor in the WordPress ecosystem.

hellofromtonya commented 1 year ago

Hello @shilo-ey 👋

Thanks for your feedback and support. If you're able, would appreciate your help in testing it with themes and especially through registering fonts from a plugin or theme without a theme.json file. Feedback and testing contributions are greatly appreciated as this API continues in development from experimental into stable.

azaozz commented 1 year ago

it makes sense not to force the local “downloading” to happen by default

@shilo-ey I'm a bit unsure of what "downloading" has to do with it and how that might work :)

The general idea is that themes would include recommended fonts, and the users would be able to pick from a preset, curated list of fonts that would look good and work well in the theme. These recommended fonts will be packaged with the theme and will include the recommended variants (weights, subsets, etc.) and the CSS needed to use them as determined by the theme's authors. This ensures that the theme will look good and work well for different devices, accessibility requirements, etc.

For users that "know what they are doing" there may be plugins that would offer extra fonts. These fonts should be included with the plugin, and the CSS for the different variants would be preset. Such plugins would likely have some UI so the users can select to enqueue in WP only the fonts they intend to use.

There's no point in registering hundreds, even thousands of fonts as the users would have very difficult time picking what they need, and will be likely to choose something unsuitable.

Themes and plugins that want to offer fonts can include them by using npm or download them from Fontsource. Instructions: https://fontsource.org/docs/getting-started.

In other words, the "heavy lifting" part of choosing fonts will be done by the theme authors and some plugins authors. The users will only need to select from a list of fonts that "work", and are ready for use on their sites. It'd be a bad idea to "push" the users to make decisions they may not be equipped to make.

Eventually there may be a plugin that would offer to "automatize" installation of more fonts. Such plugin would need to download the fonts and work out the CSS needed for each of them. However thinking such plugin would not be particularly helpful for the great majority of users.

my question earlier about "Downloading" is around when someone is already using a remotely hosted font, how they would (font license permitting) download that font to serve it locally.

@adamsilverstein Ideally their theme will be updated and the font(s) they are using will be included. If not, the second-best option would be to install a plugin that includes the font they want to use.

I'm aware that there are plugins that offer to download a remote font and make it available locally. Imho this is a stop-gap solution that is inferior to having the theme authors choose and include recommended fonts and font settings. Thinking that for now it would be okay to use so the site is compliant with privacy requirements, but hoping this will be abolished in the future.

hellofromtonya commented 1 year ago

Update:

The Fonts API is not ready for introduction into WordPress Core for WP 6.2. Why?

The API needs several Gutenberg release cycles to stabilize after being completely rewritten and renamed. The renaming and latest rewrites are targeted for GB 15.1 which releases 1 day after 6.2 Beta 1. That's not enough time to ensure the API is ready.

Focus will be on:

All of these seem doable to target introduction into WP 6.3 alpha.

adamsilverstein commented 1 year ago

@adamsilverstein Ideally their theme will be updated and the font(s) they are using will be included. If not, the second-best option would be to install a plugin that includes the font they want to use.

That makes sense - the theme should have specific fonts it specifies and uses. Since fonts are pretty small, it makes sense to bundle them.

I was just wondering if there is a use case for a "side loading" capability - that way fonts could be loaded from the network when used and still be served locally. Another idea would be the ability to add a new font dynamically in the block editor (maybe this could already work with a block plugin?).

Perhaps something more for a plugin to build rather than core?

hellofromtonya commented 1 year ago

Update:

simison commented 1 year ago

@hellofromtonya I have a feature request for your consideration for the roadmap ("allow deprecating fonts").

webd-uk commented 1 year ago

@hellofromtonya Your roadmap explains that "remove" and "enqueue" are to be exposed for plugins to remove and add fonts via the Font API. Would you please provide more information as to how this can be done or has this functionality not yet been developed? We actively attempting to test this but cannot find any documentation. Thanks! Oliver.

hellofromtonya commented 1 year ago

Update 19 Jun 2023

tl;dr BIG changes are coming to the Fonts API.

Why?

Managing fonts is about to get a brand new user workflow as defined in the tracking issue.

The Font Library consists of a font manager for WordPress. The Font Library is available globally, independently of the theme activated, similar to the Media Library. This list of installed fonts and their assets are site-wide available and the users can select the fonts activated (available in the editor) for each theme.

The new (and WIP) Font Library will provide:

Fonts API new role

The role of the Fonts API changes with this new font management system.

Previously, its roles were:

Its new role is:

Changes to the Fonts API

With new font management system, the Fonts API becomes "read-only" of the Theme JSON fonts definitions and then prints the @font-face styles for only those fonts.

More specifically:

Change: Public-facing register and deregister functionality are no longer needed.

Why?

Plugins will no longer interact with the Fonts API. Instead, they will integrate directly into the Font Library (once that capability exists).

Change: Public-facing enqueue functionality is no longer needed.

The decision of which fonts to print @font-face styles for is made in the font management system, i.e. by the theme's design and users actions to activate fonts in the Font Library.

The means to override and force a font as "activated" should be done within that feature, not in a lower level api.

Why? Fonts added to the Fonts API that do not exist in Theme JSON will not show in the Font Library, Site Editor, or block font pickers. This is because the Fonts API becomes a read-only of the Theme JSON data. It will no longer inject fonts into the settings.

An example may help to visualize why this is important.

Imagine a plugin wants to force its defined font to always be activated and its @font-face styles to print. If it skipped the Font Library and directly registered and enqueued in the Fonts API, what would happen? Its @font-face styles will print. But its font would not (a) be available for user selection in the Site Editor or in blocks and (b) show in the Font Library. In other words, the user would have no means to manage the font, other than to deactivate the plugin.

Change: Adding missing fonts into Theme JSON is no longer needed.

The Fonts API will become read-only. It will no longer inject fonts into Theme JSON. This change simplifies the API and removes the decision making, solving a lot of open issues.

Changes:

https://github.com/WordPress/gutenberg/blob/9cd88c73fd84fe103c487effb9aa65d753a78f91/lib/class-wp-theme-json-resolver-gutenberg.php#L277-L279

Change: Automatic enqueueing of user selected fonts from Site Editor is no longer needed.

Before the Font Library, the Fonts API automatically identified and enqueued fonts selected by users in the Site Editor (currently doing in WP_Fonts_Resolver::enqueue_user_fonts()). This is no longer needed.

Other Considerations and Questions

What about "providers"?

Maybe in the future.

Supporting custom providers in the Fonts API should not happen until the Font Library also supports it.

Why?

Providers were originally conceptualized to support local fonts (built-in) and Google fonts (custom). With the Font Library, Google Fonts will now be built-in.

What about other remote font services?

Is there enough of a use-case to add provider functionality to support other remote font services? If yes, then the Font Library will need the means to (a) disable its @font-face styles generator to use the custom provider and (b) save the "provider" setting with the other font properties for the Fonts API to pull when printing.

What about property validation?

Should the Fonts API be validating font properties? Hmm, validation should happen at a higher level, before rendering a preview of the font to users.

Why? To avoid low level errors that users are unaware of.

I suspect the validation can happen in the theme.json schema.

Should the Fonts API's architecture change?

Action: I'll open a new issue to capture the discussion.

A significant amount of its functionality is no longer needed. Much of WP_Dependencies public facing methods need to be disabled, thus making a significant amount of its functionality overkill for what this API needs.

Essentially, only a public-facing "print" is needed with all of the interworkings of how to pull and process the data hidden inside.

For current needs, what's in WordPress Core should already handle what's needed for font management. That code was meant as a temporary stopgap. But it can be the inspiration for a redesign of the Fonts API.

I'm wondering:

I'm leaning towards the latter by designing a lean version that does hide the interworkings to avoid introducing a future BC concern in WordPress Core.

What about classic sites?

👉 Proposal to classic themes to adopt theme.json for defining fonts to generate and print @font-face styles https://github.com/WordPress/gutenberg/issues/51714

Originally the Fonts API was intended to also work on classic sites. The register, enqueue, and print functionality was agnostic, given it extended WP_Dependencies.

Is there a way for classic sites to get their fonts @font-face styles generated and printed? Is there enough of a use-case?

UPDATE 20 June 2023: I tested a TT1 theme variations where I added a theme.json file that only defined the fonts (set up instructions are here). It works properly - meaning the @font-face styles are generated and the theme is recognized to use Customizer, instead of Site Editor ✅

hellofromtonya commented 1 year ago

This week, I'll be updating the roadmap, opening new issues for changes, and triaging existing issues as many will no longer apply.

webd-uk commented 1 year ago

@hellofromtonya Wow! That's quite the U-turn and pretty exciting!

(yet to be designed) means for plugins to "register" their fonts for user consideration.

How can we find out more about this because it will need to be used to add fonts that a plugin previously added via other methods. Specifically ... if a user has already selected to use a font via an existing plugin, will there be a way for the plugin to seamlessly pre-select the font via this new Font Library registration method for the user so that the user doesn't have to select the font again?

Otherwise, when the user updates the plugin to a Font Library friendly version, they would need to go into the Font Library and re-affirm that they want to select their fonts before they'd be available for use, right?

Also, and forgive me if I missed it in your description above, but will the Font Library be able to de-select fonts added by the theme via theme.json? Assuming these fonts would be automatically pre-selected for use.

Thanks!

Oliver

felixarntz commented 1 year ago

Thanks for the update @hellofromtonya! While reading through your comment, I was a bit skeptical on what the change would mean for classic themes since the original proposal would have indeed been agnostic. But as long as a classic theme can introduce support via theme.json only for fonts without having to also opt in to other block theme features, the new direction sounds great to me.

Let's make sure to keep the classic theme considerations on our radar, we need to make sure that the way the Font Library is eventually implemented satisfies both block and classic themes use-cases.

hellofromtonya commented 1 year ago

Thank @felixarntz.

Yesterday, I confirmed that since WordPress 6.0.0 (with the _wp_theme_json_webfonts_handler() stopgap code), a classic theme has had the ability to define their fonts in theme.json file (only the fonts) and results are:

Cool!

I created this Proposal yesterday to stay with that convention for classic themes, use a theme.json file instead of also providing global functions to directly add their fonts. I'll cross-post your feedback. Thanks!

we need to make sure that the way the Font Library is eventually implemented satisfies both block and classic themes use-cases.

As far as I know, the Font Library will only work with Site Editor, which is only available to block themes. Classic themes use Customizer. I think the better place to raise awareness of classic themes with the Font Library is in this issue https://github.com/WordPress/gutenberg/issues/45271, i.e. where managing fonts and font library are being discussed and worked on.

hellofromtonya commented 1 year ago

Sorry for the delay in responding to you @webd-uk.

How can we find out more about this because it will need to be used to add fonts that a plugin previously added via other methods. Specifically ... if a user has already selected to use a font via an existing plugin, will there be a way for the plugin to seamlessly pre-select the font via this new Font Library registration method for the user so that the user doesn't have to select the font again?

If the user has already selected a plugin defined font, then that font should be saved in the database when saving those selections in the Site Editor. Those fonts then should be within the theme.json merged data, i.e. WP_Theme_JSON_Resolver_Gutenberg::get_merged_data()->get_settings() within ['typography']['fontFamilies'].

Then when it's time to "print" @font-face styles, the new Fonts API (or whatever name it becomes) pulls from WP_Theme_JSON_Resolver_Gutenberg::get_merged_data()->get_settings() to extract the fonts to print.

As for what gets "activated" in the Font Library, I think it's also using that same data.

What isn't there yet is the means for a plugin to "register" its defined fonts with the Font Library.

I'd suggest asking the question and contributing in the main issue https://github.com/WordPress/gutenberg/issues/45271 or in the Font Library's WIP PR https://github.com/WordPress/gutenberg/pull/50927.

webd-uk commented 1 year ago

I'd suggest asking the question and contributing in the main issue #45271 or in the Font Library's WIP PR #50927.

Thank you, @hellofromtonya! I will definitely be doing that but need to read up on everything first. Thanks again, Wordpress has needed this built-in feature for soooooooo long!

hellofromtonya commented 1 year ago

Update 22 Jun 2023

New Learnings

New Learnings since my 19th Jun update:

What currently works with the Fonts Library?

WordPress Core ✅ Fonts API ❌

The stopgap code in WordPress Core since 6.0.0 works with the Fonts Library _wp_theme_json_webfonts_handler() and supports classic themes adding a theme.json file with only fonts defined. ✅

However, the Fonts API in Gutenberg does not work with the Fonts Library and must be changed before the Fonts Library is merged. ❌

Should the Fonts API's architecture change?

Yes! ✅

It needs a near complete redesign.

Issue https://github.com/WordPress/gutenberg/issues/51769 is for the redesign, transforming the Fonts API into only a Font Face styles generator and printer.

WIP PR https://github.com/WordPress/gutenberg/pull/51770 is what I envision as the redesign.

What about classic sites?

Yes, supported ✅

Classic themes and plugins can have their @font-face styles generated without requiring register or enqueue. How?

Classic themes have 2 options:

  1. Option 1: Add a callback function hooked in 'wp_head' and 'admin_print_styles' and within that callback function, invoke a new print method and pass their fonts to it.
  2. Option 2: Add a theme.json file that only defines the fonts. See issue https://github.com/WordPress/gutenberg/issues/51714 for more information.

Plugins supporting classic sites can use Option 1.

What about font-face property validation?

Yes, still required ✅

To support classic sites and potentially other needed customizations, the new Font Face design exposes a print( $fonts ) method that accepts an array of fonts. Those are the fonts that will be processed to generate and print the @font-face styles.

As any source could invoke that print( $fonts ) method, the passed in font-face properties still require validation. Why? To (a) protect the code from missing properties or invalid data types and (b) provide extenders guidance of where problems are in the array of fonts.

What about "providers"?

Fonts Library only supports serving @font-face src from local assets. It has Google Fonts built into it, but downloads the font files to wp-content/fonts/ for local access.

To keep parity with the Fonts Library, the Fonts API support of custom providers will be removed. The new design will only support local font files. This change will ensure fonts work the same on all types of sites.

If enough of need is discovered, then a future enhancement could be to add custom provider support.

What about sites currently using the Fonts API?

The API is experimental. However, the API has taken the approach of supporting backward compatibility through the BC Layer to avoid sites breaking.

The new Font Face generation is a big big change. Care is needed to consider how to safeguard sites currently using the Fonts API while guiding developers towards where and what needs to change.

hellofromtonya commented 1 year ago

The description of this roadmap is now updated for "Font Face", i.e. to define its new role in font management and its scope of work.

hellofromtonya commented 1 year ago

Update

Font Face is ready to be introduced into WordPress Core. It is a direct replacement for _wp_theme_json_webfonts_handler() in that it processes block themes with the same @font-face styles while providing the means for classic themes and plugins to also print their font's @font-face styles.

TODO:

hellofromtonya commented 1 year ago

Here's the Core Trac ticket for merging Font Face into Core https://core.trac.wordpress.org/ticket/59165.

annezazu commented 7 months ago

Closing this out as https://core.trac.wordpress.org/ticket/59165 shipped. Let me know if that's incorrect and I can reopen. Thanks for all the hard work here!