Set WooCommerce product variation thumbnail by attribute

WooCommerce allows you to assign a thumbnail to each of your product variations. If you have a lot of variations, this will be very time-consuming. In some cases, it would be more convenient to assign a thumbnail to each attribute term.

If you’re selling T-shirts for example, you would have 2 attributes: color and size. Each color would need a unique image, no matter what size it is.

There are 2 big steps in this guide:

  1. Admin: Add thumbnail fields for each term (red, green, blue, …) in a certain attribute (color)
  2. Frontend: Replace the default thumbnail by this thumbnail whenever a variation is displayed on the product page

1. Admin: Add thumbnail fields

Fig. 1: Fields for each attribute term

1.1 Add a custom product data tab

add_filter( 'woocommerce_product_data_tabs', function( $tabs ) {

	$tabs['variation_images'] = array(
		'label'    => __( 'Variation images', 'woocommerce' ),
		'target'   => 'variation_images',
		'class'    => array( 'show_if_variable' ),
		'priority' => 65,
	);

	return $tabs;
	
} );

1.2 Add fields to this tab

<?php
add_action( 'woocommerce_product_data_panels', function(){
	global $post, $thepostid, $product_object;
	?>
	<div id="variation_images" class="panel woocommerce_options_panel hidden">
		<div class="options_group show_if_variable">
			<div class="options_group">
				<?php if( $product_object->is_type( 'variable' ) ): ?>
					<?php $product_variation_attributes = $product_object->get_variation_attributes(); ?>
					<?php if ( $product_object->is_type( 'variable' ) && $product_variation_attributes ) : ?>
						<?php foreach ( $product_variation_attributes as $attribute_name => $product_terms ) : ?>
							<table class="widefat striped table-attribute-thumbnails">
								<thead>
									<tr>
										<th colspan="2"><strong><?php echo wc_attribute_label( $attribute_name ); ?></strong></th>
									</tr>
								</thead>
								<tbody>
									<?php foreach ( $product_terms as $product_term ) : ?>
										<tr>
											<th>
												<?php echo esc_html( ucfirst( $product_term ) ); ?>
											</th>
											<td>
												<?php
												$image_id = get_post_meta( $thepostid, 'variation_image_' . $attribute_name . '_' . $product_term, true );
												$thumbnail = wp_get_attachment_image( $image_id, 'thumbnail' );
												if ( $thumbnail ) {
													printf( '<a href="#" class="btn-media-upload">%s</a><br /><a href="#" class="btn-media-remove">%s</a>', $thumbnail, __( 'Remove image', 'wc-variation-general-thumbnail' ) );
												} else {
													printf( '<a href="#" class="btn-media-upload">Upload image</a><a href="#" class="btn-media-remove" style="display:none">%s</a>', __( 'Remove image', 'wc-variation-general-thumbnail' ) );
												}
												?>
												<input type="hidden" name="variation_images[<?php echo esc_html( $attribute_name ); ?>][<?php echo esc_html( $product_term ); ?>]" value="<?php echo esc_html( get_post_meta( $thepostid, 'variation_image_' . $attribute_name . '_' . $product_term, true ) ); ?>">
											</td>
										</tr>
									<?php endforeach; ?>
								</tbody>
							</table>
						<?php endforeach; ?>
						<?php wp_nonce_field( 'variation_images_' . $product_object->get_ID(), 'save_variation_images' ); ?>
					<?php endif; ?>
				<?php endif; ?>
			</div>
		</div>
	</div>
	<?php
} );
?>

1.3 Save fields

add_action( 'woocommerce_process_product_meta_variable', function( $post_id ) {
	if ( isset( $_POST['variation_images'] ) && check_admin_referer( 'variation_images_' . $post_id, 'save_variation_images' ) ) {
		$attributes = wp_unslash( $_POST['variation_images'] );
		foreach ( $attributes as $attribute => $terms ) {
			foreach ( $terms as $term => $image ) {
				if ( $image ) {
					update_post_meta( $post_id, 'variation_image_' . $attribute . '_' . $term, filter_var( $image, FILTER_SANITIZE_STRING ) );
				} else {
					delete_post_meta( $post_id, 'variation_image_' . $attribute . '_' . $term );
				}
			}
		}
	}
} );

1.4 Some JavaScript to enable the WordPress media library

This code was based on Misha Rudrastyh’s blog post: https://rudrastyh.com/wordpress/customizable-media-uploader.html

jQuery(document).ready(function($){
	// on upload button click
	$('body').on( 'click', '.btn-media-upload', function(e){
 
		e.preventDefault();
 
		var button = $(this),
		custom_uploader = wp.media({
			title: 'Insert image',
			library : {
				// uploadedTo : wp.media.view.settings.post.id, // attach to the current post?
				type : 'image'
			},
			button: {
				text: 'Use this image' // button label text
			},
			multiple: false
		}).on('select', function() { // it also has "open" and "close" events
			var attachment = custom_uploader.state().get('selection').first().toJSON();
			button.html('<img src="' + attachment.sizes.thumbnail.url + '">').next().val(attachment.id).next().show();
			button.parent().find('input').val(attachment.id)
			button.parent().find('.btn-media-remove').show();
		}).open();
 
	});
 
	// on remove button click
	$('body').on('click', '.btn-media-remove', function(e){
 
		e.preventDefault();
 
		var button = $(this);
		button.parent().find('input').val('')
		button.hide()
		button.parent().find('.btn-media-upload').html('Upload image');
	});
});

1.5 Style the table

.table-attribute-thumbnails {
  border: 0 !important;
}

.table-attribute-thumbnails thead {
  background-color: #007cba;
}

.table-attribute-thumbnails thead tr th {
  color: white;
}

2. Frontend: Replace the thumbnail

WooCommerce allows us to customize a variation before it is displayed with the woocommerce_available_variation filter. First we need to check if an image is explicitly defined for this variation, if so, display this image instead of our global attribute term thumbnail.

After this, we iterate each of this product’s attribute terms and see if we defined a thumbnail. If so, we replace the default thumbnail by the term thumbnail.

add_filter( 'woocommerce_available_variation', function( $attr, $product, $variation ) {

	// Get the variation image.
	$default_image = get_post_meta( $variation->get_ID(), '_thumbnail_id', true );

	// Only find the attribute image if no default image is set.
	if ( ! $default_image ) {
		$attributes = $variation->get_variation_attributes();
		foreach ( $attributes as $attribute_name => $value ) {
			$stripped_attribute = str_replace( 'attribute_', '', $attribute_name );
			$attribute_image = get_post_meta( $product->get_ID(), 'variation_image_' . $stripped_attribute . '_' . $value, true );
			if ( $attribute_image ) {
				$attr['image'] = wc_get_product_attachment_props( $attribute_image );
				break;
			}
		}
	}

	return $attr;

}, 10, 3 );

3. Caveats

  • The product needs to be saved before these thumbnail fields are displayed in the admin. So you need to add your attributes & terms, save your product. The page gets refreshed and will display the thumbnail fields.
  • If you set thumbnails for multiple attributes, e.g. size & color, only the first one will show.

4. Plugin

This code is available as a WooCommerce Extension on Github: https://github.com/tombroucke/otomaties-woocommerce-variation-general-thumbnail

Leave a Reply

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

Overtuigd?

Neem dan contact op voor een offerte of vrijblijvend gesprek.
Stuur een e-mail naar [email protected] of maak gebruik van het contactformulier.