Skip to content

Google Fonts: preserve native sources and trim frontend catalogue work - #52653

Merged
mreishus merged 10 commits into
trunkfrom
fix/google-fonts-native-font-faces
Sep 30, 2026
Merged

mreishus merged 10 commits into
trunkfrom
fix/google-fonts-native-font-faces

Conversation

@mreishus

@mreishus mreishus commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor

Human Desc

Big Picture.

Jetpack Google Fonts is an older module with planned retirement that lets users use a wide range of fonts. It came before core WordPress's official Font Library added to WP 6.5 in 2024. It works by injecting 60 font-families (comprising of 706 font faces) into the theme json's default origin, which is a lot of data.

When profiling front-end renders on sites with this enabled, Gutenberg processing the 706 fonts with sanitizing and merging, comes up as one of the longest executing filters - somewhere in the 10-20ms range. The goal of this PR is to lessen this processing, but without losing any fonts that sites use, and fixing duplicated font faces in CSS.

The old way of doing it:

The new way of doing it:

  • Before registering fonts, most of the time, we unset( $font_family['fontFace'] ); which stops the font face from going into theme json data where it has to be processed by Gutenberg. We only add name, slug, and fontFamily, which is ~60 entries.
    • On admin, rest requests, cli, we continue to provide all fontFaces. There's also a filter you can use to opt-in.
  • Gutenberg now only handles 60 smaller entries instead of 706 font faces.
  • We leave the core font printer on.
  • We also run our own printer, that does lookups and only converts the faces that are actually in use and not already provided by the theme or user.

When testing the front-page render of one of my testing sites, it moved the number of PHP function calls executed from 274k -> 267k. I also have some TTFB times down in the PR comments.

I've also done a manual test of 6 different types of themes and sites across (Simple, Jetpack, Atomic) and (Trunk, This PR). See PR comments below.

We're doing 3 things:

(1) Stop turning off Gutenberg's font printer

OLD

remove_action( 'wp_head', 'wp_print_font_faces', 50 );
remove_action( 'wp_head', 'gutenberg_print_font_faces', 50 );

NEW

remove_action( 'wp_head', 'wp_print_fonts', 50 );
// let wp_print_font_faces and gutenberg_print_font_faces run

This is safe to do because our (2) change next, removes the fontFaces, meaning they won't all be printed.

(2) Lighter font presets on the front-end

When filling out the list of fonts in load-google-fonts.php, the front-end only needs name, slug, and fontFamily. We can remove a lot of data and only load it in the editor (and also customizer, REST API and CLI):

$load_font_faces = jetpack_google_fonts_load_font_faces();
foreach ( $google_fonts_families as $font_family ) {
    if ( ! $load_font_faces ) {
        unset( $font_family['fontFace'] );  // Strip the heavy face data
    }
    $raw_data['settings']['typography']['fontFamilies'][ $origin ][] = $font_family;
}

(3) Let our print_font_faces() respect other sources

For each font family in the catalog, check first:

  • If there's a theme/user definition for the font, skip, and let the core printer print it.
  • If there's a preset that remaps this slug to a different family, then skip it.
  • If the font isn't actually used by global styles or blocks, then skip it.
  • Only print if we've passed all these checks (Meaning no one else is taking care of it and it's in use).

Note that if the theme or user font is missing a weight or a style (like italic), then the catalogue version should fill in those gaps.

AI Desc (Codex, Astra 6)

Proposed changes

When the Google Fonts module is active, its printer replaces Core/Gutenberg font printing and applies legacy usage detection to every font. This can omit native fonts and emit catalogue sources alongside a theme's bundled version of the same family.

Keep Core/Gutenberg responsible for native theme and user fonts. On ordinary frontend requests, register the catalogue's presets without their fontFace arrays, then convert and print only the legacy catalogue families detected in use. Native sources take precedence by family, and a preset that replaces a catalogue family takes precedence by slug.

Preserve older themes that declare a family or alias without font files: those presets can still use catalogue files. Keep full catalogue metadata for admin, REST/JSON, Customizer and CLI contexts, and preserve the full-data getter used by preview consumers.

Add regression tests for native collisions, aliases, system-font replacements, block-only selections, catalogue filtering, missing data, editor metadata and head/footer ordering. Include generated Gutenberg declarations for static analysis.

Related product discussion/links

Does this pull request change what data or activity we track or use?

No.

Testing instructions

  1. Enable the Google Fonts module and use a block theme with a bundled font also present in the catalogue, such as Inter in Twenty Twenty-Four. Check page-source @font-face rules: the theme's local font should be present without competing catalogue sources. Native fonts should print even when used only through CSS or a style location outside Jetpack's legacy detector.
  2. Also check italics on a theme that bundles only upright faces, like Plus Jakarta Sans in texty - do we still load the real italic font or is the browser making the italic version?
  3. Select a different catalogue-only font through global styles, including a fallback stack. Confirm it renders and unused catalogue families have no @font-face rules. Repeat with a font selected only on a block.
  4. Repeat with a classic theme. The catalogue font selected on a block should print in the footer; native fonts should keep their native printing path. With Gutenberg active, verify a user-installed font on a classic theme as well.
  5. Check a legacy theme preset that names a catalogue family without a fontFace, both with the catalogue slug and a custom alias. It should still load the catalogue font. Replacing the catalogue slug with system-ui should not download the old font.
  6. Open the editor and check font previews and selection. Verify the font catalogue remains available through the editor's REST requests and template previews.
  7. Run the PHP tests in tests/php/modules/google-font-face.

Local validation (PHP 8.4.11 / WordPress 7.2-alpha-63394):

  • Core-only module integration suite: 46 passed, 108 assertions; one Gutenberg-specific test skipped.
  • Gutenberg 23.9 + multisite: 47 passed, 110 assertions, including actual block rendering and head/footer actions.
  • PHPCS and git diff --check: passed.
  • Targeted Phan analysis of the changed source and tests: passed using the polyfill parser and installed PHPUnit 11 declarations (the checkout's PHPUnit 12 stubs do not resolve correctly with this local parser).

These integration runs load real WordPress and, where noted, Gutenberg through a focused test bootstrap. The full Jetpack bootstrap was also attempted, but this checkout cannot load Automattic\Jetpack\Assets\Shared_Stores_Assets. CI and the site/editor smoke test remain to be checked. No new end-to-end performance measurement is claimed by this PR.

WP.COM Simple Front-end font checks (Simple site with this branch; view page source)

Theme fonts print in <style id='wp-fonts-local'> (core/Gutenberg). Catalogue fonts print in <style class="wp-fonts-local"> with fonts.wp.com URLs (Jetpack; in the footer on classic themes). Add a post with some italic and bold text to each test.

  1. Italics filled in — loudness: the theme ships DM Mono (body) upright only and Rubik (headings) at 400/500. Expect catalogue DM Mono 300/500 and italics, Rubik 300 and 600–900 and all italics, and no catalogue copies of the theme's own faces. Italic text should be a real italic, not slanted upright.
  2. Missing weights filled in — message: the theme ships Inter 400/700. Expect catalogue Inter 100–300, 500, 600, 800 and 900 only. (The catalogue has no Inter italics, so italics stay synthesized, as they do without Jetpack.)
  3. Full set, nothing added — strand (Newsreader and Plus Jakarta Sans with italics): expect no Jetpack wp-fonts-local block at all.
  4. Legacy preset without files — twentytwentytwo-swiss (Inter preset, no fontFace): expect catalogue Inter faces and no theme faces.
  5. Style variation — twentytwentytwo, switch to the Blue variation (DM Sans 400/700 with italics): expect only the missing DM Sans weights from the catalogue.
  6. Classic theme — twentyseventeen: pick a catalogue font (e.g. Lora) on one paragraph. Expect that family's catalogue faces in the footer, and no other catalogue families.
  7. Editor — font previews in the Styles panel and the block font picker still show the catalogue fonts.

Comment thread .phan/stubs/gutenberg-stubs.php
@github-actions

github-actions Bot commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor

Are you an Automattician? Please test your changes on all WordPress.com environments to help mitigate accidental explosions.

  • To test on WoA, go to the Plugins menu on a WoA dev site. Click on the "Upload" button and follow the upgrade flow to be able to upload, install, and activate the Jetpack Beta plugin. Once the plugin is active, go to Jetpack > Jetpack Beta, select your plugin (Jetpack), and enable the fix/google-fonts-native-font-faces branch.
  • To test on Simple, run the following command on your sandbox:
bin/jetpack-downloader test jetpack fix/google-fonts-native-font-faces

Interested in more tips and information?

  • In your local development environment, use the jetpack rsync command to sync your changes to a WoA dev blog.
  • Read more about our development workflow here: PCYsg-eg0-p2
  • Figure out when your changes will be shipped to customers here: PCYsg-eg5-p2

@github-actions github-actions Bot added [Feature] Google Fonts [Plugin] Jetpack Issues about the Jetpack plugin. https://wordpress.org/plugins/jetpack/ [Status] In Progress [Tests] Includes Tests labels Sep 22, 2026
@github-actions

github-actions Bot commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor

Thank you for your PR!

When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:

  • ✅ Include a description of your PR changes.
  • ✅ Add a "[Status]" label (In Progress, Needs Review, ...).
  • ✅ Add testing instructions.
  • ✅ Specify whether this PR includes any changes to data or privacy.
  • ✅ Add changelog entries to affected projects

This comment will be updated as you work on your PR and make changes. If you think that some of those checks are not needed for your PR, please explain why you think so. Thanks for cooperation 🤖


Follow this PR Review Process:

  1. Ensure all required checks appearing at the bottom of this PR are passing.
  2. Make sure to test your changes on all platforms that it applies to. You're responsible for the quality of the code you ship.
  3. You can use GitHub's Reviewers functionality to request a review.
  4. When it's reviewed and merged, you will be pinged in Slack to deploy the changes to WordPress.com simple once the build is done.

If you have questions about anything, reach out in #jetpack-developers for guidance!


Jetpack plugin:

The Jetpack plugin has different release cadences depending on the platform:

  • WordPress.com Simple releases happen as soon as you deploy your changes after merging this PR (PCYsg-Jjm-p2).
  • WoA releases happen weekly.
  • Releases to self-hosted sites happen monthly:
    • Scheduled release: October 6, 2026

If you have any questions about the release process, please ask in the #jetpack-releases channel on Slack.

@github-actions github-actions Bot added the [Status] Needs Author Reply We need more details from you. This label will be auto-added until the PR meets all requirements. label Sep 22, 2026
@jp-launch-control

jp-launch-control Bot commented Sep 22, 2026 •

Copy link
Copy Markdown

Code Coverage Summary

Coverage changed in 2 files.

File Coverage Δ% Δ Uncovered
projects/plugins/jetpack/modules/google-fonts/current/class-jetpack-google-font-face.php 129/133 (96.99%) 12.66% -9 💚
projects/plugins/jetpack/modules/google-fonts/current/load-google-fonts.php 59/119 (49.58%) 49.58% -47 💚

Full summary · PHP report · JS report

@mreishus
mreishus force-pushed the fix/google-fonts-native-font-faces branch 4 times, most recently from c56c98b to ec54f43 Compare September 23, 2026 19:47
@mreishus
mreishus marked this pull request as ready for review September 23, 2026 19:47
@mreishus
mreishus force-pushed the fix/google-fonts-native-font-faces branch from 27ca8c3 to 6227a3f Compare September 23, 2026 21:06
@mreishus

mreishus commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor Author

I had AI compile my testing notes. But I did this testing manually by visiting the sites and taking notes in a txt file. All looked good across a variety of themes and (simple, jetpack, atomic) on each.

Testing notes:
Counts are @font-face rules on the front end. "Theme" = files shipped by the theme; "catalogue" = Jetpack catalogue files (fonts.wp.com on WordPress.com and Atomic, fonts.gstatic.com on standalone Jetpack). Counts leave out one Ctrl-F match from Jetpack Beta's admin-bar branch name.

WordPress.com Simple

Trunk = production. PR = sandbox with this branch and the WordPress.com filter. On the sandbox, theme files are served from the site instead of s0.wp.com; that is sandbox behaviour and does not happen in production.

Theme Setup Trunk PR Change
loudness DM Mono 400 and Rubik 400/500 upright only 23 (20 catalogue + 3 theme) 20 (3 theme + 17 catalogue) Catalogue copies of the theme's faces removed; italics and other weights still come from the catalogue
message Inter 400/700 11 (9 catalogue + 2 theme) 9 (2 theme + 7 catalogue) Duplicate 400/700 removed
strand Full upright and italic sets 56 (28 catalogue + 28 theme) 28 (theme) All duplicates removed
twentytwentytwo-swiss Inter preset without files 9 (catalogue) 9 (catalogue) Unchanged
twentytwentytwo Blue variation, DM Sans 400/700 with italics 22 (18 catalogue + 4 theme) 18 (4 theme + 14 catalogue) Duplicate 400/700 removed
twentyseventeen (classic) Lora on one paragraph 8 (catalogue) 8 (catalogue) Unchanged

Standalone Jetpack (Jurassic Ninja)

Trunk = Jetpack 16.3-a.3 through Jetpack Beta. No Gutenberg plugin, so every block is <style class="wp-fonts-local">.

Theme Setup Trunk PR Change
Twenty Twenty-Four Default 13 (9 catalogue + 4 theme) 6 (4 theme + 2 catalogue) Only Inter 100/200 added from the catalogue
Twenty Twenty-Two Blue 22 (18 catalogue + 4 theme) 18 (4 theme + 14 catalogue) Duplicate 400/700 removed
Twenty Twenty-Two Swiss 10 (9 catalogue + 1 theme) 2 (1 theme + 1 catalogue) Only Inter 100 added
Twenty Twenty-Five Default 2 (theme) 2 (theme) Unchanged
Twenty Twenty-Five Literata + Fira Sans typography 68 (34 catalogue + 34 theme) 34 (theme) All duplicates removed
Twenty Twenty-One (classic) Lora on one paragraph 8 (catalogue) 8 (catalogue) Unchanged

Editor font picker and Styles → Typography list the full catalogue on both. With the module off, only theme fonts remain.

WordPress.com Atomic

Same themes and setups as standalone, same results. The Gutenberg plugin is active, so the PR prints theme fonts in <style id='wp-fonts-local'> and catalogue fonts in <style class="wp-fonts-local">.

Theme Setup Trunk PR
Twenty Twenty-Four Default 13 6
Twenty Twenty-Two Blue 22 18
Twenty Twenty-Two Swiss 10 2
Twenty Twenty-Five Default 2 2
Twenty Twenty-Five Literata + Fira Sans 68 34
Twenty Twenty-One (classic) Lora on one paragraph 8 8

WordPress.com theme previews (v1.2 /themes/twentytwentytwo-red)

Font rules in each style variation's inline_css. The regex fix is needed for any font CSS to appear; it will ship separately.

Jetpack WordPress.com filter Regex fix default blue / pink / swiss
trunk no no 0 0 / 0 / 0
trunk yes yes 706 4 / 8 / 1
PR no no 0 0 / 0 / 0
PR yes yes 706 4 / 8 / 1
PR no yes 0 4 / 8 / 1

@mreishus

mreishus commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor Author

Performance

(AI compiled the following perf notes but I did these measurements by hand with my usual methods)

TLDR: About -20ms rendering the front page of both twentytwenty and twentytwentyfour themes, on a stock site on WPCOM simple.


Performance: time to first byte on a WordPress.com Simple sandbox

Method: 600 uncached requests per run to a stock test site on a WordPress.com Simple sandbox, measuring time to first byte (TTFB). Runs alternate trunk / this PR / trunk / this PR. No profiler was running.

Theme Run Trunk p50 PR p50 Trunk p75 PR p75
Twenty Twenty (classic) 1 260.5 ms 235.0 ms 272.4 ms 242.8 ms
2 259.2 ms 239.3 ms 268.3 ms 247.0 ms
Twenty Twenty-Four (block) 1 301.1 ms 282.3 ms 310.7 ms 291.5 ms
2 301.5 ms 282.3 ms 311.5 ms 291.0 ms

Averages of the two runs:

Theme p50 p75
Twenty Twenty (classic) 259.9 → 237.1 ms (−22.7 ms, −8.7%) 270.3 → 244.9 ms (−25.4 ms, −9.4%)
Twenty Twenty-Four (block) 301.3 → 282.3 ms (−19.0 ms, −6.3%) 311.1 → 291.2 ms (−19.9 ms, −6.4%)
  • Repeated runs of the same build agree within about 4 ms, and the gap between trunk and this PR is 19–25 ms in every run.
  • The classic theme benefits even though it uses no catalogue fonts. On trunk, Jetpack's printer converted all 706 catalogue faces before it checked whether any font was in use. On both themes, the catalogue files also no longer go through theme JSON processing.
  • Sandbox times usually overstate a saving compared to production, so expect a smaller absolute saving there. This is two sites and one environment; it is not a production measurement.

@mreishus
mreishus requested a review from jeherve September 23, 2026 22:56
@mreishus

Copy link
Copy Markdown
Contributor Author

@jeherve I know this is big and possibly intimidating, maybe you'd like to take a look? I know you were active in the Google Fonts retirement thread. Basically, here, I'm looking to make ThemeJSON code process less data without breaking anything for people using the module.

@mreishus mreishus self-assigned this Sep 23, 2026

@jeherve jeherve left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This looks good, and tests well. Thank you for the detailed testing instructions; it had been a long while since I looked at that module, I had forgotten everything about it 😅

@mreishus

Copy link
Copy Markdown
Contributor Author

Thank you! I will aim for a Monday deploy.

@mreishus
mreishus force-pushed the fix/google-fonts-native-font-faces branch 2 times, most recently from 8e19c0d to 269f02c Compare September 29, 2026 15:46
mreishus and others added 4 commits September 30, 2026 09:05
Native theme and user font files still take precedence, but only for the
styles and weights they provide. Catalogue faces now fill the gaps, so a
theme that bundles only upright faces keeps real italics instead of
browser-synthesized ones. Faces that overlap a native weight are skipped
so the two sources never compete at the same weight and style.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mreishus and others added 6 commits September 30, 2026 09:05
The google-font-face tests were registered only in the multisite configs,
which CI runs on WordPress trunk jobs alone. Register them in the
single-site configs so every PHP job runs them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…er case

Add `jetpack_google_fonts_load_font_faces` so WordPress.com can force the
full catalogue where it builds cached theme previews. The Customizer
preview frame is an ordinary front-end page, so it no longer loads every
catalogue face; its controls run in wp-admin and keep the full catalogue.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`get_font_slug_aliases()` lost its last caller when the printer started
reading merged settings. The tests share one theme JSON cache helper, and
cover catalogue registration through the resolver and single-quoted
family names as the real catalogue writes them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The printer only handles catalogue faces now, and every catalogue source
is an absolute URL (fonts.gstatic.com, or fonts.wp.com on WordPress.com).
Theme `file:./` sources are native fonts, which core resolves. Only the
old test fixture used `file:./`, so it now uses an absolute URL.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`wp_is_json_request()` matches any Accept header that mentions JSON, such
as axios's default `application/json, text/plain, */*`. A front-end page
requested that way loaded every catalogue face into theme JSON, so the
native printer output about 700 rules, and the page cache could keep that
HTML because it only varies on JSON-only Accept headers. The REST prefix
or `rest_route` argument identifies REST requests from the start, including
when a theme resolves theme JSON before REST_REQUEST is defined.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mreishus
mreishus force-pushed the fix/google-fonts-native-font-faces branch from 269f02c to 42f8560 Compare September 30, 2026 14:06
@mreishus
mreishus merged commit 7608c14 into trunk Sep 30, 2026
101 of 104 checks passed
@mreishus
mreishus deleted the fix/google-fonts-native-font-faces branch September 30, 2026 15:00
@github-actions github-actions Bot removed [Status] In Progress [Status] Needs Author Reply We need more details from you. This label will be auto-added until the PR meets all requirements. labels Sep 30, 2026
@github-actions github-actions Bot added this to the jetpack/16.3 milestone Sep 30, 2026
@github-actions github-actions Bot added the [Status] UI Changes Add this to PRs that change the UI so documentation can be updated. label Sep 30, 2026
@mreishus

Copy link
Copy Markdown
Contributor Author

wp.com 16:04 UTC 9/30

anomiex added a commit that referenced this pull request Oct 1, 2026
Gutenberg 24.1.0 dropped this function, which breaks the stub update
job. Looks like #52653 already dropped the use of it in the actual code,
but left usages behind in tests. Drop it there too, so we can drop it
from the stubs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Feature] Google Fonts [Plugin] Jetpack Issues about the Jetpack plugin. https://wordpress.org/plugins/jetpack/ [Status] UI Changes Add this to PRs that change the UI so documentation can be updated. [Tests] Includes Tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants