Variation Swatches Without a Plugin – Add a Color Variation

In this tutorial, I will show you how you can create variation swatches programmatically without using any plugins. However, if you change your mind and decide to switch to a plugin, I would highly recommend the one I developed myself.

As an example, we’re going to create a color variation. So, if by default, the variations are displayed like a select dropdown:

default variation switcher on WooCommerce product page
Wouldn’t it be better to add color variations here?

But we will learn how to display them as color swatches. This is our goal for this tutorial:

woocommerce variation swatches without plugin

1. Add a Custom Attribute Type

Let’s start with configuring things in the WooCommerce admin dashboard.

Right now, our goal is to create a new type of attribute, which is going to be a “Color” type:

Selecting a color attribute type in WooCommerce

This moment is pretty simple, and it seems like WooCommerce was supposed to have this functionality included because we don’t need to create custom fields like we usually need to do when working with regular WordPress taxonomies.

product_attributes_type_selector

The hook product_attributes_type_selector is pretty amazing, and all you need to do is to pass an additional attribute type to an array of attribute types.

add_filter( 'product_attributes_type_selector', 'rudr_add_attribute_type' );

function rudr_add_attribute_type( $types ) {

	$types[ 'color' ] = 'Color';
	return $types;
	
}

Even this small snippet of code will affect a lot of things on your website. Even the WooCommerce REST API will allow you to pass an attribute type other than select.

All right, here is the result:

Selecting a color attribute type in WooCommerce

woocommerce_product_option_terms

I assume the previous step seemed simple to you, however, it is not all we need to do when creating a custom color attribute type. The thing is that the attribute selection when editing a product doesn’t work with custom attribute types by default. Below is an example of what you’re expected to get:

attributes form is missing on edit product pages

It can be fixed pretty easily; however, just never forget about this step. The thing is that the attribute selection form should be additionally created for every custom attribute type! Below is how to do it:

<?php
add_action( 'woocommerce_product_option_terms', function( $attribute_taxonomy, $i, $attribute ) {

	// do nothing if it is not our custom attribute type
	if( 'color' !== $attribute_taxonomy->attribute_type ) {
		return;
	}

	// get current values
	$options = $attribute->get_options();
	$options = ! empty( $options ) ? $options : array();
	
	?>
	<select multiple="multiple" data-placeholder="Select color" class="multiselect attribute_values wc-enhanced-select" name="attribute_values[<?php echo $i ?>][]">
		<?php
			$colors = get_terms( 'pa_color', array( 'hide_empty' => 0 ) );
			if( $colors ) {
				foreach ( $colors as $color ) {
					$selected = wc_selected( $color->term_id, $options );
					echo "<option value=\"{$color->term_id}\"{$selected}>{$color->name}</option>";
				}
			}
		?>
	</select>
	<button class="button plus select_all_attributes">Select all</button>
	<button class="button minus select_no_attributes">Select none</button>
	<?php
}, 25, 3 );

In the code above, I skipped a couple of escaping functions for the sake of simplicity; however, don’t forget about them when developing your custom plugin.

Add a Color Picker Field to the Attribute Terms

We can change the attribute type now, which is great, but we also need to add a field to the attribute term editing form because we’re creating color variations, after all.

You can learn more about adding custom fields to term pages in this tutorial.

Long story short, below is the code you can use:

<?php
add_action( 'pa_color_edit_form_fields', function( $term, $taxonomy ){

	global $wpdb;

	$attribute_type = $wpdb->get_var(
		$wpdb->prepare(
			"
			SELECT attribute_type
			FROM " . $wpdb->prefix . "woocommerce_attribute_taxonomies
			WHERE attribute_name = '%s'
			",
			substr( $taxonomy, 3 ) // remove the "pa_" prefix
		)
	);

	// if it is not a color attribute, just do nothing
	if( 'color' !== $attribute_type ) {
		return;
	}

	// otherwise let's display our color picker field
	// we can use attribute type as a meta key why not
	$color = get_term_meta( $term->term_id, 'color', true );

	?>
		<tr class="form-field">
			<th><label for="term-color">Color</label></th>
			<td><input type="text" id="term-color" name="color" value="<?php echo esc_attr( $color ) ?>" /></td>
		</tr>
	<?php

}, 25, 2 );

add_action( 'edited_pa_color', function( $term_id ) {
	
	$color = ! empty( $_POST[ 'color' ] ) ? $_POST[ 'color' ] : '';
	update_term_meta( $term_id, 'color', sanitize_hex_color( $color ) );
	
} );

A couple of things to keep in mind about that code:

  • I created an attribute “Color”, and its slug is color (matches the attribute type in our case). That also means that the taxonomy name is always going to be pa_color. A custom field name is also color. But it is not necessary for all of them to be the same.
  • In order to deal with less amount of code in our example, I decided to add the color picker field only on “Edit term” pages. To do so, I used TAXONOMY NAME_edit_form_fields, but you can also add it to “Add term” pages with TAXONOMY NAME_add_form_fields.
  • Never forget about sanitizing functions, so for hex color values, I used the sanitize_hex_color() function.

Last but not least in this chapter, we need to add a color picker functionality itself, so shop managers don’t need to type a color manually like #fff or something.

WordPress already has color picker libraries in the code, you can include them using this small code snippet:

add_action( 'admin_enqueue_scripts', function() {
	// we don't want to include the color picker script on every admin page
	$screen = get_current_screen();
	if( false === strpos( $screen->id, 'edit-pa_' ) ) {
		return;
	}
	
	wp_enqueue_script( 'wp-color-picker' );
} );

I decided not to use an exact screen ID edit-pa_color because who knows, maybe an attribute will be created with another taxonomy slug, for example, fabric_color or something.

The jQuery code that activates the color picker for our custom field:

jQuery( function( $ ) {

	$( '#term-color' ).wpColorPicker();
	
} );

In case everything has been done correctly, we can enjoy our brand new color picker field when you edit attributes of a color type.

Creating a color picker field for WooCommerce color attributes.

Add Color Variations (Swatches) on Product Pages

Finally, we have finished with configuring the admin dashboard part, and we’re ready to add color variations to our WooCommerce store pages.

Specifically, we’re going to work with single product pages below. If you’re interested in how to add them on the shop and category pages, either check another tutorial or my variation swatches plugin.

This part comes to using the woocommerce_dropdown_variation_attribute_options_html filter hook to create custom color swatches, and we’re also going to use some CSS and JS to make it look good and to work correctly.

add_filter( 'woocommerce_dropdown_variation_attribute_options_html', 'rudr_swatches_html', 20, 2 );

function rudr_swatches_html( $html, $args ){

	global $wpdb;

	$taxonomy = $args[ 'attribute' ];
	$product = $args[ 'product' ];

	$attribute_type = $wpdb->get_var(
		$wpdb->prepare(
			"
			SELECT attribute_type
			FROM " . $wpdb->prefix . "woocommerce_attribute_taxonomies
			WHERE attribute_name = '%s'
			",
			substr( $taxonomy, 3 ) // remove "pa_" prefix
		)
	);

	// if it is not a color attribute, just do nothing
	if( 'color' !== $attribute_type ) {
		return $html;
	}

	// the thing is that we do not remove original dropdown, just hide it
	$html = '<div style="display:none">' . $html . '</div>';

	// then we display the swatches

	// in order to do so we loop all attributes in a taxonomy
	$colors = wc_get_product_terms( $product->get_id(), $taxonomy );

	foreach( $colors as $color ) {
		if( in_array( $color->slug, $args[ 'options' ] ) ) {
			// get the value of a color picker actually
			$hex_color = get_term_meta( $color->term_id, 'color', true );
			// add class for a selected color swatch
			$selected = $args[ 'selected' ] === $color->slug ? 'color-selected' : '';

			$html .= sprintf(
				'<span class="swatch %s" style="background-color:%s;" title="%s" data-value="%s"></span>',
				$selected,
				$hex_color,
				$color->name,
				$color->slug
			);
		}
	}

	return $html;

}

CSS:

/* color swatches styles */
.swatch {
	width: 30px;
	height: 30px;
	display: inline-block;
	margin-right: 10px;
	cursor:pointer;
	border: 1px solid #fff;
	outline: 2px solid #fff;
}
.swatch.selected{
	outline: 2px solid #333;
}

JavaScript:

$( '.variations_form' ).on( 'click', '.swatch', function ( e ) {

	const el = $( this ),
	      // original select dropdown with variations
	      select = el.closest( '.value' ).find( 'select' ),
	      // color slugs, like "coral", "grey" etc
	      value = el.data( 'value' )


	el.addClass( 'selected' ).siblings( '.selected' ).removeClass( 'selected' )
	select.val( value )
	select.change()

} )

As you might have noticed, we are just going to trick WooCommerce to make it think that customers click on the original variation dropdown when they do not.

Finally, the result:

woocommerce variation swatches without plugin

Of course, if you’re having some difficulties with implementing this code on your website, take a look at my Simple Variation Swatches for WooCommerce plugin.

Misha Rudrastyh

Misha Rudrastyh

Hey guys and welcome to my website. For more than 15 years I've been doing my best to share with you some superb WordPress guides and tips for free.

Need some developer help? Contact me

Follow me on X