Google Fonts Loader Generator
Enqueue web fonts in WordPress the right way: one request, font-display swap, preconnect hints, and the editor covered as well as the front end.
<?php
/**
* Web fonts.
*/
/**
* Builds the stylesheet URL.
*
* One request for every family: css2 takes repeated family parameters, and
* each extra request costs a round trip before any text can be painted.
*
* @return string
*/
function my_theme_fonts_url() {
$families = array(
'Inter:wght@400;600',
);
// Spaces in a family name are plus signs in the URL.
$families = array_map(
static function ( $family ) {
return str_replace( ' ', '+', $family );
},
$families
);
return 'https://fonts.googleapis.com/css2?family=' . implode( '&family=', $families ) . '&display=swap';
}
/**
* Enqueues the fonts on the front end.
*/
function my_theme_fonts() {
// null version: the URL already carries everything that identifies it,
// and a ?ver= query on a third-party stylesheet only breaks caching.
wp_enqueue_style( 'my-theme-fonts', my_theme_fonts_url(), array(), null );
}
add_action( 'wp_enqueue_scripts', 'my_theme_fonts' );
/**
* Preconnects to both font hosts.
*
* The CSS comes from fonts.googleapis.com and the font files from
* fonts.gstatic.com, which is a second connection and needs crossorigin.
*
* @param array $urls Hints for this relation.
* @param string $relation_type The relation.
* @return array
*/
function my_theme_fonts_preconnect( $urls, $relation_type ) {
if ( 'preconnect' !== $relation_type ) {
return $urls;
}
$urls[] = 'https://fonts.googleapis.com';
$urls[] = array(
'href' => 'https://fonts.gstatic.com',
'crossorigin' => 'anonymous',
);
return $urls;
}
add_filter( 'wp_resource_hints', 'my_theme_fonts_preconnect', 10, 2 );
/**
* Loads the same fonts inside the editor.
*
* Without this the editor renders your content in a different typeface, so
* line lengths and spacing decisions made there do not match the front end.
*/
function my_theme_fonts_editor() {
add_editor_style( my_theme_fonts_url() );
}
add_action( 'after_setup_theme', 'my_theme_fonts_editor' );
Output is valid and updates as you type.
Fix the highlighted fields to update the output.
Load web fonts in WordPress with one request, a sensible font-display, the preconnect hints that actually help, and the editor covered as well as the front end.
How to use
- Decide where the fonts come from. Self-hosting removes a third-party connection, which is faster and avoids the privacy question several EU regulators have raised about Google Fonts.
- List only the weights you use. Each weight is another file, and a family with five weights costs more than the design gains.
- Leave
displayonswap. Text paints immediately in the fallback and swaps when the font arrives, instead of staying invisible. - Keep preconnect on for the CDN. The stylesheet and the font files come from two different hosts, and the second hint needs
crossorigin. - Load the fonts in the editor too, or the typography you tune there will not match what visitors see.
Example
The URL builder, which is where the single-request part comes from:
function acme_fonts_url() {
$families = array(
'Inter:wght@400;600',
'Playfair+Display:ital,wght@0,700;1,700',
);
return 'https://fonts.googleapis.com/css2?family=' . implode( '&family=', $families ) . '&display=swap';
}
Two wp_enqueue_style() calls for two families is two round trips before any styled text appears. One URL with two family parameters is one.
Pitfalls
- A version string on an external stylesheet breaks caching for no benefit. Pass
nullas the version for a CDN URL. font-display: block, the browser default for@font-facewithout the property, hides the text for up to three seconds.swapis almost always the better trade.- Preconnect to
fonts.gstatic.comneedscrossorigin; without it the browser opens a second connection anyway and the hint is wasted. - Preloading every font file delays everything else. Preload the one face used above the fold, or nothing.
- The editor loads its own styles. Without
add_editor_style()the content looks different there, which leads to line-length decisions that do not hold. - Spaces in a family name must be
+in the URL.Playfair Displayfails silently and you get the fallback. - Variable fonts are one file covering a weight range.
[email protected]is often smaller than three static weights. - Google Fonts sets no cookies, but the request still sends the visitor’s IP to a third party, which is the basis of the German court rulings on it.
Compatibility
wp_enqueue_style(), wp_resource_hints and add_editor_style() have been stable since WordPress 4.6 and earlier. The css2 endpoint is the current Google Fonts API and supports variable font ranges and the display parameter. font-display is supported by every current browser. Block themes can also register fonts in theme.json, which is the native path when you are self-hosting. The generated code targets PHP 7.0 and up, and the tool runs entirely in your browser.
Frequently asked questions
Should I self-host?
theme.json font families if you are on a block theme.Why is my text invisible for a moment?
font-display: block, the default. Set swap so the fallback paints immediately.Does a version number matter here?
?ver= only defeats caching.How many weights should I load?
Do I need this in a block theme?
theme.json, which WordPress then loads for you. A CDN font still needs an enqueue.