Make WordPress Core

Opened 15 months ago

Closed 14 months ago

Last modified 4 months ago

#59165 closed enhancement (fixed)

Font Face: Server-side @font-face styles generator and printer

Reported by: hellofromtonya's profile hellofromTonya Owned by: hellofromtonya's profile hellofromTonya
Milestone: 6.4 Priority: normal
Severity: normal Version:
Component: General Keywords: gutenberg-merge has-patch has-unit-tests has-testing-info has-screenshots commit
Focuses: Cc:

Description (last modified by hellofromTonya)

Introducing Font Face, a server-side @font-face styles generator and printer. This ticket tracks merging Font Face from Gutenberg into Core.

What is Font Face?

Font Face's role is to generate and print the @font-face styles for all theme defined and user activated fonts (activation will be handled by Font Library #59166).

There is no font registration or enqueuing.

It is not involved in the process of determining which fonts the site should or is using. Rather, it processes what is passed to it or, if none, pulls / gets the fonts from Theme_JSON's merged data layer.

It introduces a new global function called wp_print_font_faces(). This function is automatically called:

  • when the 'wp_head' hook runs (for the front-end).
  • when the 'admin_print_styles' hook runs (for the back-end).
  • when _wp_get_iframed_editor_assets() runs to inject the @font-face styles into the iframed editor.

Once called, it gets the fonts from Theme_JSON merged data layer, which includes theme defined fonts and user activated fonts (once the Font Library #59166 is introduced into Core).

What is @font-face styles?

Per mdn web docs:

The @font-face CSS at-rule specifies a custom font with which to display text; the font can be loaded from either a remote server or a locally-installed font on the user's own computer.

Does it work on classic sites too?

Yes. For classic sites, themes and plugins can directly call wp_print_font_faces() and pass their fonts array to it for processing.

Does it replace _wp_theme_json_webfonts_handler()?

Yes. Font Face is a direct replacement for the stopgap code in _wp_theme_json_webfonts_handler() that was introduced in 6.0 via [53282].

Is it built-off of Fonts API?

Font Face is built off of the early versions of a Web Fonts API that was first proposed in #46370. The internal CSS generation and printing comes from that early version.

It does not include register, deregister, enqueue, or custom provider functionality.

Why no register or enqueue?

The earlier versions of a web font API went through many implementations to fit what was known in each's time. It involved from Webfonts API to Web Fonts API to Fonts API. Each of these APIs provided the means for themes and plugins to register fonts with it, these registered fonts were injected into Theme JSON theme data layer for presentation to the user for selection. And then user selected fonts and theme defined fonts were enqueued and printed.

The role of registration existed for the purpose of making fonts available for users to globally select what they want on their website. Then those selections were enqueued for style generation and printing.

But problems happened with a low level service trying to inject fonts into higher data levels. A low level service should not be involved in the process of determining what fonts are being used and should be generated and printed. Rather, a low level service should be told "Hey, process these fonts."

The Font Library (see #59166) changed the direction as its role is to present fonts to users for them to manage what fonts they want on their website. Users will be able to upload / install, activate, and deactivate fonts. Those selections will then be saved for the system to use, including Font Face.

Is it an API?

No. Other components and APIs will not interact with it, per se. Rather, it receives or gets what it needs to do its job.

References:

Attachments (3)

Scenario1-Step5.gif (8.6 MB) - added by hellofromTonya 15 months ago.
Test Report Scenario 1 Step 5 - showing the font-face CSS in the main doc's head
Scenario1-Step11.gif (1.4 MB) - added by hellofromTonya 15 months ago.
Test Report Scenario 1 Step 11 - showing the font file in the Network tab.
Scenario2-Step3.png (243.1 KB) - added by hellofromTonya 15 months ago.
Test Report Scenario 2 Step 3: shows the generated CSS on the front-end of a classic site

Change History (41)

#1 @hellofromTonya
15 months ago

  • Owner set to hellofromTonya
  • Status changed from new to accepted

The following Gutenberg PRs are in process to prepare Font Face for merge into Core:

Once merged into Gutenberg, then I'll prepare a PR patch for this ticket.

#2 @hellofromTonya
15 months ago

  • Description modified (diff)

#3 @hellofromTonya
15 months ago

  • Description modified (diff)

Added links to Font Library Trac ticket, i.e. #59166.

This ticket was mentioned in PR #5051 on WordPress/wordpress-develop by @hellofromTonya.


15 months ago
#4

  • Keywords has-patch has-unit-tests added

Adds the new Font Face, a server-side @font-face styles generator and printer. Code is copied from Gutenberg.

Trac ticket: https://core.trac.wordpress.org/ticket/59165

## How to Test

Instructions are coming ....

#5 @hellofromTonya
15 months ago

  • Keywords has-testing-info added

Scenario 1: Testing Instructions

These steps define how to test this enhancement, and indicates the expected behavior or results.

This scenario is a block site that uses the default set up with no plugins activated and using Twenty Twenty-Three (TT3) theme.

Steps to Test

  1. Apply the patch in your local test environment.
  2. Start your local test environment. If using wp-env Docker environment, do the following:
npm install
npm run build:dev
npm run env:start
npm run env:install

and then in your browser, go to localhost:8889/wp-admin to access the test site.

  1. Go to Appearance > Site Editor.
  2. Open Developer Tools in your browser.
  3. In the HTML / Elements tab of your browser's dev tools, search for "wp-fonts-local" element (which has the Twenty-TwentyThree @font-face CSS). See below for the expectations.
  4. Open the Styles UI by selecting the content area and then the Styles icon in the top right hand corner.
  5. Select "Typography" to open the Typography UI.
  6. Select "Headings" (or any other element).
  7. Select the "Font" dropdown to view the list of available fonts. See below for expectation.
  8. Change the Font to "Source Serif Pro". See below for the expectation.
  9. In your browser's dev tools, click on the Network tab. See below for the expectation.

Fonts defined in TT3

The Twenty Twenty-Three (TT3) theme defines the following fonts in its theme.json file. These are the fonts that should appear in the Site Editor and @font-face CSS.

List of fonts defined in TT3:

  • DM Sans with 4 different fontFace variations:
    • font-style:normal, font-weight:400, and the src is in the theme's assets/fonts/dm-sans/DMSans-Regular.woff2.
    • font-style:italic, font-weight:400, and the src is in the theme's assets/fonts/dm-sans/DMSans-Regular-Italic.woff2.
    • font-style:normal, font-weight:700, and the src is in the theme's assets/fonts/dm-sans/DMSans-Bold.woff2.
    • font-style:italic, font-weight:700, and the src is in the theme's assets/fonts/dm-sans/DMSans-Bold-Italic.woff2.
  • IBM Plex Mono with 4 variations:
    • font-style:normal, font-weight:300, font-display:block, and the src is in the theme's assets/fonts/ibm-plex-mono/IBMPlexMono-Light.woff2.
    • font-style:normal, font-weight:400, font-display:block, and the src is in the theme's assets/fonts/ibm-plex-mono/IBMPlexMono-Regular.woff2.
    • font-style:italic, font-weight:400, font-display:block, and the src is in the theme's assets/fonts/ibm-plex-mono/IBMPlexMono-Italic.woff2.
    • font-style:normal, font-weight:700, font-display:block, and the src is in the theme's assets/fonts/ibm-plex-mono/IBMPlexMono-Bold.woff2.
  • Inter with 1 variation:
    • font-style:normal, font-weight:200 900, font-display:block, and the src is in the theme's assets/fonts/inter/Inter-VariableFont_slnt,wght.ttf.
  • Source Serif Pro with 2 variations:
    • font-style:normal, font-weight:200 900, and the src is in the theme's assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2.
    • font-style:italic, font-weight:200 900, and the src is in the theme's assets/fonts/source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2.

Expected Results

Here is the list of expectations for each testing step above. This is what should happen for each of these steps:

  • ✅ At Step 5, the <style id="wp-fonts-local"> element should be in the main document's head, i.e. head > style#wp-fonts-local.
  • ✅ At Step 5, the <style id="wp-fonts-local"> element should be in the iframed editor's head, i.e. and the iframe.edit-site-visual-editoreditor-canvas > html > head > style#wp-fonts-local`.
  • ✅ At Step 5, both <style id="wp-fonts-local"> elements should contain the same CSS which should be the following:
<style id="wp-fonts-local">
@font-face{font-family:"DM Sans";font-style:normal;font-weight:400;font-display:fallback;src:url('http://localhost:8889/wp-content/themes/twentytwentythree/assets/fonts/dm-sans/DMSans-Regular.woff2') format('woff2');font-stretch:normal;}
@font-face{font-family:"DM Sans";font-style:italic;font-weight:400;font-display:fallback;src:url('http://localhost:8889/wp-content/themes/twentytwentythree/assets/fonts/dm-sans/DMSans-Regular-Italic.woff2') format('woff2');font-stretch:normal;}
@font-face{font-family:"DM Sans";font-style:normal;font-weight:700;font-display:fallback;src:url('http://localhost:8889/wp-content/themes/twentytwentythree/assets/fonts/dm-sans/DMSans-Bold.woff2') format('woff2');font-stretch:normal;}
@font-face{font-family:"DM Sans";font-style:italic;font-weight:700;font-display:fallback;src:url('http://localhost:8889/wp-content/themes/twentytwentythree/assets/fonts/dm-sans/DMSans-Bold-Italic.woff2') format('woff2');font-stretch:normal;}
@font-face{font-family:"IBM Plex Mono";font-style:normal;font-weight:300;font-display:block;src:url('http://localhost:8889/wp-content/themes/twentytwentythree/assets/fonts/ibm-plex-mono/IBMPlexMono-Light.woff2') format('woff2');font-stretch:normal;}
@font-face{font-family:"IBM Plex Mono";font-style:normal;font-weight:400;font-display:block;src:url('http://localhost:8889/wp-content/themes/twentytwentythree/assets/fonts/ibm-plex-mono/IBMPlexMono-Regular.woff2') format('woff2');font-stretch:normal;}
@font-face{font-family:"IBM Plex Mono";font-style:italic;font-weight:400;font-display:block;src:url('http://localhost:8889/wp-content/themes/twentytwentythree/assets/fonts/ibm-plex-mono/IBMPlexMono-Italic.woff2') format('woff2');font-stretch:normal;}
@font-face{font-family:"IBM Plex Mono";font-style:normal;font-weight:700;font-display:block;src:url('http://localhost:8889/wp-content/themes/twentytwentythree/assets/fonts/ibm-plex-mono/IBMPlexMono-Bold.woff2') format('woff2');font-stretch:normal;}
@font-face{font-family:Inter;font-style:normal;font-weight:200 900;font-display:fallback;src:url('http://localhost:8889/wp-content/themes/twentytwentythree/assets/fonts/inter/Inter-VariableFont_slnt,wght.ttf') format('truetype');font-stretch:normal;}
@font-face{font-family:"Source Serif Pro";font-style:normal;font-weight:200 900;font-display:fallback;src:url('http://localhost:8889/wp-content/themes/twentytwentythree/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2') format('woff2');font-stretch:normal;}
@font-face{font-family:"Source Serif Pro";font-style:italic;font-weight:200 900;font-display:fallback;src:url('http://localhost:8889/wp-content/themes/twentytwentythree/assets/fonts/source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2') format('woff2');font-stretch:normal;}
</style>

Note: http://localhost:8889 may be different if you're using a different localhost URL or provider.

  • ✅ At Step 9, the list of fonts should be:
    • Default
    • DM Sans
    • IBM Plex Mono
    • Inter
    • System Font
    • Source Serif Pro
  • ✅ At Step 10, the heading "Mindblown: a blog about philosophy." with the Source Serif Pro font selected should render to visually look like the same font on the Google Fonts UI page.
  • ✅ At Step 11, "SourceSerif4Variable-Roman.tff.woff2" should appear in your browser's Network tab with a 200 Status and Type of "font". Note: You may need to refresh your browser.

Test Report Icons:
✅ <= Behavior is expected.
❌ <= Behavior is NOT expected.

Last edited 15 months ago by ironprogrammer (previous) (diff)

#6 @hellofromTonya
15 months ago

How does the CSS compare to the stopgap code being deprecated by this ticket?

The only difference is the <style> element ID.

  • Stopgap code enqueues to the wp-block-library:
    <style id="wp-block-library-inline-css">
    
  • Font Face generates its own element:
    <style id="wp-fonts-local">
    

#7 @hellofromTonya
15 months ago

Scenario 2: Classic Site Testing Instructions

These steps define how to test this enhancement, and indicates the expected behavior or results.

This scenario tests a classic site with a plugin that passes its array of fonts to wp_print_font_faces().

Steps to Test

  1. Install and activate the Font Face Tester plugin.
  2. Activate the Twenty Twenty-One (TT1) theme.
  3. In the HTML / Elements tab of your browser's dev tools, search for "wp-fonts-local" element. See below for the expectations.

Expected Results

Here is the list of expectations for each testing step above. This is what should happen for each of these steps:

  • ✅ At Step 3, the <style id="wp-fonts-local"> element should be in the main document's head, i.e. head > style#wp-fonts-local.
  • ✅ At Step 3, the <style id="wp-fonts-local"> element should contain the following CSS:
<style id="wp-fonts-local">
@font-face{font-family:"Playfair Display";font-style:normal;font-weight:200 900;font-display:fallback;src:url('http://localhost:8889/wp-content/plugins/font-face-tester/assets/fonts/PlayfairDisplay-VariableFont_wght.ttf') format('truetype');}
@font-face{font-family:"Playfair Display";font-style:italic;font-weight:200 900;font-display:fallback;src:url('http://localhost:8889/wp-content/plugins/font-face-tester/assets/fonts/PlayfairDisplay-Italic-VariableFont_wght.ttf') format('truetype');}
</style>

Test Report Icons:
✅ <= Behavior is expected.
❌ <= Behavior is NOT expected.

@hellofromTonya
15 months ago

Test Report Scenario 1 Step 5 - showing the font-face CSS in the main doc's head

@hellofromTonya
15 months ago

Test Report Scenario 1 Step 11 - showing the font file in the Network tab.

#8 @hellofromTonya
15 months ago

Scenario 1 Test Report

Testing Instructions: comment:5

Patch tested: https://github.com/WordPress/wordpress-develop/pull/5051

Environment

  • OS: macOS
  • Localhost: wp-env Docker
  • PHP: 7.4.33
  • WordPress: trunk
  • Browser: Firefox and Chrome
  • Theme: Twenty Twenty-Three (TT3)
  • Active Plugins: None

Actual Results

For Step 5,

  • ✅ Confirmed <style id="wp-fonts-local"> element is in the main document's head.
  • ✅ Cconfirmed <style id="wp-fonts-local"> element is in the iframed editor's head, iframe.edit-site-visual-editoreditor-canvas > html > head > style#wp-fonts-local.
  • ✅ Confirmed both <style id="wp-fonts-local"> elements contained the expected CSS.

See it in action in Scenario1-Step5.gif.

For Step 9:

  • ✅ Confirmed the list of fonts matches what is expected.

For Step 10:

  • ✅ Confirmed the heading visually changed when selecting "Source Serif Pro" and it matched the font on Google Fonts UI.

For Step 11:

  • ✅ Confirmed "SourceSerif4Variable-Roman.tff.woff2" font file does appear in the browser's Network tab with a 200 status and Type of "font".

See it in action in Scenario1-Step11.gif.

Additional Notes

✅ Also confirmed the CSS matches the stopgap code's generated CSS. They are the same, except for the element's ID as noted in comment:6.

@hellofromTonya
15 months ago

Test Report Scenario 2 Step 3: shows the generated CSS on the front-end of a classic site

#9 @hellofromTonya
15 months ago

Scenario 2 Test Report

Testing Instructions: comment:7

Patch tested: https://github.com/WordPress/wordpress-develop/pull/5051

Environment

  • OS: macOS
  • Localhost: wp-env Docker
  • PHP: 7.4.33
  • WordPress: trunk
  • Browser: Firefox and Chrome
  • Theme: Twenty Twenty-One (TT1)
  • Active Plugins:

Actual Results

For Step 3,

  • ✅ Confirmed <style id="wp-fonts-local"> element is in the main document's head.
  • ✅ Confirmed the <style id="wp-fonts-local"> element contains the expected CSS.
<style id="wp-fonts-local">
@font-face{font-family:"Playfair Display";font-style:normal;font-weight:200 900;font-display:fallback;src:url('http://localhost:8889/wp-content/plugins/font-face-tester/assets/fonts/PlayfairDisplay-VariableFont_wght.ttf') format('truetype');}
@font-face{font-family:"Playfair Display";font-style:italic;font-weight:200 900;font-display:fallback;src:url('http://localhost:8889/wp-content/plugins/font-face-tester/assets/fonts/PlayfairDisplay-Italic-VariableFont_wght.ttf') format('truetype');}
</style>

See the results in Scenario2-Step3.png.

Additional Notes

✅ Works as expected.

@hellofromTonya commented on PR #5051:


15 months ago
#10

Need to merge https://github.com/WordPress/gutenberg/pull/53805 to use wp_get_global_settings() instead of the private API. Commit will be pushed shortly.

This ticket was mentioned in Slack in #core by hellofromtonya. View the logs.


15 months ago

@hellofromTonya commented on PR #5051:


15 months ago
#12

One broader nit-pick, I'm not sure about the file organization of the new files, I think all the nested folders are unnecessary and don't fit well with the way core typically organizes files. I would instead advise the following structure:

wp-includes/fonts directory for the new classes (no additional subdirectories)
wp-includes/fonts.php file for the global function(s)

Hello @felixarntz 👋 Thank you for your review!

The thinking around the file organization is to group the different fonts management components in sub-directories, which as of today is Font Face and Font Library. There's a mix of approaches in Core, though predominately there is as you note a tendency to group all like files in the "group" folder, rather than sub directories.

I'm okay with either approach. When Font Library lands, it would also go into the wp-includes/fonts/ directory too.

@hellofromTonya commented on PR #5051:


15 months ago
#13

@felixarntz commit https://github.com/WordPress/wordpress-develop/pull/5051/commits/e2db981bc075cc27769f202fd2133ce1388c0de7 relocates the wp-includes/fonts/font-face files into its root wp-includes/fonts/ per your suggestion ✅

@flixos90 commented on PR #5051:


15 months ago
#14

@hellofromtonya Thank you for the updates, also for updating the file/folder structure. What about moving the functions file fonts.php directly into wp-includes, i.e. wp-includes/fonts.php? I think that ties in better with how Core organizes files, it is common to have general global function files in there and then specific classes for a feature in a directory. For example, that is similarly handled for the REST API, which uses wp-includes/rest-api.php for functions and the wp-includes/rest-api directory for classes.

#15 @antonvlasenko
15 months ago

Test Report: Scenario 1

Testing instructions: https://core.trac.wordpress.org/ticket/59165#comment:5

Environment

  • WordPress: 6.4-alpha-56267-src
  • PHP: 7.3.33
  • Server: Apache/2.4.57 (Unix) PHP/7.3.33
  • Database: mysqli (Server: 5.7.43 / Client: mysqlnd 5.0.12-dev)
  • Browser: Safari 16.6 (macOS)
  • Theme: Twenty Twenty-Three 1.2
  • MU-Plugins: None activated
  • Plugins:
    • None.

Actual Results

  • ✅ Step 5 works as expected with patch.
  • ✅ Step 9 works as expected with patch.
  • ✅ Step 10 works as expected with patch.
  • ✅ Step 11: In my tests, the site behaves differently in Chrome versus Safari. In Safari, no additional fonts are loaded when I change the font to Source Serif Pro. Also, there are about 14 requests to load the Source Serif Pro font before I change the font. In Chrome, everything works as expected. I tested this on the trunk branch, and the behavior is consistent. Thus, it seems this issue isn't related to this PR.

Screenshots

Chrome:
https://cldup.com/qUzk6bW_S0.png
Safari:
https://cldup.com/xgUhwZxhok.png

Last edited 15 months ago by antonvlasenko (previous) (diff)

#16 @antonvlasenko
15 months ago

Test Report: Scenario 2

Testing Instructions: https://core.trac.wordpress.org/ticket/59165#comment:7

Environment

  • WordPress: 6.4-alpha-56267-src
  • PHP: 8.0.30
  • Server: Apache/2.4.57 (Unix) PHP/8.0.30
  • Database: mysqli (Server: 5.7.42 / Client: mysqlnd 8.0.30)
  • Browser: Safari 16.6 (macOS)
  • Theme: Twenty Twenty-One 1.9
  • MU-Plugins: None activated
  • Plugins:
    • Font Face Tester 1.0.0

Actual Results

  • ✅ Step 3 works as expected with patch.
Last edited 15 months ago by antonvlasenko (previous) (diff)

#17 @hellofromTonya
15 months ago

  • Keywords commit added

After a thorough code review process (thank you @costdev @antonvlasenko @flixos90), https://github.com/WordPress/wordpress-develop/pull/5051 has multiple approvals and is ready for commit.

#18 @ironprogrammer
15 months ago

  • Keywords has-screenshots added

Test Report: Scenario 1

Patch tested: https://github.com/WordPress/wordpress-develop/pull/5051 👍

Environment

  • Hardware: MacBook Pro Apple M1 Pro
  • OS: macOS 13.5.1
  • Browser: Safari 16.6, Google Chrome 116.0.5845.140
  • Server: nginx/1.25.2
  • PHP: 8.2.9
  • WordPress: 6.4-alpha-56267-src
  • Theme: twentytwentythree v1.2
  • Active Plugins: none

Actual Results

  • ✅ Step 5: results as expected.
  • ✅ Step 9: results as expected.
  • ✅ Step 10: works as expected.
  • ✅ Step 11: result as expected in site editor. Also validated on site frontend.

Additional Notes

  • As noted in comment:15, Safari appears to load already cached fonts referenced in #wp-fonts-local. With a cleared browser cache, changing the font under Styles > Typography behaved similar to Chrome, by only loading the newly-assigned font.
  • For transparency, I've modified the expected count of DM Sans variations from 3 to 4 in the test instructions provided in comment:5.
Last edited 15 months ago by ironprogrammer (previous) (diff)

#19 @ironprogrammer
15 months ago

Test Report: Scenario 2

Patch tested: https://github.com/WordPress/wordpress-develop/pull/5051 👍

Environment

  • Hardware: MacBook Pro Apple M1 Pro
  • OS: macOS 13.5.1
  • Browser: Safari 16.6, Google Chrome 116.0.5845.140
  • Server: nginx/1.25.2
  • PHP: 8.2.9
  • WordPress: 6.4-alpha-56267-src
  • Theme: twentytwentyone v1.9
  • Active Plugins: font-face-tester v1.0.0

Actual Results

  • ✅ Works as expected in the site admin* and frontend for classic themes.

* Excludes the iframed editor, which presently only supports theme.json data.

Additional Notes

  • Also validated that "Playfair Display" is assignable via font-family CSS (tested directly in DevTools' Elements inspector).
Last edited 15 months ago by ironprogrammer (previous) (diff)

#20 @hellofromTonya
15 months ago

  • Resolution set to fixed
  • Status changed from accepted to closed

In 56500:

Introduce font-face styles generator and printer.

Introducing Font Face, a server-side @font-face styles generator and printer.

tl;dr:

  • Introduces Font Face.
  • Deprecates _wp_theme_json_webfonts_handler().

Introduce Font Face

From an array of fonts (i.e. each font-family and its font variations to be processed), it:

  1. Validates each font-face declaration, i.e. the CSS property and value pairing. If validation fails, processing stops with no font-face styles printed.
  2. Generates the @font-face CSS for each font-family.
  3. Prints the CSS within a <style id="wp-fonts-local"> element.

The entry point into Font Face is through a new global function called wp_print_font_faces(), which is automatically called:

  • when the 'wp_head' hook runs (for the front-end).
  • when the 'admin_print_styles' hook runs (for the back-end).
  • when _wp_get_iframed_editor_assets() runs to inject the @font-face styles into the iframed editor.

Once called, it gets the fonts from Theme_JSON merged data layer, which includes theme defined fonts and user activated fonts (once the Font Library #59166 is introduced into Core).

For classic sites, themes and plugins can directly call wp_print_font_faces() and pass their fonts array to it for processing.

Deprecates _wp_theme_json_webfonts_handler().

As Font Face is a direct replacement, the stopgap code in _wp_theme_json_webfonts_handler() (introduced in 6.0.0 via [53282]) is deprecated and unused in Core.

Props note:
There's a long multiple year history baked into Font Face, which dates back to the early versions of a web font API (see #46370 and roadmap. The props list includes those who contributed from those early versions up to this commit.

References:

Follow-up to [53282].

Props aristath, jonoaldersonwp, hellofromTonya, andraganescu, annezazu, antonvlasenko, arena, askdesign, azaozz, bph, bradley2083, colorful-tones, costdev, davidbaumwald, desrosj, dingo_d, djcowan, domainsupport, dryanpress, elmastudio, flixos90, francina, garrett-eclipse, gigitux, grantmkin, grapplerulrich, gziolo, ironprogrammer, jb510, jeffpaul, jeremyyip, jffng, joostdevalk, jorgefilipecosta, juanmaguitar, mamaduka, matveb, mburridge, mitogh, ndiego, ntsekouras, oandregal, ocean90, oglekler, paaljoachim, pagelab, peterwilsoncc, poena, priethor, scruffian, SergeyBiryukov, shiloey, simison, skorasaurus, soean, westonruter, wildworks, zaguiini.
Fixes #59165.

@hellofromTonya commented on PR #5051:


15 months ago
#21

Committed via https://core.trac.wordpress.org/changeset/53282. Thank you everyone for your contributions!

#22 @hellofromTonya
15 months ago

In 56501:

Tests: Remove webfonts tests.

Removes the test file and webfonts directory for the stopgap code that was deprecated by [56500].

Follow-up to [56500], [53282].

Fixes #59165.

This ticket was mentioned in PR #5159 on WordPress/wordpress-develop by @hellofromTonya.


14 months ago
#23

Removes the static instance in wp_print_font_faces().

Why?

The static instance of WP_Font_Face is not needed. It was originally introduced when a singleton was needed to persist internal data. However, that functionality was previously removed. The remaining static artifact should have also been removed.

Removing the static instance also removes the need to run wp_print_font_faces() tests in separate processes.

Trac ticket: https://core.trac.wordpress.org/ticket/59165

#24 @hellofromTonya
14 months ago

  • Keywords commit removed
  • Resolution fixed deleted
  • Status changed from closed to reopened

Reopening to remove the static instance within wp_print_font_faces(). See https://github.com/WordPress/wordpress-develop/pull/5159.

Ref:

Last edited 14 months ago by hellofromTonya (previous) (diff)

#25 @hellofromTonya
14 months ago

  • Resolution set to fixed
  • Status changed from reopened to closed

In 56540:

Fonts: Removes static instance in wp_print_font_faces().

The static instance of WP_Font_Face is not needed. It was an unnecessary carryover from the experimental Fonts API (which was not introduced into Core).

Whereas the Fonts API needed to persist its data (i.e. to maintain the registered and enqueued fonts throughout the web request), Font Face does not have data to persist.

Font Face processes the fonts it receives when WP_Font_Face::generate_and_print( $fonts ) is invoked. Thus, a singleton is not needed.

Removing the static reduces the amount of the code in the function and eliminates running its tests in separate processes to ensure a different instance is always used.

References:

Follow-up to [56500].

Props hellofromTonya, costdev.
Fixes #59165.

#27 @hellofromTonya
14 months ago

  • Resolution fixed deleted
  • Status changed from closed to reopened

Reopening to merge a bugfix from Gutenberg to get the font-family name from the "fontFamily" field, instead of the "name" field.

Why?

To avoid a back-compatibility (BC) break for themes that do not have the "name" field defined.

WP Core also does not require the "name" field. Using it exclusively is a BC break in Core.

It's not clearly documented that the "name" field is required. Thus, it's been optional.

This ticket was mentioned in PR #5298 on WordPress/wordpress-develop by @hellofromTonya.


14 months ago
#28

Fixes a BC break in how the font-family name is pulled from the incoming font data.

Merge from Gutenberg's PR https://github.com/WordPress/gutenberg/pull/54615.

## What?

Gets the font-family name from the "fontFamily" field, instead of the "name" field.

## Why?
To avoid a back-compatibility (BC) break for themes that do not have the "name" field defined.

WP Core also does not require the "name" setting. Using it exclusively is a BC break.

It's not clearly documented that the "name" setting is required. Thus, it's been optional.

## How?

Uses the font-family's fontFamily field instead of its name field.

As the fontFamily field could be a comma-separated list of font-families, it parses the list to extract the first entry.

### Why fontFamily setting?

WP_Theme_JSON schema requires the fontFamily setting in each of the typography.fontFamilies.

Trac ticket: https://core.trac.wordpress.org/ticket/59165

#29 @ironprogrammer
14 months ago

Test Report

Patch tested: https://github.com/WordPress/wordpress-develop/pull/5298

Steps to Test

Test steps adapted from the original GB PR.

  1. If your test environment has been used to test Gutenberg PRs, check for and delete any rows in the wp_posts table where post_name = 'wp-global-styles-twentytwentythree' to prevent interference from cached global styles.
  2. Activate the Twenty-Twenty-Three (TT3) theme.
  3. In the TT3 theme's directory, open theme.json in an editor and modify it in the following ways, saving the file after each change and checking Step 4:
    • Scroll to line 152 and delete the line: "name": "DM Sans",
    • Change the order of the fonts provided in fontFamily, or add a new one before "DM Sans".
    • Give the name property a different name from "DM Sans".
  4. Refresh the browser, view the HTML, and inspect the #wp-fonts-local style element after each change.

Expected Results

  • ✅ After removing the name property, "DM Sans" remains listed in the #wp-fonts-local element's @font-face definitions.
  • ✅ For fontFamily props containing multiple fonts, only the first one is used in the @font-face definition.
  • ✅ The name prop does not affect the name of the generated @font-face.

Environment

  • Hardware: MacBook Pro Apple M1 Pro
  • OS: macOS 13.5.2
  • Browser: Safari 16.6, Google Chrome 117.0.5938.88
  • Server: nginx/1.25.2
  • PHP: 7.4.33
  • WordPress: 6.4-alpha-56267-src
  • Theme: twentytwentythree v1.2
  • Active Plugins: none

Actual Results

  • ✅ DM Sans was included in #wp-fonts-local.
  • ✅ Only the first comma-delimited value in the fontFamily prop is used for the final @font-face. The value can be double-, single-, or non-quoted.
  • ✅ Specifying a different value for the name prop does not affect the final generated @font-face.

#30 @hellofromTonya
14 months ago

  • Keywords commit added

Thank you @ironprogrammer! Marking https://github.com/WordPress/wordpress-develop/pull/5298 for commit. Prepping it now.

#31 @hellofromTonya
14 months ago

  • Resolution set to fixed
  • Status changed from reopened to closed

In 56688:

Fonts: Get font-family name from 'fontFamily' field.

Instead of getting the name from the optional 'name' field, the font-family name now comes from the required 'fontFamily' field.

This change fixes a back-compat (BC) break in how the font-family name is pulled from the incoming font data in the WP_Font_Face_Resolver.

Why?

WP Core does not require the 'name' field in theme.json. For themes that do not declare it, that set of font variations is ignored, thus causing a BC break from how the stopgap code worked (see [53282]).

However, WP_Theme_JSON schema does require the fontFamily field in each of the typography.fontFamilies.

Other details:

Includes a parser to extract the first entry when a fontFamily field has a comma-separated list of font-families, e.g. Inter, sans-serif.

References:

Follow-up to [56500], [53282].

Props ironprogrammer, hellofromTonya, mmaattiiaass, pbking.
Fixes #59165.

#33 @codente
13 months ago

@hellofromTonya is there a dev note for this?

Is this something for the email to plugin authors which is being collated in Marcomms? This dev note is being tracked in this issue https://github.com/WordPress/Documentation-Issue-Tracker/issues/1164

This ticket was mentioned in Slack in #core by hellofromtonya. View the logs.


13 months ago

#35 @hellofromTonya
13 months ago

  • Keywords needs-dev-note removed

Though introduced in 6.4, I think a dev note would be better for 6.5 when the font management (with Font Library) also ships. Then guidance can be given more holistically for block, hybrid, and classic theme and plugin developers.

In 6.4, it's introduction is to replace the temporary stopgap code. It's real impact comes within a complete font management system. For example, with the Font Library, plugin developers register their fonts with it and do not need to interact with Font Face (as the @font-face styles for activated fonts are automatically generated and printed).

#36 @hellofromTonya
8 months ago

Though introduced in 6.4, I think a dev note would be better for 6.5 when the font management (with Font Library) also ships. Then guidance can be given more holistically for block, hybrid, and classic theme and plugin developers.

Following up on a ping from @leonnugraha as to whether to include Font Face with the Font Library dev note.

No, Font Face, and more specifically wp_print_font_faces(), should (and was) not be included with the Font Library dev note. Why? It's not part of the Font Library; rather, it's low-level functionality that works out-of-the-box.

What about classic themes that might want to use wp_print_font_faces()?

My current thinking: The dev docs page should be enough to guide extenders building classic themes. Thus, I'm thinking a dev note specifically for classic themes is not needed. However if it is needed, one can be created.

#37 @tskk
5 months ago

Hello,

Not sure if this is the correct place, but is it possible to make this :

<link rel="preload" href="montserrat-v26-latin-700.woff2" as="font" type="font/woff2" crossorigin>

instead of

@font-face{font-family:Montserrat;font-style:normal;font-weight:900;font-display:fallback;src:url('montserrat-v26-latin-900.woff2') format('woff2');}

because @font-face is causing CLS problems in PageSpeed test.

Thanks,
Srikanth

#38 @ironprogrammer
4 months ago

Thanks for the question, @tskk!

Because this update shipped with WordPress 6.4, I would recommend opening a new enhancement ticket (performance focus) here in Trac where, e.g. a preload option or the possibility of changing the default font-display strategy can be explored. In the new ticket if you could provide concrete examples where the current implementation causes correctable CLS, all the better!

Note: See TracTickets for help on using tickets.