Use selective refresh in the customizer

Since WordPress 4.5, we can reload only parts of the customizer preview after a setting has changed. With that, the user has — at least — the feeling of a faster experience. And in most cases, it will be actually faster (and besides that, this feature could eliminate the customizer page and replace it with inline editing, writes Weston Ruter in his post »Selective Refresh in the Customizer«). Here I show you how to implement selective refresh.

Using selective refresh for a customizer setting

Using the feature with an existing customizer setting is actually quite simple. Here comes a complete example for a customizer setting from my Photographus theme:

/**
 * Create setting for page.
 */
$wp_customize->add_setting( "photographus_panel_{$i}_page", [
	'default'           => false,
	'sanitize_callback' => 'absint',
	'transport'         => 'postMessage',
] );

/**
 * Create control for page.
 */
$wp_customize->add_control( "photographus_panel_{$i}_page", [
	'label'           => __( 'Select page', 'photographus' ),
	'section'         => 'photographus_options',
	'type'            => 'dropdown-pages',
	'allow_addition'  => true,
	'active_callback' => 'photographus_is_page_panel',
	'input_attrs'     => [
		'data-panel-number' => $i,
	],
] );

$wp_customize->selective_refresh->add_partial( "photographus_panel_{$i}_page_partial", [
	'selector'            => "#frontpage-section-$i",
	'settings'            => [
		"photographus_panel_{$i}_page",
	],
	'render_callback'     => 'photographus_the_page_panel',
	'container_inclusive' => true,
] );

The add_setting() and add_control() part should not be something new for you if you already worked with the customizer. Since 4.5 we can use $wp_customize->selective_refresh->add_partial, which we hand over a unique identifier as the first param and a settings array as the second, which contains the following values:

  • An HTML selector, who specifies the element which needs a reload.
  • One or more settings, which trigger the refresh.
  • A callback function which echoes the new markup.
  • The instruction to also reload the container element in our case (#frontpage-section-$i).

And that is it — we implemented selective refresh for a setting 🎉 But there is one thing to notice:

Markup which is modified by JavaScript inside render_callback

If you reload an element which contains markup, which is modified by JavaScript (for example, a masonry grid), then you have to run the JavaScript on a selective refresh. The handling looks as following in my Photographus theme:

/**
 * Custom JavaScript functions for the customizer preview.
 *
 * @version 1.0.0
 *
 * @package Photographus
 */
;(function () {
    document.addEventListener('DOMContentLoaded', function () {
        /**
         * Selectice refresh check from https://github.com/xwp/wp-jetpack/blob/feature/selective-refresh-widget-support/modules/widgets/contact-info/contact-info-map.js#L35
         * @type {*}
         */
        hasSelectiveRefresh = (
            'undefined' !== typeof wp &&
            wp.customize &&
            wp.customize.selectiveRefresh &&
            wp.customize.widgetsPreview &&
            wp.customize.widgetsPreview.WidgetPartial
        );
        if (hasSelectiveRefresh) {
            wp.customize.selectiveRefresh.bind('partial-content-rendered', function (placement) {
                buildMasonryGrid(hasSelectiveRefresh);

                addClassToImageLinks();

                fullWidthImages();

                /**
                 * Get the front page panels.
                 * @type {NodeList}
                 */
                var panels = document.querySelectorAll('.frontpage-section');
                /**
                 * Check if we have panels.
                 */
                if (0 !== panels.length) {
                    var panelsWithContent = 0;
                    /**
                     * Loop through them.
                     */
                    for (var i = 0; i < panels.length; i++) {
                        /**
                         * Check if it is a panel placeholder.
                         */
                        if (!panels[i].classList.contains('frontpage-section-placeholder')) {
                            panelsWithContent++;
                        }
                    }
                    /**
                     * Refresh the preview if we have only panel placeholders, so the default homepage is displayed
                     * correctly.
                     *
                     * @link https://make.xwp.co/2015/12/08/implementing-selective-refresh-in-the-customizer/
                     */
                    if (panelsWithContent === 0) {
                        wp.customize.preview.send('refresh');
                    }
                }
            });
        }
    });
})();

The important part is the first section up to line 22 — after that, you can call the functions to get the wanted behavior for the reloaded markup.

Related posts

Leave a Comment

Your email address will not be published. Required fields are marked *