Contextual customize partials
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.