Customizer improvements in 4.4

Now an update for the hottest most buzz-worthy JavaScript-driven single page application (SPA) in WordPress: Calypso the Customizer. Earlier in the release cycle there was a proposed roadmap for the Customizer and I wanted to share an update for what improvements have made it into the 4.4 release. I won’t include everything, but I’ll highlight some items that you may notice or want to make note of.


As noted on the roadmap, the focus for the Customizer in 4.4 has been to improve performance, and there are some drastic improvements in this release. Note that selective refresh (#27355, neé partial refresh) did not make it in, however the feature plugin now has a pull request for review.

Multidimensional Customizer settings (options & theme mods) are not scalable (#32103)

In 4.3 the time to load/refresh the Customizer preview increases exponentially as the number of settings/controls grows. If you have 200 settings it can take 15 seconds for the preview to update. If you have 300 settings, it can take 36 seconds to load/refresh the Customizer preview. And the time to reload the preview continues to grow exponentially as the number increases:

With the fixes in place for 4.4, the time to refresh the preview grows linearly very slowly (basically flatlined) as opposed to exponentially. I would share a graph, but it would be a very boring flat horizontal line.

See also aggregated multidimensional settings below.

Reduce Customizer peak memory usage by JSON-encoding settings and controls separately (#33898)

In addition to the slow preview load/refresh time, when there are a lot of Customizer settings/controls registered, the process for exporting the data from PHP to JavaScript used a lot of server memory when it serializes the JSON data in 4.3. In 4.4, each setting and control now gets serialized individually in a loop to avoid the memory spike, and this helps avoid any white screen of death due to the allowed memory size being exhausted in PHP.

Defer embedding Customizer widget controls to improve DOM performance (#33901)

The previous performance improvements were for the server and reduced the amount of time it takes to get a response (TTFB). Nevertheless, for sites that have a lot of widgets, the Customizer would still load very slowly, not due to WordPress being slow on the server, but due to the JavaScript running in the browser. In 4.3 given 100 widgets (with a lot of inputs), the Customizer could take 40 seconds to finish building the page due to all of the widget controls being embedded into the DOM. So in 4.4 we defer the embedding of widget controls until the contained widget area section is expanded, that is until the widget control is actually shown to the user. This results in the Customizer loading over 10× faster: what did take 40 seconds now takes 3 seconds in WordPress 4.4.

Widgets section in customize late to show up (#33052)

The widgets panel now will now always be shown even if there are no widget areas currently displayed in the preview. This ensures that the widgets panel doesn’t slide down after the preview finishes loading. This is another browser-based improvement that doesn’t actually improve actual performance but it does improve perceived performance, or at least the user experience.

Aggregated Multidimensional Settings

The problem with the scalability of multidimensional settings for options or theme mods (#32103) is that the number of filters added to preview changes grows exponentially (see above). The fix for this is to ensure that only one filter gets added for a multidimensional settings that share a common ID base. The entire root value for the option or theme mod gets stored in a variable, and any previewed setting’s value gets applied to that variable once, and this root value then gets returned by the filter. This construct is referred to in the source as a “aggregated multidimensional setting”. Note that this has only been implemented for options and theme mods: custom multidimensional setting types that subclass WP_Customize_Setting should also be able to make use of the functionality, although this has not been specifically tested.

Two new actions have been introduced:

  • customize_post_value_set
  • customize_post_value_set_{$setting_id}

These are triggered whenever WP_Customize_Manager::set_post_value() is called, and they allow for WP_Customize_Setting::preview() to update the value being previewed. You can now, for instance, call preview() on a setting up-front and then set the post value later, and the new value will be applied for previewing as expected. This can be called a “deferred preview” or “just in time” previewing.

Facilitate plugins to override Customizer features (#33552)

Sometimes widgets or menus are not applicable for a given site. Ticket #33552 introduces a new filter customize_loaded_components which allows nav menus or widgets to be skipped from initialization. For example, to prevent the nav menu functionality from being loaded the following plugin code can be used:

add_filter( 'customize_loaded_components', function ( $components ) {
    return array_filter( $components, function ( $component ) {
        return 'nav_menus' !== $component;
    } );
} );

JS Inline Docs

The Customizer is a JavaScript-heavy application, and in #33503 #33639 the inline docs for JS have been improved to help developers understand how it works. See [33709] [33911] [33841].

Non-autoloaded Option Settings (#33499)

When settings are registered for options that don’t already exist in the DB, an update for these settings in the Customizer would result in update_option() called with the default $autoload parameter and thus them being saved as autoloaded. In 4.4 you can now register option settings to explicitly not get added with autoloading, for example:

$wp_customize->add_setting( 'foo[first]', array(
    'type' => 'option',
    'autoload' => false,
) );

Other Improvements

  • #21389 Retina theme custom headers
  • #31540 Dropdown pages Customizer description option
  • #32637 Customizer should default to returning to the front page, not the themes page
  • #32812 Customizer Menus: Escaping inconsistencies — You can now use limited markup in nav menu item titles in the Customizer.
  • #33319 Customizer header image crop uses static URL when refreshing UI after crop.
  • #33665 Menu Customizer: Implement indicators for invalid menu items
  • #34432 Customizer subclasses can be broken out and remain BC — All Customizer PHP classes now reside in a separate files.
  • #34607 Customizer: Wrapped labels should align to start of label, not checkbox or radio button
  • New methods:
    • WP_Customize_Manager::get_preview_url()
    • WP_Customize_Manager::set_preview_url()
    • WP_Customize_Manager::get_return_url()
    • WP_Customize_Manager::set_return_url()
    • WP_Customize_Manager::set_autofocus()
    • WP_Customize_Manager::get_autofocus()
    • WP_Customize_Manager::customize_pane_settings()

Several accessibility fixes were also made.

See also the full list of tickets that were closed during the 4.4 release for the customize component.

#4-4, #customize, #dev-notes