Contextual customize partials

Animated preview of selectively refreshing the featured image size from the WordPress customizer.

While building the Exhale theme, my latest WordPress project, I wanted to build a cool feature into the customizer. The idea was that the user would have an option to select their preferred featured image size. When selecting a size, their featured images would be refreshed in the preview panel without fully refreshing the entire preview.

That sounds pretty easy to do in theory. I’ve used the selective refresh feature many times since it became a core feature. In practice, what I found was there was no existing documentation on how to do this contextually.

By context I mean that I needed to figure out a way to pass around the post ID to refresh the featured image for each post shown in the preview panel.

After a lot of digging through undocumented code, I managed to stumble upon the data-customize-partial-placement-context HTML attribute, which is what needs to be set to get this to work.

In this tutorial, I’m going to share how I built this feature into my theme. However, you can use the method applied here for other features that need a context.

Building a class for output

The first thing I wanted to do is build a wrapper for the core get_the_post_thumbnail() function so that I’d have some consistency with the output of the image. So, I created a FeaturedImage class to handle the job. This primarily serves as a quick template tag within my theme templates, and it allows me to return the image in the customizer partial.

Another benefit is that I could control the attributes. Remember that data-customize-partial-placement-context attribute I mentioned? We can check if we’re in the customizer preview and add that if so. We only need to pass a post_id parameter back, but you can pass an entire array of parameters.

Here’s what my featured image class looks like:

namespace JT\Template;

class FeaturedImage {

	public static function display( $post = null ) {
		return static::render( $post );
	}

	public static function render( $post = null ) {

		$post = get_post( $post );

		if ( ! $post ) {
			return '';
		}

		$attr = [
			'class' => 'entry__image'
		];

		// If in the customizer, add a context to be passed back to the
		// partial's render method.
		if ( is_customize_preview() ) {

			// JSON encode our context.
			$context = wp_json_encode( [
				'post_id' => $post_id
			] );

			$attr['data-customize-partial-placement-context'] = esc_attr( $context );
		}

		return get_the_post_thumbnail(
			$post,
			get_theme_mod( 'featured_image_size', 'thumbnail' ),
			$attr
		);
	}
}

Selectively refreshing the featured image

In the customizer, we need to be able to re-render our featured images whenever a new featured image size is chosen. This way, the appropriate size is shown in the preview panel.

The most important bit of adding a customize partial is the following:

$manager->selective_refresh->add_partial( 'featured_media_size', [
	'selector'            => '.entry__image',
	'container_inclusive' => true,
	'fallback_refresh'    => false,
	'render_callback'     => function( $partial, $context ) {
		return isset( $content['post_id'] )
		       ? FeaturedImage::render( absint( $context['post_id'] ) )
		       : '';
		}
	}
] );

The render_callback function accepts two parameters: $partial and $context. The $context parameter will be the JSON-decoded array passed in earlier.

Here’s a full look at a customize class with the section, setting, control, and partial:

namespace JT\Customize;

use WP_Customize_Manager;
use JT\Template\FeaturedImage;

class Customize {

	// Call this to bootstrap.
	public function boot() {
		add_action( 'customize_register', [ $this, 'register' ] );
	}

	public function register( WP_Customize_Manager $manager ) {

		// Create a media section.
		$manager->add_section( 'media', [
			'title' => __( 'Media' )
		] );

		// Featured image size setting.
		$manager->add_setting( 'featured_image_size', [
			'default'           => 'thumbnail',
			'sanitize_callback' => 'sanitize_key',
			'transport'         => 'postMessage'
		] );

		// Featured image size control.
		$manager->add_control( 'featured_image_size', [
			'section' => 'media',
			'type'    => 'select',
			'label'   => esc_html__( 'Featured Image Size' ),
			'choices' => [
				'thumbnail' => __( 'Thumbnail' ),
				'medium'    => __( 'Medium' ),
				'large'     => __( 'Large' )
			]
		] );

		// Featured image size partial.
		if ( isset( $manager->selective_refresh ) ) {

			$manager->selective_refresh->add_partial( 'featured_media_size', [
				'selector'            => '.entry__image',
				'container_inclusive' => true,
				'fallback_refresh'    => false,
				'render_callback'     => function( $partial, $context ) {
					return isset( $content['post_id'] )
					       ? FeaturedImage::render( absint( $context['post_id'] ) )
					       : '';
					}
				}
			] );
		}
	}
}

Wrapping up

All that’s really left is calling <?php JT\Template\FeaturedImage::display() ?> in the appropriate theme template.

I hope this helps someone else along the way. It took me a lot of digging to find this little-explored feature of the WordPress customizer.