Automattic / Automattic/jetpack

Google Fonts (Beta) module disables core wp_print_font_faces() and drops/overrides theme.json fonts on the front end

Open
#50,180 1 comment 0 reactions 1 assignee Assigned to @arthur791004 View on GitHub
Bug Needs triage
Dominant language
PHP
Stars
1.8k
Forks
898
Avg merge
1d 18h
Merged PRs (30d)
774

Description

### 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`:

1. **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.
2. 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

1. Block theme registers a font in `theme.json` with a bundled `fontFace` (`src: ["file:./…/InterVariable.woff2"]`, slug `inter`).
2. Reference it in `styles` **with a fallback stack**:
```json
"styles": {
"typography": {
"fontFamily": "var(--wp--preset--font-family--inter), system-ui, sans-serif"
}
}
```
3. 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 Image |
| OFF | core `wp-fonts-local` prints the theme's `InterVariable` faces, font restored Image |

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 |
| ----------- | ----------- |
| Image | Image |

## 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`:
```php
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 `)`:
```php
// get_font_slug_from_setting()
preg_match( '/font-family--(?P.+)\)$/', $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--)` 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

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.