Polishing the WordPress Customizer Experience

Custom car | WordPress customizer

The same day that my last post about the WordPress customizer went live, the WordPress.org Theme team made headlines with their decision that all future themes submitted will have to use the customizer for theme settings. Old themes can continue to use their custom settings pages, but if you want to offer users control of custom features in a theme not currently in the repository, you’ll need to use the customizer. I joked about it on Twitter:

But with the new policy, there’s been a whole set of recent interest in the topic, and a rash of new great resources on creating customizer settings are starting to pop up. The one that I like so much that I’ll put it right here in the introduction to my own article is this one on the WordPress Developer Handbook, from @NickHalsey_. It’s very comprehensive.

Our focus is three specific tricks that really put a nice sheen on the customizer experience.

Our focus here, though, is three specific tricks that really put a nice sheen on the customizer experience:

  1. Smooth real-time previewing of customizer settings, using postMessage and AJAX refreshing,
  2. Grouping detailed blocks of customizer settings with Panels, and
  3. Intelligently showing and hiding specific customizer settings using active_callback.

Let’s begin!

Propagate User Changes Faster with postMessage Data Refreshing

postMessage uses AJAX to update customizer options previews on-the-fly, without page reload flickers and delays.

As we mentioned last time: out of the box, without you needing to do anything, any change you make in the left panel (the customizer controls) will propagate over to the right-side site preview panel. This is great: it makes it really easy to get started using the customizer, and keeps the whole thing simple.

But the default setup has one disadvantage, which is that it can cause a perceptible delay between the time a user flips an option or changes a value and the time he or she sees it. This is because the default setup is refreshing the entire page to force the changes to take effect—the equivalent of hitting “reload” in your browser.

Delays in the the theme customizing experience aren’t the end of the world, but they’re a small and unnecessary problem, because postMessage is available. postMessage uses AJAX to update customizer options previews on-the-fly, without page reload flickers and delays. The result is a much quicker and more seamless user experience.

Turning on the postMessage Transport Method

When you create any setting for the customizer, you either explicitly or implicitly (by accepting the default) set the transport method to refresh. To start to make your customizer options propagate faster, you’ll want to change that option to postMessage. If you’re registering the setting yourself, that will look like:

$wp_customize->add_setting( 'header_color', array(
    'default'     => '#000000',
    'transport'   => 'postMessage',
) );

Alternatively, if someone else has added the setting already (say, WordPress itself…), and you’re just tweaking it, it’d look like:

$wp_customize->get_setting( 'header_color' )->transport = 'postMessage';

If that syntax looks strange to you, remember that the customizer is an object-oriented system.

The $wp_customize instance of the WP_Customize_Manager class has methods like add_setting(), and get_setting(). And what get_setting returns to you is an object—an instance of WP_Customize_Setting class—whose properties are publicly settable.

So we’re changing the transport property of that object with the = operator for assignment. Here’s a slightly longer restatement in PHP:

$setting_object = $wp_customize->get_setting( 'header_color' );
$setting_object->transport = 'postMessage';

JavaScript to Catch the postMessage Transport

Once you change a setting to use the postMessage transport method, you’re not done. (If you were, why would it even be an option? It’d just be The Best Way.)

You have to also catch the transport of the data, and have it change the right panel. That’ll require that you write the JavaScript which does the “catching,” and also make sure that that JavaScript is there on the customizer.

Let’s write the JavaScript first. It’ll generally look something like:

( function( $ ) {
    wp.customize( 'header_color', function( value ) {
        value.bind( function( newval ) {
            $('.header-area').css('background-color', newval );
        } );
    } );
    
} )( jQuery );

There are two major things to notice here:

  1. We’re using jQuery (aliased to the dollar sign, $) to change the actual property, background-color, in the site preview’s HTML markup.
  2. We’re also using the wp.customize object to take care of basics (like actually catch the message) of what we’re doing.

For a great deal more about the wp.customize object and what’s inside it, you should check out the Handbook page I mentioned earlier.

For our purposes, the important thing about this use of the class is that we’re binding a function to value. That function is using function( newval ) {} to set the property in the page preview to the newval, the value of the option we’re “catching” with value.bind().

Loading Your JS With the Customizer

Finally, we’ve written the JavaScript, but we need to load it. We’ll use wp_enqueue_script pretty simply for this, with just two extra things to remember: declaring your dependencies, and that you only want to include this script when the customizer loads.

The following script will accomplish both:

function wpshout_customizer_preview() {
    wp_enqueue_script( 
          'shout-customizer',
          get_template_directory_uri().'/js/theme-customizer.js',
          array( 'jquery','customize-preview' )
    );
}
add_action(
    'customize_preview_init',
    'wpshout_customizer_preview'
);

We’re adding our enqueue function onto the customize_preview_init action (rather than the more traditional wp_enqueue_scripts) so that it will only be loaded when you’re looking at the customizer’s preview. (You obviously won’t be using this script to actually set options for regular site viewers: you’ll be using the calls to get_theme_mod or get_option we talked about last time.)

And we’re also including the third parameter to wp_enqueue_scripts. This is an array that tells WordPress of our script’s two dependencies: jQuery, and customize-preview, the file which declares the wp.customize object we used in the JavaScript.

With that, we’re done. We’ve now got a quick-refreshing preview!

Adding Panels, but Only When Needed

We discussed last time how sections are made of controls that represent settings. And you can add sections beyond the defaults WordPress provides. But sometimes, you may have so many sections, that are so conceptually connected, that you’d like to break them out into an independent unit. This is the case for the widget experience in the customizer, if you’ve ever toyed with it.

That’s possible with add_panel. Just as sections are made up of controls, panels are made up of multiple sections. (Technically, you can have a panel with only one section, but then why is it a panel at all?)

If you managed to wrap your head around adding sections, you’ll quickly get the hang of panels:

$wp_customize->add_panel( 'front_page_panel', array(
    'title' => 'WPShout Homepage',
    'description' => 'For customizing front page',
    'priority' => 10
) );

Then, you’ll need to specify that panel when you add the sections that’ll appear in it. (When you don’t specify the panel, it goes into the default panel.)

$wp_customize->add_section( 'links_section', array(
    'title' => 'Link Block',
    'panel' => 'front_page_panel',
) );

Panels are best used for sections where you have a great deal of complex stuff going on.

Don’t let the ease of making panels convince you to use it too quickly. Panels are best used for sections where you have a great deal of complex stuff going on. If you have a complex homepage with a number of customizable areas, it makes a lot of sense to put all those sections under a panel. But for most of the things the customizer’s used for, they’re likely to be overkill.

Intelligent Hiding with active_callback

Some of your customizer settings may only impact a specific page or set of pages. Fortunately, there’s a simple property to control when they’re visible.

When you’re using the customizer just for big and always-present elements of your theme, it makes a lot of sense to show your settings all the time. But some of your settings may only have an impact on a specific page or set of pages — your archive pages, your homepage, and so on. In those cases, having the setting visible when the user won’t actually see the change propagate into the preview is not great.

Fortunately, controls, settings, and panels all have a nice and simple property which lets you control whether or not they’re visible: active_callback.

Using the example of a Homepage panel, we could make that panel only show up when we’re looking at the front page in the customizer preview as follows:

$wp_customize->add_panel( 'front_page_panel', array(
    'title' => 'WPShout Homepage',
    'description' => 'For customizing front page',
    'priority' => 10,
    'active_callback' => 'is_front_page'
) );

The string you provide for the 'active_callback' is a function name (or a function itself, if you don’t need to support PHP 5.2…) that returns either true or false. In our case, we’ve provided is_front_page, a reference to WordPress’s is_front_page() function, which is true on the site’s front page and false everywhere else. In the background, WordPress takes care of syncing that check with what’s being shown to the user. Pretty neat!

Also worth considering: because you can create your own custom functions for active_callback (rather than just using a WordPress one as we do here), you can do some pretty cool things. Things like showing and hiding one setting controller based on the value of a different setting. You might be able to work out the details yourself, but if not, check out the section “Fun with Active Callbacks” in the latest post from Otto.

Three Great Tricks, Making Good Even Better

It’s great about the customizer that all three of these ideas represent really important — and not super hard to get — user experience improvements over the defaults. But what’s even greater is that the defaults themselves are still a better experience than the bad, and often confusing and random, custom settings pages that come with so many themes.

I, for one, am pretty excited by the move by the WordPress.org theme team to push toward greater standardization. Some settings pages were good, and some might actually be better than the customizer experience. (I doubt it, but I’ll concede it’s a possibility.) However, my overwhelming experience coming into new, especially commercial, themes is one of profound confusion. If the whole WordPress ecosystem continues to march into the customizer, I will be a very happy man.

And if they do, I hope they’ll keep these improvements to the basics of the customizer in mind. I think panels could be a problem if overused, but the intelligent showing and hiding of information enabled by active_callback and the seamlessness available via postMessage settings transport is going to be great. Happy hacking!

Image credit: Craig Howell


7 Responses

Pingbacks