Adding Typekit and dynamic styles to the WordPress editor

kelly sikkema 291518

An often overlooked part of theme development is the back end. It’s quite possible to ignore differences in font and appearance between the editor and the front-end of the theme but after toggling between the two views for a while, I find that discrepancies, especially with fonts, start to jar.

Styling the WordPress editor to match the front-end styles allows authors and editors to visualize more closely what their content is going to look like to the end-user. As projects like the Gutenberg editor move forward and eventually (presumably) become incorporated into core, it’s likely that the WordPress writing and editing process will feel more unified but, until then, there’s a clear distinction between the back-end editor and the front-end content.

In putting this article together, I used two main sources. First, for work on pulling Typekit fonts into the WordPress editor, all the credit goes to Tom J Nowell and his article at https://tomjn.com/2012/09/10/typekit-wp-editor-styles/. I only modified this slightly to allow us to pass the Typekit Kit ID in dynamically rather than hard-coding it.

Second, for adding styles dynamically to the TinyMCE iframe head, I referred to the article by Matt Cromwell at https://www.mattcromwell.com/dynamic-tinymce-editor-styles-wordpress/ which in itself is based on work by Samuel Wood.

All I’ve done is essentially combine these two pieces of work and adapt them slightly to meet my specific needs.

Adding Typekit to the WordPress editor

If your theme allows your user to utilize Typekit fonts, it’s a good idea to use the same font in the WordPress editor. There are a number of obstacles, discussed in more detail in the article above, in trying to accomplish this. However, I found the following code to work:

/**
 * Add Typekit to the editor
 * @link https://tomjn.com/2012/09/10/typekit-wp-editor-styles/
 */
function showcase_mce_external_plugins( $plugin_array ) {
  // Check if we have Typekit enabled
  $typekit_kit = get_theme_mod( 'typekit-kit', '' );
  $typekit = get_theme_mod( 'use-typekit', 0 );
  if( $typekit && $typekit_kit && ! is_customize_preview ) {
    // You may need to update the path to the js file below
    $plugin_array['typekit'] = get_template_directory_uri() . '/assets/js/typekit.tinymce.js';
  }
  return $plugin_array;
}
add_filter( 'mce_external_plugins', 'showcase_mce_external_plugins' );

As with Tom Nowell’s code, this uses the mce_external_plugins filter to create a new TinyMCE plugin (see below). Note that this differs from Tom’s code in that it first checks that Typekit is enabled in the theme. Your theme will no doubt use a different method for detecting this so please make any changes as required for your theme. Also, please ensure that you use the correct path to the plugin js file.

Note that I found this threw a JavaScript error in the Customizer so this doesn’t try to load the plugin if the Customizer is active.

Add the code above to your theme’s functions.php file or whichever file you’ve reserved for editor styles then add the following code:

/**
 * Add Typekit ID to variable so we can grab it from the tinymce script
 */
function showcase_admin_add_typekit_id() {
  // Use whichever method you like to grab the Typekit ID
  $typekit_kit = get_theme_mod( 'typekit-kit', '' );
  ?>
  <script type="text/javascript">
    var global_typekit_id = '<?php echo esc_attr( $typekit_kit ); ?>';
  </script>
  <?php
}
add_action( 'admin_head', 'showcase_admin_add_typekit_id' );

The purpose of the code above, which isn’t part of the original script, is to add the Typekit Kit ID as a global variable to the page. We can then grab that from the JavaScript, see below.

Add the JavaScript

The second piece of code is the TinyMCE plugin file itself. (Note that a TinyMCE plugin is not the same as a WordPress plugin – it’s a module that works specifically for the TinyMCE editor, not something you install via WordPress). Add this code to a file named ‘typekit.tinymce.js’ and save it in your theme directory. You’ll need to update the path in the code above to point to its saved location.

(function() {
  tinymce.create('tinymce.plugins.typekit', {
    init: function(ed, url) {
      ed.onPreInit.add(function(ed) {
        // Get the DOM document object for the IFRAME
        var doc = ed.getDoc();
        var jscript = "(function() {\n\
          var config = {\n\
            kitId: '"+global_typekit_id+"'\n\
          };\n\
          var d = false;\n\
          var tk = document.createElement('script');\n\
          tk.src = '//use.typekit.net/' + config.kitId + '.js';\n\
          tk.type = 'text/javascript';\n\
          tk.async = 'true';\n\
          tk.onload = tk.onreadystatechange = function() {\n\
            var rs = this.readyState;\n\
            if (d || rs && rs != 'complete' && rs != 'loaded') return;\n\
            d = true;\n\
            try { Typekit.load(config); } catch (e) {}\n\
          };\n\
         var s = document.getElementsByTagName('script')[0];\n\
         s.parentNode.insertBefore(tk, s);\n\
       })();";

       // Create a script element and insert the TypeKit code into it
       var script = doc.createElement("script");
       script.type = "text/javascript";
       script.appendChild(doc.createTextNode(jscript));

       // Add the script to the header
       doc.getElementsByTagName('head')[0].appendChild(script);

      });
    }
  });
  tinymce.PluginManager.add('typekit', tinymce.plugins.typekit);
})();

Again, there is only one change from the original code and that’s to use the global_typekit_id variable to insert the Typekit ID rather than hardcoding it.

Adding dynamic styles to the editor

It’s simple enough to use add_editor_style to enqueue a stylesheet for your editor. The drawback to this is that you can’t dynamically update any of the CSS to reflect style changes made via the Customizer, e.g. different font choices or color combinations. So the second part of this post shows how you can dynamically add styles to the TinyMCE head. As I mentioned above, this is based on work by Matt Cromwell and Samuel Wood.

/**
 * Adds styles from customizer to head of TinyMCE iframe.
 * @link https://www.mattcromwell.com/dynamic-tinymce-editor-styles-wordpress/
 */
function showcase_add_editor_styles( $mceInit ) {
 
  // Add each style to this array
  $styles = array();
  $secondary_color = get_theme_mod( 'secondary-color' );
  if( $secondary_color ) {
    $styles[] = 'color: ' . esc_attr( $secondary_color );
  }
 $typekit_kit = showcase_editor_use_typekit();
 if( $typekit_kit ) {
   $mod = get_theme_mod( 'typekit-font-family', '' );
   $styles[] = 'font-family: ' . $mod . ', sans-serif';
 }
 // Join the $styles array using semi-colon as separator
 // Then add to style rule to pass back to TinyMCE
 $mce_styles = '.mce-content-body { ' . join( ';', $styles ) . ' }';
 
 // Add a style rule for link colors
 $primary_color = get_theme_mod( 'primary-color' );
 if( $primary_color ) {
   $mce_styles .= '.mce-content-body a { color: ' . $primary_color . ' }';
 }
 
 // Pass new styles back to TinyMCE
 if ( ! isset( $mceInit['content_style'] ) ) {
   $mceInit['content_style'] = $mce_styles . ' ';
 } else {
   $mceInit['content_style'] .= ' ' . $mce_styles . ' ';
 }
 return $mceInit;
}
add_filter( 'tiny_mce_before_init', 'showcase_add_editor_styles' );

I’ve modified this code so that I create an array of styles in the $styles variable. Each element is the style selector and declaration for different theme mods that are set in the Customizer. Once the array has been built, each element is joined using a semi-colon as the separator to create the CSS. This is passed back to the TinyMCE head using the $mceInit variable.

You can update this for your own Customizer options and style settings.

Front-end editing

I think that this method of editing in WordPress has a finite future. The Customizer and Gutenberg are making content writing much more of a WYSIWYG process and we’ll start to see far less separation between front-end and back-end in WordPress. But for now, the methods outlined above should improve the quality of editing within your theme for your end-user.

 

Leave a Reply

Your email address will not be published. All fields are required.