Originally published on my blog
Introduction
Recently I’ve been working on Morse, a WordPress theme custom-built for small newspapers, drawing on my experience building and then maintaining The Phillipian’s website for a year. I wanted this theme to be highly customizable, able to easily accomodate any paper’s branding and maybe even The Phillipian’s one day. A big part of this is allowing users to specify what fonts they want to be used.
To start, it would just be Google Fonts. Good variety, hopefully easy to implement. The vision was that a user could go to the Customizer interface in WordPress, plug in a font name, and watch the preview update to use that font where applicable, then publish it and have their changes go live.
Honestly, this was one of the features I was most intimidated by. I’ve worked a fair bit with WordPress and PHP, and with JavaScript, but never in combination. I looked through the source code of open-source plugins and themes that had already implemented Google Fonts integration and got lost in their endless includes and complexities, not even knowing where to find the code that mattered.
This morning, though, I managed to figure it out, implementing exactly what I wanted with way simpler code than expected! To solidify my own learning (learn, build, share, repeat) and to share this knowledge with anyone else who might want to implement the same functionality in their WordPress theme, I’ve created this post as a little tutorial of my solution.
WP Customizer
First, let’s create fields in the customizer to allow users to specify fonts. For simplicity, I implemented these as straightforward string fields: users will have to browse through fonts beforehand and enter the exact name. Google Fonts does have an API for getting a list of all available fonts, and some WordPress plugins have implemented fancy lists
We’ll add three different fields: a body font, a heading font, and an accent font (for the occassional button, label, etc.; obviously you can make these options whatever you want). This is straightforward to implement:
function morse_wp_plugin_customizer($wp_customize)
{
$wp_customize->add_section('morse-wp-custom-section', array(
'title' => "Morse WP Theme Overall Settings"
));
$wp_customize->add_setting('morse-wp-font-body');
$wp_customize->add_control('morse-wp-font-body-control', array(
'label' => 'Google Font for Body',
'type' => 'string',
'section' => 'morse-wp-custom-section',
'settings' => 'morse-wp-font-body'
));
$wp_customize->add_setting('morse-wp-font-heading');
$wp_customize->add_control('morse-wp-font-heading-control', array(
'label' => 'Google Font for Headings',
'type' => 'string',
'section' => 'morse-wp-custom-section',
'settings' => 'morse-wp-font-heading'
));
$wp_customize->add_setting('morse-wp-font-accent');
$wp_customize->add_control('morse-wp-font-accent-control', array(
'label' => 'Google Font for Accents',
'type' => 'string',
'section' => 'morse-wp-custom-section',
'settings' => 'morse-wp-font-accent'
));
}
add_action('customize_register', 'morse_wp_plugin_customizer');
Utility Classes
In a template PHP file, we can now access these customizer settings using get_theme_mod()
, for example get_theme_mod(
"
morse-wp-font-heading
"
, "Georgia")
to get the heading font, with a default of Georgia if the option has not been set by the user. Now, how do we get this into our CSS?
The trick here is to use utility classes instead of trying to write dynamic fonts into semantic CSS. Instead of specifying that .article-title h1
should have our heading font, we specify a utility class .morse-font-heading
that we can apply to any element we want our heading font on. Instead of trying to insert snippets into or overwrite various parts of a stylesheet, then, we can simply add our utility classes in an inline style block using the wp_head
hook:
function morse_wp_plugin_add_styles(){ ?>
<style>
.morse-font-body{
font-family: <?php echo get_theme_mod("morse-wp-font-body", "Georgia"); ?>
}
.morse-font-heading{
font-family: <?php echo get_theme_mod("morse-wp-font-heading", "Georgia"); ?>
}
.morse-font-accent{
font-family: <?php echo get_theme_mod("morse-wp-font-accent", "sans-serif"); ?>
}
</style>
<?php
}
add_action("wp_head","morse_wp_plugin_add_styles");
Note: above is only a snippet of the add_styles
function I actually use. The same approach can be applied to implementing user-specified colors, for example, which I might write about later.
Web Font Loader
The last step, and the one that confused/intimidated me for a little bit, was how to actually load these fonts from Google Fonts. Google Fonts has a JavaScript Web Font Loader library/API that allows fonts to be dynamically loaded, but I’ve never connected WordPress functionality with JavaScript before. It’s something I’ll have learn eventually, especially with Gutenberg blocks being React-based. In this case, though, I was able to figure out a straightforward solution, based on this tutorial:
First, download the Web Font Loader library. Throw that JS file somewhere in your plugin or theme, and enqueue it like any other script.
Now, all we need to do is run WebFont.load()
with our desired parameters to load in our fonts. Web Font Loader’s GitHub provides documentation on what these parameters look like, but here’s a quick example:
WebFont.load({
google: {
families: ["Roboto:400,700", "Roboto Mono"]
}
});
Pretty easy, right? WordPress allows us to easily insert inline scripts using wp_add_inline_script
, which we can include right after we enqueue the Web Font Loader library. All we have left to do, then, is generate the parameters to call based on our Customizer settings. This just takes some simple PHP. First, I create an array of fonts with array_unique([get_theme_mod("morse-wp-font-body"), get_theme_mod("morse-wp-font-heading"), get_theme_mod("morse-wp-font-accent")])
— array_unique
making sure I don’t duplicate-request fonts — then turn this into the specific format that the loader wants with a for loop and some string concatenation. For now, I just specified 400 and 700 weights (regular and bold), though it’s only a matter of busiwork if you wanted to allow user-specified weights as well.
Here’s how it all comes together:
function morse_wp_enqueue_fonts(){
wp_enqueue_script( 'webfontloader', plugin_dir_url( __FILE__) . "../js/webfontloader.js", NULL, '', true );
$fonts_array = array_unique([get_theme_mod("morse-wp-font-body"), get_theme_mod("morse-wp-font-heading"), get_theme_mod("morse-wp-font-accent")]);
$fonts_string = "";
foreach ($fonts_array as $f){
$fonts_string = $fonts_string . "\"" . $f . ":400,700\",";
}
$config_string = "
WebFont.load({
google: {
families: [
" . $fonts_string . "
]
}
});
";
wp_add_inline_script( 'webfontloader', $config_string, 'after' );
}
add_action("wp_enqueue_scripts", "morse_wp_enqueue_fonts");
And We’re Done!
And there we have it, an easy-to-implement, easy-to-extend solution for loading user-specified Google Fonts into your WordPress theme. There’s a lot more to look into — here are a few ideas:
- Dropdown list of potential fonts
- User-specified font weights
- User-uploaded custom fonts
But, honestly, I thought this feature was gonna be really hard to build, and it turned out to be surprisingly simple, and highly functional for its simplicity. No plugins, no jank hacks going against WordPress’ design, just a few straightforward lines of code.
Find the full source code for the Morse theme and theme-specific plugin (where the code from this tutorial is located) on my GitHub, and let me know what you think of this solution through Twitter (@wwsalmon) or in the comments of this post!
Top comments (1)
good day dear Samson,
many thank you so much for spending your time creating and posting this article.
i just found your article and i like it. The way you talk about user selected fonts.
Many thanks for the article it is just great!! It looks very promising and your thoughts regarding the usage user-selected fonts are interesting. Many thanks for your inspiring ideas.
i am currently working on some issues - that have to do with the CSS and google fonts.
to begin with the beginning:i have found out that my wordpress-site fetches two google fonts:
one of them is montserrat
i decided to host them locally. so i have to
a. fetch the fonts
b. correct the css code
with the following tool i fetch them
google-webfonts-helper.herokuapp.c...
here i have the option to add the paths - to customize the path in the css-data
/* montserrat-regular - latin / u/font-face { font-family: 'Montserrat'; font-style: normal; font-weight: 400; src: url('../fonts/montserrat-v25-latin-regular.eot'); / IE9 Compat Modes / src: local(''), url('../fonts/montserrat-v25-latin-regular.eot?#iefix') format('embedded-opentype'), / IE6-IE8 / url('../fonts/montserrat-v25-latin-regular.woff2') format('woff2'), / Super Modern Browsers / url('../fonts/montserrat-v25-latin-regular.woff') format('woff'), / Modern Browsers / url('../fonts/montserrat-v25-latin-regular.ttf') format('truetype'), / Safari, Android, iOS / url('../fonts/montserrat-v25-latin-regular.svg#Montserrat') format('svg'); / Legacy iOS */ } Customize folder prefix (optional):
and now i have to add a path to set the correct path - (that means to customize the path )
../fonts/
some additional thought: what makes me wonder is the fact that some of the examples show full paths as reference - others dont:
see the following examples;
a. wp-ninjas.de/wordpress-google-font...
url("https://wp-ninias.de/fonts/muilti-latin-300.woff2") format (
url("https://wp-ninias.de/fonts/muilti-latin-300.woff") format (
b. pixelgrade.com/docs/advanced-custo...
Copy the URL Path field and paste it before each URL in the Embed Code field. The example code will look like this:
@font-face {
font-family: 'Name of the font';
src: url('http://yourwebsite.com/wp-content/uploads/fonts/11148/name-of-the-font-file.woff2') format('woff2'),
url('http://yourwebsite.com/wp-content/uploads/fonts/11148/name-of-the-font-file.woff') format('woff');
}
c. themeisle.com/blog/custom-fonts-wo...
Once the file is in place, open up your child theme’s stylesheet. Now you’ll need to call on that font so you can use it, via a snippet that should look like this:
`
@font-face {
font-family: New Font;
src: url(yourwebsite.com/wp-content/themes/...);
font-weight: normal;
}
`
and now compare it with the following example here:
Code:
/* montserrat-regular - latin */
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 400;
src: url('../fonts/montserrat-v25-latin-regular.eot'); /* IE9 Compat Modes */
src: local(''),
url('../fonts/montserrat-v25-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('../fonts/montserrat-v25-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */
url('../fonts/montserrat-v25-latin-regular.woff') format('woff'), /* Modern Browsers */
url('../fonts/montserrat-v25-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */
url('../fonts/montserrat-v25-latin-regular.svg#Montserrat') format('svg'); /* Legacy iOS */
see the helper-tool google-webfonts-helper.herokuapp.c...
the question: so the question is: how to set the path correct for the CSS... which path should we use here!?
Dear Samson, i look forward to hear from you