Your WordPress theme ships with a default font, and most tutorials reach for a CSS @import to swap in a Google Font. That method is slow, and since a 2022 court ruling it raises a privacy flag too. This DevAnswers guide enqueues the font in functions.php instead, then covers preconnect and GDPR-safe self-hosting.
Before You Start
- A WordPress site you can log into as an administrator.
- A child theme or a site-specific plugin to hold the code, so a theme update can’t erase it. New to this? See how to add code to WordPress.
- A way to edit your theme files: Appearance > Theme File Editor, SFTP, or your host’s file manager.
Why Enqueue Instead of @import?
An @import rule sits inside your CSS, so the browser has to download and parse the stylesheet before it even discovers the font request. That serial chain delays the moment your text can render.
Enqueuing solves this. wp_enqueue_style() is the safe, WordPress-native way to register a stylesheet, and hooking it to wp_enqueue_scripts puts the font <link> in the page <head> early. Despite its name, wp_enqueue_scripts is the correct hook for both scripts and styles on the front end.
Select Your Google Fonts
Open the Google Fonts library, pick a family, and choose only the weights and styles you will actually use. Each extra weight is another file to download. In the “Get embed code” panel, select the <link> option rather than @import, and copy the URL out of the href attribute.
The modern css2 endpoint lets you combine several families in one request by repeating the &family= parameter, and adding &display=swap sets font-display: swap so the browser shows fallback text immediately instead of leaving it invisible while the font loads (a flash of invisible text, or FOIT):
https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;700&family=Roboto+Mono&display=swap
One catch when you enqueue a multi-family URL: if WordPress appends its own ?ver string it re-parses the URL and collapses the duplicate family keys, leaving only one family. Passing null as the version argument, which the snippet below does, skips that step so the combined URL loads every family intact.
Add the Code to functions.php
Add the snippet below to your active theme’s functions.php (or drop the same code into a site-specific plugin), editing through a child theme so an update can’t wipe it. The fourth argument is the part most copied snippets get wrong:
functions.php in a child theme, never the parent. A parent-theme update overwrites the file and your fonts disappear. <?php
// Source: https://devanswers.net/enqueue-google-fonts-to-wordpress-functions-php/
function devans_enqueue_google_fonts() {
wp_enqueue_style(
'devans-google-fonts',
'https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;700&display=swap',
array(),
null
);
}
add_action( 'wp_enqueue_scripts', 'devans_enqueue_google_fonts' );
If your functions.php already opens with <?php, paste only the function and the add_action line, not a second opening tag. Passing null as the version ($ver) stops WordPress appending its own ?ver= query string to the Google URL, which would otherwise bust Google’s own caching. The third argument, array(), says this stylesheet has no dependencies. This example loads one family; drop in the combined multi-family URL from above and it still works, because the version is null.
Reload the front end and view source. You should see the stylesheet in the <head> with a clean URL and no version string:
<link rel='stylesheet' id='devans-google-fonts-css' href='https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;700&display=swap' media='all' />
Apply the Font in Your CSS
Loading the font does not change anything until you reference it. Add the font-family rules to your theme stylesheet, or the correct way, in a properly enqueued custom CSS file:
body {
font-family: 'Open Sans', sans-serif;
}
h1, h2, h3 {
font-family: 'Open Sans', sans-serif;
font-weight: 700;
}
Wrap any font name that contains a space in quotes, and end the stack with a generic fallback such as sans-serif so text still renders if the web font fails to load.
Speed It Up With preconnect
Google serves the CSS from fonts.googleapis.com and the font files themselves from fonts.gstatic.com. A preconnect resource hint tells the browser to open those connections early, before it has parsed the font <link>. The gstatic hint needs the crossorigin attribute because font files are fetched using CORS.
WordPress has a dedicated filter, wp_resource_hints, for adding these tags the right way:
<?php
// Source: https://devanswers.net/enqueue-google-fonts-to-wordpress-functions-php/
function devans_gfonts_preconnect( $urls, $relation_type ) {
if ( 'preconnect' === $relation_type ) {
$urls[] = 'https://fonts.googleapis.com';
$urls[] = array(
'href' => 'https://fonts.gstatic.com',
'crossorigin' => 'anonymous',
);
}
return $urls;
}
add_filter( 'wp_resource_hints', 'devans_gfonts_preconnect', 10, 2 );
Self-Host Your Fonts for Privacy (GDPR)
Every time a visitor loads a page, their browser fetches the font directly from Google’s servers, which sends their IP address to Google. In January 2022 a German court (LG München, case 3 O 17493/20) ruled that embedding Google Fonts via the standard external link constitutes a GDPR violation.
Self-hosting fixes this. When you store the font files on your own server, the browser never makes a third-party request to Google, so no visitor IP is sent to Google. Once you switch, remove the Google Fonts enqueue and the preconnect hints from earlier, or the browser will still open a connection to Google. To do it manually:
- Generate the font files with a tool like the Google Webfonts Helper, choosing the weights and character sets you need.
- Upload the files and the generated CSS into your theme, for example a
/fonts/folder. - Enqueue the local stylesheet with
wp_enqueue_style()exactly as above, swapping the Google URL for your local one.
Using a Block Theme? Use theme.json Instead
Block themes (full-site editing) now ship as the WordPress default, so it is worth knowing the native path. The functions.php enqueue above still works on a block theme, but the cleaner route is to register the font in theme.json, which also makes it selectable in the editor. In WordPress 6.5 and later you can add it through the Font Library in the Site Editor; on 6.0 to 6.4 you register it in theme.json by hand. WordPress’s wp_register_webfonts() helper was added in 6.0 and deprecated in 6.4 (use wp_print_font_faces()), so build new code around theme.json directly.
Troubleshooting
- A second font family won’t load. WordPress appended a
?verstring and collapsed the duplicatefamilykeys when it re-parsed the URL. Passnullas the fourthwp_enqueue_style()argument (as shown above) and the combinedcss2URL loads every family. The old pipe syntax (family=A|B) is the legacy/cssAPI and won’t work here. - The font doesn’t change after editing. You must purge all site-wide caches and perform a hard refresh in your browser; a page or CDN cache is almost always serving the old stylesheet.
- A
?ver=string is appended to the Google URL. Passnullas the fourth argument towp_enqueue_style()so WordPress stops adding its version query string.
Next steps
You now load Google Fonts the fast way, hint the browser to connect early, and have a GDPR-safe self-hosting path when you need it. From here, keep trimming what your theme loads:
- Strip unused core styles with our guide to dequeuing the classic-themes stylesheet.
- Apply the same enqueue discipline to scripts: add a custom JavaScript file the correct way.
Is this safe to use now? Trying to add to my WP site and this seems to be the best way
Yes, I fixed it.
You shouldn’t be adding <?php in the function source code here -_- Just lost my access to wp admin, can't get ftp login until couple of days!!!
Sorry about that. Fixed.