WordPress Themes Typography Options

Most of the premium themes and many free ones come with typography options these days. This means that the end user is allowed to customize their theme by picking a different font in their theme options. Not only does this give more freedom to the end user, but if done correctly, it gives freedom to child theme developers to extend that given list to include any other fonts, which means that you, as the parent theme developer, shouldn’t even bother shipping your theme with over 200 web fonts available from Google.

Today we’re going to look at one of the many different approaches to providing typography options to the end user and child theme developers. We’ll be using Google Web Fonts as our primary web fonts provider and we’ll also look at how WordPress filters and actions can help you provide an interface to child theme developers, so they can easily hook and modify your list.

Google Web Fonts

Google Web Fonts is only one of the major web typography providers and of course one of the most popular among WordPress themes. Probably because of it’s simplicity and the brand. We picked Google Web Fonts because it’s free, flexible and very easy to use. For example, here’s how you embed the Open Sans family in your stylesheet:

@import url(http://fonts.googleapis.com/css?family=Open+Sans);

And here’s how you actually use it:

body {
    font-family: 'Open Sans', sans-serif;
}

We wrote about using Google Web Fonts back in June as well as an announcement of their second version so I’ll be assuming you’re familiar with the basics. The code snippets shown above have got a pattern, and we’ll use that pattern to create a flexible typography choice in WordPress.

A similar approach can be taken to provide support for other web fonts providers, including commercial ones such as Typekit. But okay, back to WordPress.

Preparing Your Stylesheets

First things first. If you’re working on an existing theme you have to make sure your stylesheets are clean and ready for web typography. If you’re working on a new theme or simply playing around, make sure your stylesheets are clean from the start.

By clean I mean you have to remove all references to existing Google Web Fonts. That’s right, best would be if there were no references to font-family at all. This has to be done because whatever the end-user will pick in their typography options list, will be printed out into the head section of your theme.

Imagine if your stylesheets included a 150kb Lato font family, and the user has picked Open Sans from their list — Lato will not be used so you’re simply burning those 150kb. You can use Chrome’s developer tools or Firebug and the Network tab to see what external references are called.

Ideally you should be able to change the font family of all the elements on your website with just one attribute to the body selector. Of course it sounds easier than it is in reality, and watch out for the code, pre, tt and kb tags too, you don’t want to apply a Google font to those, do you? ;)

Creating the Theme Options Page

Next up is the Theme Options page under Appearance. You might already have one if you’re working on an existing theme and if you do, make sure you’re using the Settings API to render your controls. There’s a very neat article by Chip Bennett on Incorporating the Settings API in WordPress Themes, you should read that if register_setting sounds like alien to you ;)

So let’s get to some coding, everything in your theme’s functions.php file. First thing you have to do is add an admin menu, we’ll call it My Theme Options:

add_action( 'admin_menu', 'my_admin_menu' );
function my_admin_menu() {
    add_theme_page( 'My Theme Options', 'My Theme Options', 'edit_theme_options', 'my-theme-options', 'my_theme_options' );
}

As you can see we’re using the my_theme_options function as the callback to render the page, here’s what the function looks like:

function my_theme_options() {
?>
    <div class="wrap">
        <div><br></div>
        <h2>My Theme Options</h2>

        <form method="post" action="options.php">
            <?php wp_nonce_field( 'update-options' ); ?>
            <?php settings_fields( 'my-options' ); ?>
            <?php do_settings_sections( 'my-options' ); ?>
            <?php submit_button(); ?>
        </form>
    </div>
<?php
}

Not too much here, just a standard options page titled My Theme Options and a form with a nonce, some hidden settings fields and a call to do_settings_section that will render the tables for all the settings that we define later. Note that the submit_button function is new to WordPress 3.1, it’s basically a wrapper around a submit-typed input.

Finally we need to let WordPress know about our settings, settings sections and settings fields, we do that in the admin_init action, like this:

add_action( 'admin_init', 'my_register_admin_settings' );
function my_register_admin_settings() {
    register_setting( 'my-options', 'my-options' );

    // Settings fields and sections
    add_settings_section( 'section_typography', 'Typography Options', 'my_section_typography', 'my-options' );
    add_settings_field( 'primary-font', 'Primary Font', 'my_field_primary_font', 'my-options', 'section_typography' );
}

I created a setting (and a group) called my-options. I created a section called section_typography with the my_section_typography function as the callback (we’ll get to it soon). Finally I created a field under that section called primary-font with the my_field_primary_font callback where we’ll stick in our select box. For now I just put some filler text so you can actually see the Theme Options page in action but keep in mind that it’s far from ready.

function my_section_typography() {
    echo 'Section description can go here.';
}

function my_field_primary_font() {
    echo 'Font control will go here.';
}

Here’s what it looks like at this stage:

WordPress Theme Options Typography

Available Fonts Function

The reason why I left the font control empty is that we won’t hard-code any of the fonts there. Instead, we’ll use a function that will give us a list of available fonts, and the fun part is that we’ll apply a filter to the function to make it flexible. Let’s call it get_my_available_fonts:

function get_my_available_fonts() {
    $fonts = array(
        'open-sans' => array(
            'name' => 'Open Sans',
            'import' => '@import url(http://fonts.googleapis.com/css?family=Open+Sans);',
            'css' => "font-family: 'Open Sans', sans-serif;"
        ),
        'lato' => array(
            'name' => 'Lato',
            'import' => '@import url(http://fonts.googleapis.com/css?family=Lato);',
            'css' => "font-family: 'Lato', sans-serif;"
        ),
        'arial' => array(
            'name' => 'Arial',
            'import' => '',
            'css' => "font-family: Arial, sans-serif;"
        )
    );

    return apply_filters( 'my_available_fonts', $fonts );
}

So we’re creating a $fonts array that will house all our available fonts. Each font entry is an array of it’s own with name, import and css keys. You might have guessed that the import key holds the @import CSS directive which should be called before the font is used, while the css key holds the font-family attribute that we’ll apply to elements. The Arial font’s there too and as you can see there’s nothing to import.

Also note the call to apply_filters before returning the array, that means that a child theme developer can hook and provide their own typography options, or remove some of ours ;) Now let’s get this function working for our font control on our theme options page. Here’s how the my_field_primary_font changed:

function my_field_primary_font() {
    $options = (array) get_option( 'my-options' );
    $fonts = get_my_available_fonts();
    $current_font = 'arial';

    if ( isset( $options['primary-font'] ) )
        $current_font = $options['primary-font'];

    ?>
        <select name="my-options[primary-font]">
        <?php foreach( $fonts as $font_key => $font ): ?>
            <option <?php selected( $font_key == $current_font ); ?> value="<?php echo $font_key; ?>"><?php echo $font['name']; ?></option>
        <?php endforeach; ?>
        </select>
    <?php
}

First we read the current options, grab the available fonts using our new function and figure out the current primary font. We then print a select HTML element and use a foreach loop to walk through all our available fonts. The selected function will set the option as selected if it’s our current font. Everything’s pretty straightforward here and after implementing that, you’ll see that your options screen now works:

Theme Options Typography Settings

You can save changes and see how the select box is restored at the saved state, so we’re finally left to actually applying the chosen font. Hope you’re following along so far.

Applying the Fonts

We’ve got our chosen font stored in an option and we’ve got a function that has all the details about all our fonts. Let’s now put these to good use and output some styling in the head section of our theme.

add_action( 'wp_head', 'my_wp_head' );
function my_wp_head() {
    $options = (array) get_option( 'my-options' );
    $fonts = get_my_available_fonts();
    $current_font_key = 'arial';

    if ( isset( $options['primary-font'] ) )
        $current_font_key = $options['primary-font'];

    if ( isset( $fonts[ $current_font_key ] ) ) {
        $current_font = $fonts[ $current_font_key ];

        echo '<style>';
        echo $current_font['import'];
        echo 'body * { ' . $current_font['css'] . ' } ';
        echo '</style>';
    }
}

We read in the font options and figure out the currently set font. The option gives us a key but not the details that we need, which is why we use that key to figure out the rest and store it inside $current_font. We then output the style block with the import and the css fields for the selected font family.

The body * selector is not the fastest one on earth, you should probably use a different one to target the elements that should have your primary font family, but I kept it like this for brevity. That’s about it, go ahead and try changing the fonts in your theme options and see what happens on your front end. Hopefully something does :)

Extending with Child Themes

You might already have a clue on how to add support for new fonts via child themes, but I’ll show it here anyways. Basically all you have to do is use the my_available_fonts filter and give it your new options. I’ll add the Marvel font as an example:

add_filter( 'my_available_fonts', 'my_new_fonts' );
function my_new_fonts( $fonts ) {
    $fonts['marvel'] = array(
        'name' => 'Marvel',
        'import' => '@import url(http://fonts.googleapis.com/css?family=Marvel);',
        'css' => "font-family: 'Marvel', sans-serif;"
    );
    return $fonts;
}

Easy as that, just add a new key to the $fonts array and specify your new font’s details. The Marvel font will now be available in your drop-down list and instantly works on the front end too. Congratulations!

Wrapping Up

As mentioned in the beginning, this is only one approach at providing typography settings to your theme users and child theme developers. The technique may differ when jumping from one web fonts solution to another and of course even more different when embedding fonts as files. But perhaps the most difficult part is to get all your font families out of your default stylesheets (which was covered in the beginning of this post).

Feel free to ask us anything regarding theme options pages, font pickers and stylesheets as well as web typography in general. Use the comments section below to share your thoughts and thank you so much for reading. Oh, and did you know that we’ve got a bunch of WordPress goodies on our Facebook page too? Enjoy your day!