A Strategy for Custom Colors in the Customizer

The customizer is a framework for live-previewing any change to a WordPress site. It is particularly useful for previewing visual change and has always included a color control and the ability to easily preview custom colors. But the previewing experience has often been a bit slow. This post outlines a strategy for custom colors that leverages instant JS-based previewing in conjunction with selective refresh.

Animated gif of the linework theme with its colors changing via the customizer
Demo of instant custom color previews in the customizer with the Linework theme.

Example Plugin: Custom Highlight Color

I’ll leverage the custom highlight color plugin as an example of this approach. I recommend downloading it from WordPress.org to follow along with, and this post provides a detailed walkthrough of the code.

This plugin only has one option – the highlight color. However, this approach can easily scale to additional options. As I’ll show later, it’s best to minimize your options and instead rely on code logic to generate or select variations as needed so that users can achieve custom results with minimal effort and decision-making. Finding the right balance of color options is an important step in the product design process. Even the past couple of default WordPress themes leaned in the direction of too many color options, in my opinion.

Adding Customizer Objects

The first step is to register your color options in the customizer via the PHP API. Using the colors section provided by core, a theme or plugin only needs to register the setting and control. The transport will be postMessage, indicating that we’ll preview the setting with JavaScript:

function custom_highlight_color_customize( $wp_customize ) {
	$wp_customize->add_setting( 'custom_highlight_color', array(
		'type' => 'option', // Change to theme_mod when using in a theme.
		'default' => '#ff0',
		'sanitize_callback' => 'sanitize_hex_color',
		'transport' => 'postMessage',
	) );

	$wp_customize->add_control( new WP_Customize_Color_Control( $wp_customize, 'custom_highlight_color', array(
		'section' => 'colors',
		'label' => __( 'Highlight Color', 'custom-highlight-color' ),
	) ) );
}
add_action( 'customize_register', 'custom_highlight_color_customize' );

The setting will use sanitize_hex_color, ensuring that a single secure hex color code is saved in the database for each option. For themes, you should set the type to theme_mod instead of option, and it’ll be stored with the rest of the theme-specific options automatically.

Color Patterns and Calculations

Next, we need to define the CSS that will display the custom color options. By putting this into a distinct function, the code is reusable across multiple preview and output contexts. When there’s a lot of CSS, I prefer breaking it into a separate file to ease maintenance. You can even split distinct parts of the color CSS into different functions. For a simple example, here’s what Custom Highlight Color does:

function custom_highlight_color_css() {
	require_once( 'color-calculations.php' ); // Load the color calculations library.
	$background = get_option( 'custom_highlight_color', '#ff0' ); // The second argument is the default color when the theme mod is undefined.
	// Set the text color to black or white, whichever provides higher contrast with the highlight color.
	if ( custom_highlight_color_contrast_ratio( $background, '#000' ) > custom_highlight_color_contrast_ratio( $background, '#fff' ) ) {
		$color = '#000';
	} else {
		$color = '#fff';
	}

	$css = '
		::-moz-selection {
			background: ' . $background . ';
			color: ' . $color . ';
		}
		::selection {
			background: ' . $background . ';
			color: ' . $color . ';
		}';
	return $css;
}

You’ll notice that there are some color contrast checks here, which automatically set the text color to ensure that it contrasts with the highlight color. In this case it looks for the higher contrast between two colors, but typically you’ll want to ensure that the contrast is at least 4.5 between background and text colors. These checks leverage the color-calculations.php functions that I originally developed for the Fourteen Colors plugin. Feel free to take this file from the custom highlight color plugin and ship it with your project (make sure you update the function prefixes to match your plugin or theme).

In addition to the contrast check (which is done per the WCAG guidelines), the color calculations library has a handy function to “adjust” a color. With this technique you can brighten or darken a color by a numeric amount, generating color variations automatically. The Fourteen Colors plugin uses this technique extensively.

Color Output

Now that our color patterns are defined, it’s easy to display the color CSS within style tags in wp_head. However, in the customizer preview, we also need an easy way to get the current colors in JavaScript. To do that, we’ll conditionally add the colors as data- attributes when is_customize_preview():

add_action( 'wp_head', 'custom_highlight_color' );
function custom_highlight_color() {
	if ( is_customize_preview() ) { 
		$data = 'data-color="' . get_option( 'custom_highlight_color', '#ff0' ) . '"'; 
	} else {
		$data = '';
	}
?>
	<style type="text/css" id="custom-highlight-color" <?php echo $data; ?>>
		<?php echo custom_highlight_color_css(); ?>
	</style>
<?php }

The colors should now display on the front end, but they won’t preview in the customizer just yet.

Instant Custoizer Previews with JavaScript

To preview the color changes instantly in the customizer, we first need to enqueue a JS file to manage color previews (if your theme already loads a customizer JS file, you can add to that in lieu of introducing another one):

function custom_highlight_color_customize_preview_js() {
	wp_enqueue_script( 'custom_highlight_color_customizer', plugins_url( '/customizer.js', __FILE__ ), array( 'customize-preview' ), '20160830', true );
}
add_action( 'customize_preview_init', 'custom_highlight_color_customize_preview_js' );

In that file, we’ll follow the standard customizer preview conventions and bind to changes on our settings. For each of the colors, we’ll search for instances of the original color in the CSS, and replace them with the new color:

( function( $ ) {
	wp.customize( 'custom_highlight_color', function( value ) {
		value.bind( function( to ) {
			// Update custom color CSS
			var style = $( '#custom-highlight-color' ),
			    color = style.data( 'color' ),
			    css = style.html();
			//css = css.replace( color, to );
			css = css.split( color ).join( to ); // equivalent to css.replaceAll.
			style.html( css )
			     .data( 'color', to );
		} );
	} );
} )( jQuery );

You’ll need to bind changes to each of your color settings if you have multiple color options. Now, you’ll be able to preview color changes instantly in the customizer. But what about the colors generated using color calculations in PHP?

Adding Selective Refresh for Secondary Colors

To supplement the instant JS previewing that updates the CSS with a search-and-replace of the color value, we need to add selective refresh support so that the CSS is re-rendered from PHP with our color calculations applied. We could duplicate the color patterns and calculations in JS. But that would become quite difficult to maintain and offers only a slight usability benefit. With selective refresh, we can leverage the existing function in PHP; it’s only a matter of adding a customizer partial that will be refreshed when one of the associated colors changes:

$wp_customize->selective_refresh->add_partial( 'custom_highlight_color', array(
	'selector'        => '#custom-highlight-color',
	'settings'        => array( 'custom_highlight_color' ),
	'render_callback' => 'custom_highlight_color_css',
) );

This code should be added within the same callback to the customize_register action that we added earlier. We can associate multiple settings with a single partial; add the other setting ids to the array of settings.

Once that’s complete, you should be able to preview all of your custom colors in the customizer. There will be instant updates to base colors and updates to generated colors will occur on a slight delay. And we can safely store colors in the database without the security issues of saving CSS there, while applying styles on the front end by reusing the live preview CSS. Because I find this approach to provide a nice balance between user experience and code simplicity, I’m now leveraging it in all of my themes and plugins with color options.

The custom highlight color plugin is a simple example built specifically to be an example. This approach easily scales to more colors as needed. For a more complex example, check out the code for the Fourteen Colors Plugin or the Figure/Ground theme (which runs this site and lets users customize every color).