Impacted plugin
Jetpack
Quick summary
The Google Fonts module is deprecated (WP 6.5+ supports fonts natively) but still ships and, wherever it's active, removes core's native font-face printing and substitutes its own "in-use only" printer. This causes two front-end regressions for themes that register a font via theme.json:
- The font disappears if the font-family usage value includes a fallback stack (
var(--wp--preset--font-family--slug), system-ui, …) instead of a bare var(...) — the in-use scan misses it and prints nothing for that family.
- Even when it "works," the wrong font paints — the module injects its own
fonts.wp.com copy of the same-named family alongside the theme's bundled file: faces, so visitors get Google's hosted version instead of the file the theme ships.
Both render fine in the Site Editor; only the front end is affected, and no warning is emitted.
Steps to reproduce
- Block theme registers a font in
theme.json with a bundled fontFace (src: ["file:./…/InterVariable.woff2"], slug inter).
- Reference it in
styles with a fallback stack:
"styles": {
"typography": {
"fontFamily": "var(--wp--preset--font-family--inter), system-ui, sans-serif"
}
}
- Enable the Google Fonts module; view the front end (logged out / cache bypassed)
Expected: the @font-face prints and the bundled font loads (as core wp_print_font_faces() does when the module is off).
Actual: no @font-face prints for that family; it falls back to a system font.
Site owner impact
More than 60% of the total website/platform users
Severity
Moderate
What other impact(s) does this issue have?
No response
If a workaround is available, please outline it here.
A) Toggle the module, holding theme.json constant (compound usage as above). Isolates the module as the cause:
| Google Fonts module |
Front-end result |
| ON |
0 @font-face, no wp-fonts-local, font gone → system fallback  |
| OFF |
core wp-fonts-local prints the theme's InterVariable faces, font restored  |
Same theme, same theme.json — the font's presence tracks the module exactly.
B) Hold the module ON, vary only the usage value. Isolates the compound-value trigger:
styles…fontFamily usage |
Front-end @font-face |
var(--wp--preset--font-family--inter) (bare) |
11 (9 fonts.wp.com + 2 theme faces) — works |
var(--wp--preset--font-family--inter), system-ui, … (compound) |
0 — system fallback |
C) Font substitution (bare usage, so the font is present; toggle only the module). Even when it "works," the module changes which font paints:
| Module |
Face that paints |
"Handgloves wwiill 12345" @ 60px / wt 300 |
| OFF |
theme's bundled InterVariable.woff2 |
~623px |
| ON |
Jetpack fonts.wp.com Inter (v13 static) |
~691px |
| On |
Off |
 |
 |
Root cause
Jetpack_Google_Font_Face (projects/plugins/jetpack/modules/google-fonts/current/class-jetpack-google-font-face.php) removes core/Gutenberg printing on wp_loaded:
remove_action( 'wp_head', 'wp_print_font_faces', 50 );
remove_action( 'wp_head', 'gutenberg_print_font_faces', 50 );
then prints only fonts detected in use. Slug detection is anchored to a trailing ):
// get_font_slug_from_setting()
preg_match( '/font-family--(?P<slug>.+)\)$/', $font_family, $matches );
A compound value doesn't end in ), so detection fails, the family isn't in $fonts_in_use, and — with core's printer already removed — nothing prints for it. Separately, print_font_faces() emits the module's fonts.wp.com faces for detected families even when the theme already registers that family with a local file: source, so the hosted copy wins over the bundled file.
Suggested fix
Since the module is deprecated in favor of native WP fonts, it should not remove core wp_print_font_faces() on WP ≥ 6.5 — defer to native, or auto-skip when native font support is present. At minimum:
- Make in-use detection tolerant of compound values — parse the leading
var(--wp--preset--font-family--<slug>) token instead of anchoring to )$ (e.g. drop $ / split on ,).
- Fall through to core for theme-registered
file: faces the module doesn't manage, so a detection miss degrades gracefully instead of dropping a shipped font.
- Don't inject a
fonts.wp.com copy for a family the theme already registers with a local file: source.
I noticed this while I'm working on a theme in an Atomic site. Claude help me to write this.
Platform (Simple and/or Atomic)
Simple, Atomic, Self-hosted
Impacted plugin
Jetpack
Quick summary
The Google Fonts module is deprecated (WP 6.5+ supports fonts natively) but still ships and, wherever it's active, removes core's native font-face printing and substitutes its own "in-use only" printer. This causes two front-end regressions for themes that register a font via
theme.json:var(--wp--preset--font-family--slug), system-ui, …) instead of a barevar(...)— the in-use scan misses it and prints nothing for that family.fonts.wp.comcopy of the same-named family alongside the theme's bundledfile:faces, so visitors get Google's hosted version instead of the file the theme ships.Both render fine in the Site Editor; only the front end is affected, and no warning is emitted.
Steps to reproduce
theme.jsonwith a bundledfontFace(src: ["file:./…/InterVariable.woff2"], sluginter).styleswith a fallback stack:Expected: the
@font-faceprints and the bundled font loads (as corewp_print_font_faces()does when the module is off).Actual: no
@font-faceprints for that family; it falls back to a system font.Site owner impact
More than 60% of the total website/platform users
Severity
Moderate
What other impact(s) does this issue have?
No response
If a workaround is available, please outline it here.
A) Toggle the module, holding
theme.jsonconstant (compound usage as above). Isolates the module as the cause:@font-face, nowp-fonts-local, font gone → system fallbackwp-fonts-localprints the theme'sInterVariablefaces, font restoredSame theme, same
theme.json— the font's presence tracks the module exactly.B) Hold the module ON, vary only the usage value. Isolates the compound-value trigger:
styles…fontFamilyusage@font-facevar(--wp--preset--font-family--inter)(bare)fonts.wp.com+ 2 theme faces) — worksvar(--wp--preset--font-family--inter), system-ui, …(compound)C) Font substitution (bare usage, so the font is present; toggle only the module). Even when it "works," the module changes which font paints:
InterVariable.woff2fonts.wp.comInter (v13 static)Root cause
Jetpack_Google_Font_Face(projects/plugins/jetpack/modules/google-fonts/current/class-jetpack-google-font-face.php) removes core/Gutenberg printing onwp_loaded:then prints only fonts detected in use. Slug detection is anchored to a trailing
):A compound value doesn't end in
), so detection fails, the family isn't in$fonts_in_use, and — with core's printer already removed — nothing prints for it. Separately,print_font_faces()emits the module'sfonts.wp.comfaces for detected families even when the theme already registers that family with a localfile:source, so the hosted copy wins over the bundled file.Suggested fix
Since the module is deprecated in favor of native WP fonts, it should not remove core
wp_print_font_faces()on WP ≥ 6.5 — defer to native, or auto-skip when native font support is present. At minimum:var(--wp--preset--font-family--<slug>)token instead of anchoring to)$(e.g. drop$/ split on,).file:faces the module doesn't manage, so a detection miss degrades gracefully instead of dropping a shipped font.fonts.wp.comcopy for a family the theme already registers with a localfile:source.I noticed this while I'm working on a theme in an Atomic site. Claude help me to write this.
Platform (Simple and/or Atomic)
Simple, Atomic, Self-hosted