Customizing TinyMCE 4.0

Many of the TinyMCE settings have changed in version 4.0. There is a new default theme: Modern, and all the UI settings for the former Advanced theme (theme_advanced...) are deprecated.

One often used setting was theme_advanced_blockformats. It was renamed to block_formats and keeps the same formatting. To specify a different set of elements for the ‘blockformats’ drop-down (second toolbar row in the WordPress Visual editor), you can set a string of name=value pairs separated by a semicolon in the initialization object:

block_formats: "Paragraph=p;Heading 1=h1;Heading 2=h2;Heading 3=h3"

Another handy setting: theme_advanced_styles doesn’t exist any more. However there is a more powerful version: style_formats. Now it can replace or add items to the new “Formats” menu.The value is an array of objects each containing a name that is displayed as sub-menu and several settings: a CSS class name or an inline style, and optionally the wrapper element where the class or inline style will be set:

toolbar3: 'styleselect',
style_formats_merge: true,
style_formats: { name: 'Custom styles', [
  {title: 'Red bold text', inline: 'b', styles: {color: '#ff0000'}},
  {title: 'Red text', inline: 'span', styles: {color: '#ff0000'}},
  {title: 'Red header', block: 'h1', styles: {color: '#ff0000'}},
  {title: 'Example 1', inline: 'span', classes: 'example1'},
  {title: 'Example 2', inline: 'span', classes: 'example2'}
]}

The above code will add another sub-menu to “Formats” without replacing the default menu items. There is more information and an example on the TinyMCE website.

Server managed cache in the browser

Imagine browsing to a big web page with lots of images and scripts, and it loads in your browser almost instantly, nearly as fast as loading it from your hard drive. Now imagine you’re browsing a web site with about 60-70 of these pages and they all load very very fast. Sounds interesting? But how to do that? Prime the browser’s cache? Preload all components of the web pages somehow? Is that possible?

Well, yes and no. It is possible by using Gears. It can be set to store all “static” components (JS, CSS, images, etc.) of a web page or a whole web site and load them from the local storage every time they are requested by the browser. However the Gears team shifted their priorities to HTML 5.0 offline storage which was the main idea behind Gears in the first place. Unfortunately the HTML 5.0 specification for offline storage implements only some of the features that were available in Gears, so this type of caching (controlled by the user and managed by the server) is impossible.

But why server managed cache? Isn’t the standard browser caching good enough? Yes, it is good. It has evolved significantly during the 15 or so years since the beginning of the World Wide Web. However it just can’t do that.

Lets take a simplistic look at how the browser cache works:

  • We (the users) browse to a web page.
  • The Server tells the Browser: “Hey there, these few files (images, JS, CSS, etc.) are almost never updated, put them in your cache and don’t ask me to send them again for the next 10 years.”
  • The Browser thinks: “Hmm, put them in the cache you saying? I’ll think about it. You know, I’m a Web Browser. I need to load pages very very fast. I don’t want a huge cache with millions of files in it. That will slow me down. Lets see if the User would come back to this page ever again.”

If we keep going to the same web page eventually the Browser would change his mind: “Maybe that Server was right and I should put these files in my cache. That would speed up page loading. But what will happen if these files are updated… I better keep asking the Server to check if they have been updated so my cache is always fresh.”

Couple of years ago we implemented Gears as WordPress’ Turbo feature. We didn’t use it to make WordPress an offline app, we used it to create server managed cache. It worked great. Even the heaviest pages in the WordPress admin were loading considerably faster regardless of how often the users were visiting them.

The implementation was very simple: we had a manifest that listed all “static” files and couple of user options to enable and initialize the “super cache”. The rest was handled automatically by Gears. So in reality we discovered the perfect way of browser caching for web apps:

  • The User decides which web sites / web apps are cached and can add or remove them.
  • The server (i.e. the web app) maintains the cache, updating, adding, deleting files as needed.

The results were spectacular. We didn’t need to concatenate and compress scripts and stylesheets. We even stopped compressing TinyMCE which alone can load about 30-40 files on initialization. And page load time was from 0.5 to 1.5 sec. no matter how heavy the page was. For comparison before implementing this “super caching” pages were loading in 5 to 9 sec.

Why was it performing that well? Simple: it eliminated all requests to the server for the files that were cached. And that means all, even the “HEAD” requests. In our implementation the only file that was loaded from the server was the actual HTML. All other components of the web page were stored in Gears’ offline storage.

That also had the side benefit of eliminating a big chunk of traffic to the server. At first look it doesn’t seem like a lot, 30-40 requests for the web page components followed by 30-40 of HEAD requests per page every now and then (while the browser cache is hot), but think about it in global scope: several millions of these pages are loaded every hour.

So, why not do the same with HTML 5.0 offline storage? Because it doesn’t work that way. The HTML 5.0 specification for offline storage is good only for… Offline storage. It’s missing a lot of the features Gears has. Yes, there is a workaround. We can “store offline” a skeleton of the web page and then load all the dynamic content with XHR (a.k.a. AJAX), but that method has other (quite annoying) limitations. Despite that we will try this method in WordPress for sure, but that discussion is for another post.

In short: the HTML 5.0 offline storage implementation is missing some critical features. For example a file that is stored there is not loaded from the storage when the browser goes to another page on the same website. Yes, it’s sad watching the browser load the same file again and again from the Internet when that file is already on the user’s hard drive.

What can we do about it? Don’t think there is anything that can be done short of changing, or rather enhancing the HTML 5.0 specification for offline storage. The XHR “hack” that makes this kind of caching possible with the current HTML 5.0 is still just a hack.

Can themes style the visual editor?

Short answer: yes. This has been available for quite some time but don’t think I’ve seen themes that do it. Things like typefaces, headings, image padding and borders, etc. can easily be set by the current theme making the visual editor… more WYSIWYG. All it takes is a stylesheet and a small function in the theme’s functions.php file:

add_filter('mce_css', 'my_editor_style');
function my_editor_style($url) {

  if ( !empty($url) )
    $url .= ',';

  // Change the path here if using sub-directory
  $url .= trailingslashit( get_stylesheet_directory_uri() ) . 'editor-style.css';

  return $url;
}

where¬†editor-style.css will be applied to TinyMCE’s iframe.

There is also an option to define CSS classes that can be inserted by the user and to add the “Styles” drop-down selector to the editor toolbar. This is probably most useful for developers when creating a custom theme for a client as these classes would stop working if the theme is changed.

I’ve put together a small package with examples of how to enable this. If you are creating WordPress themes, download it or have a look, it’s quite simple. If not, perhaps ask the author of your theme to add it to the next update. :)

Update: as Dion points out in the comments, this is not meant for adding the whole “style.css” to the editor. That could bring problems and most of the styling won’t apply there anyways. It works best when a separate stylesheet is made specifically for use in the editor (editor-style.css in the example). It should contain a small subset from style.css, usually the part that is applied to the actual posts.

podPress and Popularity Contest

There have been couple of patches for the feeds in podPress by Tim Berger, Update and bugfix for the atom feed and Bypass of the RSS Feed does not work. Currently they are in the Development Version. If anybody wants to add more, please make a ticket on the plugins trac and drop me an email.

Also recently had a look at the Popularity Contest plugin. It works well in WordPress 2.7 and 2.8-bleeding only the activation fails. To make it compatible a small piece of code has to be added to the beginning: global $wpdb;

This should go just above the first “if” statement, so it looks like this:

// add this 
global $wpdb;

// existing code
if (!isset($wpdb)) {
	require('../../wp-blog-header.php');
	...

Tried to contact the author and send him this fix so he can add it to the plugin.

Troubleshooting TinyMCE in WordPress 2.7

One of the many improvements in WordPress 2.7 is the updated configuration of the visual editor, TinyMCE. It was optimized to support caching better and to load faster.

The compression whitin WordPress is gone and all editor components are included as standard Javascript, CSS and HTML files. However a lot of servers compress these files automatically. If your server doesn’t do that, the first loading of the write/edit page will be slower, but after that the editor loads a lot faster than before, as all files are in the browser’s cache on the hard disk. And if the “Turbo” is turned on in WordPress and Gears enabled, the speed increase is even bigger as the browser does not have to check if any file has been updated.

In my (non-scientific) tests the loading time of the Add New Post screen went from about 5 – 8 sec. to about 1 – 2 sec. depending on the Internet connection and the computer speed.

The removal of the compression whitin WordPress also improves compatibility with some unusual server configurations and fixes some hard to catch errors, for example when there are php errors or output starts in the current theme’s functions.php file.

Currently the editor’s settings together with all Javascript files are included directly in the HTML head section of the page, making it a lot easier to troubleshoot.

There are a few steps that would help with the troubleshooting if the editor doesn’t start or work properly:

  1. Make sure the “Disable the visual editor when writing” checkbox in your profile is not selected.
  2. Whitelist or set your blog as “trusted” in your firewall and antivirus program.
  3. Disable Gears, clear your browser’s cache, quit it, start it again, go back to the write page and force-reload it several times, while holding down Shift (Firefox) or Ctrl (IE). In Safari select Clear Cache (from the Safari menu on Mac).
  4. Try another browser and/or another computer.
  5. Disable all plugins, clear the cache, restart the browser and try again.
  6. Delete both wp-admin and wp-includes directories and upload fresh copies from the WordPress installation package.
  7. And finally install Firefox or Opera, note any Javascript errors, especially the first one and try searching on the support forum for a solution. If no solution exists, open a new thread including the error.

PodPress in WordPress 2.6

Yesterday had a quick look at podPress, the premier plugin for podcasting. It has a small incompatibility with the new Post Revisions feature introduced in WordPress 2.6.

PodPress seems to be in the middle of a large update. I’ve used the “experimental” version (8.9) of the plugin and emailed the proposed fix to the authors, however for the more impatient here is the patch:

function post_edit($post_id) {
	GLOBAL $post;
	if($this->justposted) {
		return;
	}
	$this->justposted = true;

	if ( isset($_POST['post_ID']) && (int) $_POST['post_ID'] )
		$post_id = (int) $_POST['post_ID'];

	$this->settings_item_save($post_id, $_POST);
}

It goes in podpress/podpress_admin_class.php, around line 51. What it does is to make sure the custom post meta fields used by podPress are attached to the actual Post, not one of the revisions.