Being developers, we're used to looking at lines and lines of code in monospaced font and at the same time "seeing" what the page would look like in a browser. That said, it's easy for us to overlook the fact that there are quite a few non-developers out there.
Editor style is a nifty feature that allows you to match look and feel of post content inside the TinyMCE editor to what's shown to site visitors. It is extremely easy to use, but if your theme has font options and especially if it uses Google Fonts, editor style needs a little bit of extra work to style text based on font options values.
The Plan
In addition to loading editor-style.css using the add_editor_style()
function, we must do following things:
- Tell TinyMCE which font options are currently active
- If needed, load Google Fonts stylesheets
- Finally, add typography styles to our editor-style.css
Before doing any of that, you must already have a way for the site administrator to select which fonts they'd like to use. You can go with the Settings API, or - if you're one of the cool kids - the Theme Customizer, but explaining how to work with either one is not what this tutorial is about.
In order to jumpstart this project, I'll use the Underscores theme and the Theme Customizer Boilerplate. That will give me a starter theme and a way to quickly add options to the Theme Customizer, but how you handle this part is completely up to you.
Adding Font Options to the Theme Customizer
So, I downloaded a fresh copy of Underscores theme, added Theme Customizer Boilerplate to it and now I'm ready to add some options to the Theme Customizer, using the Customizer Boilerplate. This goes straight into the theme's functions.php file:
/** * Options array for Theme Customizer Boilerplate * * @link https://github.com/slobodan/WordPress-Theme-Customizer-Boilerplate * @return array Theme options */ add_filter( 'thsp_cbp_options_array', 'thsp_theme_options_array', 1 ); function thsp_theme_options_array() { // Using Customizer Boilerplate helper function to get default required capability $thsp_cbp_capability = thsp_cbp_capability(); $options = array( // Section ID 'thsp_typography_section' => array( 'existing_section' => false, 'args' => array( 'title' => __( 'Typography', 'cazuela' ), 'description' => __( 'Select fonts', 'cazuela' ), 'priority' => 20 ), 'fields' => array( 'body_font' => array( 'setting_args' => array( 'default' => 'open-sans', 'type' => 'option', 'capability' => $thsp_cbp_capability, 'transport' => 'refresh', ), // End setting args 'control_args' => array( 'label' => __( 'Body font', 'cazuela' ), 'type' => 'select', // Select control 'choices' => array( 'arial' => array( 'label' => 'Arial' ), 'open-sans' => array( 'label' => 'Open Sans', 'google_font' => 'Open+Sans:400italic,700italic,400,700' ), 'pt-sans' => array( 'label' => 'PT Sans', 'google_font' => 'PT+Sans:400,700,400italic,700italic' ) ), 'priority' => 1 ) // End control args ), 'heading_font' => array( 'setting_args' => array( 'default' => 'open-sans', 'type' => 'option', 'capability' => $thsp_cbp_capability, 'transport' => 'refresh', ), // End setting args 'control_args' => array( 'label' => __( 'Heading font', 'cazuela' ), 'type' => 'select', // Select control 'choices' => array( 'georgia' => array( 'label' => 'Georgia' ), 'open-sans' => array( 'label' => 'Open Sans', 'google_font' => 'Open+Sans:400italic,700italic,400,700' ), 'droid-serif' => array( 'label' => 'Droid Serif', 'google_font' => 'Droid+Serif:700' ) ), 'priority' => 2 ) // End control args ), ) // End fields ) ); return $options; }
As you can tell looking at that array, I'm adding a body font option and heading font option to the Theme Customizer, with three possible choices for each one - Arial, Open Sans, and PT Sans for the body font, Georgia, Open Sans, and Droid Serif for the heading font.
For Google Fonts, there's the google_font
value that I'll use later to load Google Fonts' stylesheets.
Telling TinyMCE Which Fonts Are Currently Selected
If we're going to be able to change fonts in the TinyMCE editor dynamically, based on what users select in the Theme Customizer, we must pass some information to the TinyMCE object.
For example, if Open Sans is selected as the body font, adding a 'body-open-sans
' class to the editor will do the trick. This can be done by using the tiny_mce_before_init
filter hook and changing the body_class
value in the TinyMCE settings array.
Check inline comments:
/** * Passes custom typography classes to Tiny MCE editor * * @param $thsp_mceInit array * @uses thsp_cbp_get_options_values() helper function defined in /customizer-boilerplate/helpers.php * @return $thsp_mceInit array */ function thsp_tiny_mce_classes( $thsp_mceInit ) { // Use Theme Customizer Boilerplate helper function to retrieve theme options $thsp_theme_options = thsp_cbp_get_options_values(); /** * $thsp_mceInit array stores its body classes as a string * * Whitespace character is used as separator between classes, * so when adding classes they must have a space before them */ $thsp_mceInit['body_class'] .= ' body-' . $thsp_theme_options['body_font']; // Body font class $thsp_mceInit['body_class'] .= ' heading-' . $thsp_theme_options['heading_font']; // Heading font class return $thsp_mceInit; } add_filter( 'tiny_mce_before_init', 'thsp_tiny_mce_classes' );
That will add custom classes to the TinyMCE editor, as you can see in this screenshot:
If you'd like to see the entire TinyMCE settings array, check out this Gist.
Again, I'm using the Theme Customizer Boilerplate and some of its functions to speed things up, how you handle your theme options is up to you.
Load Google Fonts Stylesheets
Some of the fonts in the array of options I passed to the Theme Customizer Boilerplate had the google_font
value defined. This helps determine whether the Google Fonts stylesheet needs to be loaded and what its URL is. Using that information, you can now hook into the mce_css
filter and add custom stylesheets to the TinyMCE editor window:
$mce_css
is a comma separated list of stylesheet URIs, so if the Google Fonts stylesheet you're loading has a comma in it you have to use an HTML entity instead. Since I added an option for both body and heading fonts I'll have to check both to see if they require the Google Fonts stylesheet:
/** * Load Google Fonts to use in Tiny MCE * * @param $mce_css string * @uses thsp_cbp_get_options_values() defined in /customizer-boilerplate/helpers.php * @uses thsp_cbp_get_fields() defined in /customizer-boilerplate/helpers.php * @return $mce_css string */ function thsp_mce_css( $mce_css ) { $theme_options = thsp_cbp_get_options_values(); $theme_options_fields = thsp_cbp_get_fields(); // Using Theme Customizer Boilerplate to retrieve theme font options values $body_font_value = $theme_options['body_font']; $heading_font_value = $theme_options['heading_font']; // Using Theme Customizer Boilerplate to retrieve all theme options $body_font_options = $theme_options_fields['thsp_typography_section']['fields']['body_font']['control_args']['choices']; $heading_font_options = $theme_options_fields['thsp_typography_section']['fields']['heading_font']['control_args']['choices']; // Check protocol $protocol = is_ssl() ? 'https' : 'http'; // Check if it's a Google Font if ( isset( $body_font_options[$body_font_value]['google_font'] ) ) { // Commas must be HTML encoded $body_font_string = str_replace( ',', ',', $body_font_options[$body_font_value]['google_font'] ); $mce_css .= ', ' . $protocol . '://fonts.googleapis.com/css?family=' . $body_font_string; } // Check if it's a Google Font if ( isset( $heading_font_options[$heading_font_value]['google_font'] ) ) { // Commas must be HTML encoded $heading_font_string = str_replace( ',', ',', $heading_font_options[$heading_font_value]['google_font'] ); $mce_css .= ', ' . $protocol . '://fonts.googleapis.com/css?family=' . $heading_font_string; } return $mce_css; } add_filter( 'mce_css', 'thsp_mce_css' );
Adding Font Styles to editor-style.css
After the last two steps, this is the easy part. TinyMCE editor now has custom classes based on active font options, and Google Fonts stylesheets are loaded, when needed. All that's left to do is add some font-family
styles to editor-style.css:
/* Body fonts */ .body-arial { font-family: Arial, sans-serif; } .body-open-sans { font-family: "Open Sans", sans-serif; } .body-pt-sans { font-family: "PT Sans", sans-serif; } /* Headings */ .heading-georgia h1, .heading-georgia h2, .heading-georgia h3, .heading-georgia h4, .heading-georgia h5, .heading-georgia h6 { font-family: Georgia, serif; } .heading-open-sans h1, .heading-open-sans h2, .heading-open-sans h3, .heading-open-sans h4, .heading-open-sans h5, .heading-open-sans h6 { font-family: "Open Sans", sans-serif; } .heading-droid-serif h1, .heading-droid-serif h2, .heading-droid-serif h3, .heading-droid-serif h4, .heading-droid-serif h5, .heading-droid-serif h6 { font-family: "Droid Serif", serif; }
Now, this method might not make too much sense if your theme allows users to select from "600+ Google Fonts". However, knowing that WordPress is built on the Decisions, Not Options principle and offering more than 600 choices for just one of the options makes even less sense.
If you prefer keeping your theme options sane by making some decisions I hope you'll appreciate this method of adding Google Fonts to the TinyMCE editor. Your feedback is welcome.
Comments