---
description: http://justintadlock.com/archives/2015/06/04/customizer-radio-image-control
---

# Customizer radio image control (ok)

<figure><img src="https://2370029328-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LWPtKFbhw0XehxVuoiZ%2Fuploads%2FsY9ewFDnAPCkOxGJItqN%2Fimage.png?alt=media&#x26;token=2e88b56a-1b1a-4071-81d1-625351bbc921" alt=""><figcaption></figcaption></figure>

C:\xampp82\htdocs\wp4\wp-content\themes\auto\functions.php

```php
<?php
add_action( 'customize_register', 'jt_customize_register' );
function jt_customize_register( $wp_customize ) {
	// Load the radio image control class.
	require_once( trailingslashit( get_template_directory() ) . 'customize/control-radio-image.php' );
	// Register the radio image control class as a JS control type.
	$wp_customize->register_control_type( 'JT_Customize_Control_Radio_Image' );
	// Add a custom layout section.
	$wp_customize->add_section( 'layout', array( 'title' => esc_html__( 'Layout', 'jt' ) ) );
	// Add the layout setting.
	$wp_customize->add_setting(
		'layout',
		array(
			'default'           => 'content-sidebar',
			'sanitize_callback' => 'sanitize_key',
		)
	);
	// Add the layout control.
	$wp_customize->add_control(
		new JT_Customize_Control_Radio_Image(
			$wp_customize,
			'layout',
			array(
				'label'    => esc_html__( 'Layout', 'jt' ),
				'section'  => 'layout',
				'choices'  => array(
					'content-sidebar' => array(
						'label' => esc_html__( 'Content / Sidebar', 'jt' ),
						'url'   => '%s/images/content-sidebar.png'
					),
					'sidebar-content' => array(
						'label' => esc_html__( 'Sidebar / Content', 'jt' ),
						'url'   => '%s/images/sidebar-content.png'
					),
					'content' => array(
						'label' => esc_html__( 'Content - One Column', 'jt' ),
						'url'   => '%s/images/content.png'
					)
				)
			)
		)
	);
}
```

C:\xampp82\htdocs\wp4\wp-content\themes\auto\customize\control-radio-image.php

```php
<?php
/**
 * Radio image customize control.
 *
 * @since  1.0.0
 * @access public
 */
class JT_Customize_Control_Radio_Image extends WP_Customize_Control {
	/**
	 * The type of customize control being rendered.
	 *
	 * @since  1.0.0
	 * @access public
	 * @var    string
	 */
	public $type = 'radio-image';
	/**
	 * Loads the jQuery UI Button script and custom scripts/styles.
	 *
	 * @since  1.0.0
	 * @access public
	 * @return void
	 */
	public function enqueue() {
		wp_enqueue_script( 'jquery-ui-button'          );
		wp_enqueue_script( 'jt-customize-controls', get_template_directory_uri() . '/js/customize-controls.js', array( 'jquery' ) );
		wp_enqueue_style(  'jt-customize-controls', get_template_directory_uri() . '/css/customize-controls.css'                  );
	}
	/**
	 * Add custom JSON parameters to use in the JS template.
	 *
	 * @since  1.0.0
	 * @access public
	 * @return void
	 */
	public function to_json() {
		parent::to_json();
		// We need to make sure we have the correct image URL.
		foreach ( $this->choices as $value => $args )
			$this->choices[ $value ]['url'] = esc_url( sprintf( $args['url'], get_template_directory_uri(), get_stylesheet_directory_uri() ) );
		$this->json['choices'] = $this->choices;
		$this->json['link']    = $this->get_link();
		$this->json['value']   = $this->value();
		$this->json['id']      = $this->id;
	}
	/**
	 * Underscore JS template to handle the control's output.
	 *
	 * @since  1.0.0
	 * @access public
	 * @return void
	 */
	public function content_template() { ?>
		<# if ( ! data.choices ) {
			return;
		} #>
		<# if ( data.label ) { #>
			<span class="customize-control-title">{{ data.label }}</span>
		<# } #>
		<# if ( data.description ) { #>
			<span class="description customize-control-description">{{{ data.description }}}</span>
		<# } #>
		<div class="buttonset">
			<# for ( key in data.choices ) { #>
				<input type="radio" value="{{ key }}" name="_customize-{{ data.type }}-{{ data.id }}" id="{{ data.id }}-{{ key }}" {{{ data.link }}} <# if ( key === data.value ) { #> checked="checked" <# } #> />
				<label for="{{ data.id }}-{{ key }}">
					<span class="screen-reader-text">{{ data.choices[ key ]['label'] }}</span>
					<img src="{{ data.choices[ key ]['url'] }}" alt="{{ data.choices[ key ]['label'] }}" />
				</label>
			<# } #>
		</div><!-- .buttonset -->
	<?php }
}
```

C:\xampp82\htdocs\wp4\wp-content\themes\auto\css\customize-controls.css

```css
.customize-control-radio-image .ui-button {
  margin: 0;
  border-radius: 0;
  border: none;
  background: transparent;
}
.customize-control-radio-image .ui-button-text {
  padding: 0;
}
.customize-control-radio-image img {
  box-sizing: border-box;
  max-width: 100%;
  height: auto;
  padding: 1px;
  border: 4px solid transparent;
}
.customize-control-radio-image img:hover,
.customize-control-radio-image img:focus {
  border-color: #ddd;
}
.customize-control-radio-image .ui-state-active img {
  border-color: #00a0d2;
}

```

C:\xampp82\htdocs\wp4\wp-content\themes\auto\js\customize-controls.js

```javascript
jQuery(document).ready(function () {
  // Use buttonset() for radio images.
  jQuery('.customize-control-radio-image .buttonset').buttonset();
  // Handles setting the new value in the customizer.
  jQuery('.customize-control-radio-image input:radio').change(
    function () {
      // Get the name of the setting.
      var setting = jQuery(this).attr('data-customize-setting-link');
      // Get the value of the currently-checked radio input.
      var image = jQuery(this).val();
      // Set the new value.
      wp.customize(setting, function (obj) {
        obj.set(image);
      });
    }
  );
}); // jQuery( document ).ready
```

###

<div><figure><img src="https://2370029328-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LWPtKFbhw0XehxVuoiZ%2Fuploads%2FYPzltgtrlNmMn9Yrxn32%2Fcontent.png?alt=media&#x26;token=d19355ab-9fec-4d81-8297-0e04f25c37c2" alt=""><figcaption></figcaption></figure> <figure><img src="https://2370029328-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LWPtKFbhw0XehxVuoiZ%2Fuploads%2FHMuGdwZtbVkpariNs04n%2Fcontent-sidebar.png?alt=media&#x26;token=d9be4788-7cd1-45cd-98a5-f51c77b547da" alt=""><figcaption></figcaption></figure> <figure><img src="https://2370029328-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LWPtKFbhw0XehxVuoiZ%2Fuploads%2FBlfhpXDyMauORsbJhCIF%2Fsidebar-content.png?alt=media&#x26;token=9eb309a8-6475-4b7a-ace6-22d12b094402" alt=""><figcaption></figcaption></figure></div>

### Vấn đề 1: Xem dữ liệu của to\_json()



![](https://2370029328-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LWPtKFbhw0XehxVuoiZ%2Fuploads%2FUrq8FGIAJb2NQHaH4AnA%2FScreenshot_1.png?alt=media\&token=cd07c3a0-3864-41c4-8f36-3a39aaa97cfb)

code

```
public function content_template() {?>
    <# console.log(data); if ( ! data.choices ) {
      return;
    } #>
    <# if ( data.label ) { #>
      <span class="customize-control-title">{{ data.label }}</span>
    <# } #>
    <# if ( data.description ) { #>
      <span class="description customize-control-description">{{{ data.description }}}</span>
    <# } #>
    <div class="buttonset">
      <# for ( key in data.choices ) { #>
        <input type="radio" value="{{ key }}" name="_customize-{{ data.type }}-{{ data.id }}" id="{{ data.id }}-{{ key }}" {{{ data.link }}} <# if ( key === data.value ) { #> checked="checked" <# } #> />
        <label for="{{ data.id }}-{{ key }}">
          <span class="screen-reader-text">{{ data.choices[ key ]['label'] }}</span>
          <img src="{{ data.choices[ key ]['url'] }}" alt="{{ data.choices[ key ]['label'] }}" />
        </label>
      <# } #>
    </div><!-- .buttonset -->
  <?php }
```

![](https://2370029328-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LWPtKFbhw0XehxVuoiZ%2Fuploads%2F0ztDWJXNB7Ck3yUknp4C%2FScreenshot_2.png?alt=media\&token=67d50ac8-0ba4-4c44-b499-a299e584abf1)

Code

```
public function to_json() {
    parent::to_json();
    // We need to make sure we have the correct image URL.
    foreach ($this->choices as $value => $args) {
      $this->choices[$value]['url'] = esc_url(sprintf($args['url'], get_template_directory_uri(), get_stylesheet_directory_uri()));
    }
    $this->json['choices'] = $this->choices;
    $this->json['link']    = $this->get_link();
    $this->json['value']   = $this->value();
    $this->json['id']      = $this->id;
    $this->json['description'] = 'description';
  }
```

![](https://2370029328-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LWPtKFbhw0XehxVuoiZ%2Fuploads%2FzJza93lMfdFF7IlWkJmZ%2FScreenshot_3.png?alt=media\&token=6312edd9-b0f2-418f-83d2-297a893bc282)

### Vấn đề 2: Đăng ký WP\_Customize\_Control

![](https://2370029328-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LWPtKFbhw0XehxVuoiZ%2Fuploads%2FFT3vEAOMjrF7SY3Q2dhv%2FScreenshot_4.png?alt=media\&token=b04aa172-970d-4f4a-bd93-aa4e5734799d)

![](https://2370029328-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LWPtKFbhw0XehxVuoiZ%2Fuploads%2FBvgDrC9MjWJqqQKAzSJs%2FScreenshot_5.png?alt=media\&token=03324434-d28d-48e8-b8c0-bc42502f5bee)

## [Justin Tadlock](https://justintadlock.com/)

* [About](https://justintadlock.com/about)
* [Archives](https://justintadlock.com/archives)
* [Contact](https://justintadlock.com/contact)
* [Writing](https://justintadlock.com/writing)
* [Feed](https://justintadlock.com/feed)

June 4, 2015

## Customizer radio image control

<figure><img src="https://justintadlock.com/user/media/2015/06/layout-customizer-control.png" alt="Layout customizer control" height="337" width="298"><figcaption></figcaption></figure>

In this tutorial, I’ll be writing about a radio image control for the WordPress customizer. This was a request, but I honestly don’t remember who asked for it. Sorry for forgetting. I hope you’re following the blog. :)

This type of control is also something I’ve needed for a long while. It’s now being used in the revamped layout setting in the [Hybrid Core](http://themehybrid.com/hybrid-core) framework.

Basically, a radio image control replaces your standard `<input type="radio" />` fields with selectable images. So, it’s pretty cool for things like selecting a layout or any other setting where it’d be nice to have a visual representation of the option.

Like other advanced customizer tutorials, I’ll be moving through this fast and not explaining each detail. You need to be at least somewhat familiar with building settings in the customizer before moving forward.

### Building the radio image control class <a href="#building-the-radio-image-control-class" id="building-the-radio-image-control-class"></a>

The first thing we need to do is build a custom control class that extends `WP_Customize_Class`. So, create a new file called `control-radio-image.php` in your theme’s `/customize` folder (or whatever structure you prefer) and place the following code into it.

Fair warning for those of you studying the code: you may be used to seeing a `render_content()` method in custom control classes. I opted to go with a JS template via the `content_template()` method. See [core ticket #30738](https://core.trac.wordpress.org/ticket/30738) for the main reason why. Admittedly, I’m a bit out of my element working with JS templates, but the best way to learn is to simply do and to teach others by writing about it. Feel free to correct anything I screw up.

```
<?php

/**
 * Radio image customize control.
 *
 * @since  1.0.0
 * @access public
 */
class JT_Customize_Control_Radio_Image extends WP_Customize_Control {

	/**
	 * The type of customize control being rendered.
	 *
	 * @since  1.0.0
	 * @access public
	 * @var    string
	 */
	public $type = 'radio-image';

	/**
	 * Loads the jQuery UI Button script and custom scripts/styles.
	 *
	 * @since  1.0.0
	 * @access public
	 * @return void
	 */
	public function enqueue() {
		wp_enqueue_script( 'jquery-ui-button'          );
		wp_enqueue_script( 'jt-customize-controls', get_template_directory_uri() . '/js/customize-controls.js', array( 'jquery' ) );
		wp_enqueue_style(  'jt-customize-controls', get_template_directory_uri() . '/css/customize-controls.css'                  );
	}

	/**
	 * Add custom JSON parameters to use in the JS template.
	 *
	 * @since  1.0.0
	 * @access public
	 * @return void
	 */
	public function to_json() {
		parent::to_json();

		// We need to make sure we have the correct image URL.
		foreach ( $this->choices as $value => $args )
			$this->choices[ $value ]['url'] = esc_url( sprintf( $args['url'], get_template_directory_uri(), get_stylesheet_directory_uri() ) );

		$this->json['choices'] = $this->choices;
		$this->json['link']    = $this->get_link();
		$this->json['value']   = $this->value();
		$this->json['id']      = $this->id;
	}

	/**
	 * Underscore JS template to handle the control's output.
	 *
	 * @since  1.0.0
	 * @access public
	 * @return void
	 */
	public function content_template() { ?>

		<# if ( ! data.choices ) {
			return;
		} #>

		<# if ( data.label ) { #>
			<span class="customize-control-title">{{ data.label }}</span>
		<# } #>

		<# if ( data.description ) { #>
			<span class="description customize-control-description">{{{ data.description }}}</span>
		<# } #>

		<div class="buttonset">

			<# for ( key in data.choices ) { #>

				<input type="radio" value="{{ key }}" name="_customize-{{ data.type }}-{{ data.id }}" id="{{ data.id }}-{{ key }}" {{{ data.link }}} <# if ( key === data.value ) { #> checked="checked" <# } #> />

				<label for="{{ data.id }}-{{ key }}">
					<span class="screen-reader-text">{{ data.choices[ key ]['label'] }}</span>
					<img src="{{ data.choices[ key ]['url'] }}" alt="{{ data.choices[ key ]['label'] }}" />
				</label>
			<# } #>

		</div><!-- .buttonset -->
	<?php }
}
```

### Loading scripts and styles <a href="#loading-scripts-and-styles" id="loading-scripts-and-styles"></a>

In the class above, you probably noticed that I enqueued a few scripts and styles. The jQuery UI `buttonset()` is the primary script that handles replacing the radio inputs with images. It’s included with WP, so we merely need to load it.

We also need a custom JS script to apply the `buttonset()` to our radio inputs and to handle the customizer setting when it changes. Place the following code in your theme’s `/js/customize-controls.js` file:

```
jQuery( document ).ready( function() {

	// Use buttonset() for radio images.
	jQuery( '.customize-control-radio-image .buttonset' ).buttonset();

	// Handles setting the new value in the customizer.
	jQuery( '.customize-control-radio-image input:radio' ).change(
		function() {

			// Get the name of the setting.
			var setting = jQuery( this ).attr( 'data-customize-setting-link' );

			// Get the value of the currently-checked radio input.
			var image = jQuery( this ).val();

			// Set the new value.
			wp.customize( setting, function( obj ) {

				obj.set( image );
			} );
		}
	);

} ); // jQuery( document ).ready
```

And, we need a little bit of custom CSS to handle styling the control. Place the following code in your theme’s `/css/customize-controls.css` file.

```
.customize-control-radio-image .ui-button {
	margin:        0;
	border-radius: 0;
	border:        none;
	background:    transparent;
}

.customize-control-radio-image .ui-button-text { padding: 0; }

.customize-control-radio-image img {
	box-sizing: border-box;
	max-width:  100%;
	height:     auto;
	padding:    1px;
	border:     4px solid transparent;
}

	.customize-control-radio-image img:hover,
	.customize-control-radio-image img:focus {
		border-color: #ddd;
	}

	.customize-control-radio-image .ui-state-active img {
		border-color: #00a0d2;
	}
```

### Actually using the radio input control <a href="#actually-using-the-radio-input-control" id="actually-using-the-radio-input-control"></a>

_OK, so you’ve got everything in place now._ Awesome. Yeah, there’s a bit of setup, but it’s pretty fun to play around with this thing.

At this point, you just have a final step before doing cool stuff.

The following code is an example of using the custom control to output a layout setting with images that represent the various layouts. Note that you’ll actually need to replace the image URLs in the code with something relevant to your theme.

```
add_action( 'customize_register', 'jt_customize_register' );

function jt_customize_register( $wp_customize ) {

	// Load the radio image control class.
	require_once( trailingslashit( get_template_directory() ) . 'customize/control-radio-image.php' );

	// Register the radio image control class as a JS control type.
	$wp_customize->register_control_type( 'JT_Customize_Control_Radio_Image' );

	// Add a custom layout section.
	$wp_customize->add_section( 'layout', array( 'title' => esc_html__( 'Layout', 'jt' ) ) );

	// Add the layout setting.
	$wp_customize->add_setting(
		'layout',
		array(
			'default'           => 'content-sidebar',
			'sanitize_callback' => 'sanitize_key',
		)
	);

	// Add the layout control.
	$wp_customize->add_control(
		new JT_Customize_Control_Radio_Image(
			$wp_customize,
			'layout',
			array(
				'label'    => esc_html__( 'Layout', 'jt' ),
				'section'  => 'layout',
				'choices'  => array(
					'content-sidebar' => array(
						'label' => esc_html__( 'Content / Sidebar', 'jt' ),
						'url'   => '%s/images/content-sidebar.png'
					),
					'sidebar-content' => array(
						'label' => esc_html__( 'Sidebar / Content', 'jt' ),
						'url'   => '%s/images/sidebar-content.png'
					),
					'content' => array(
						'label' => esc_html__( 'Content - One Column', 'jt' ),
						'url'   => '%s/images/content.png'
					)
				)
			)
		)
	);
}
```

Topics:[#WordPress Tutorials](https://justintadlock.com/topics/wordpress-tutorials)[#WordPress](https://justintadlock.com/topics/wordpress)

* [GitHub](https://github.com/justintadlock/)
* [WordPress](https://profiles.wordpress.org/greenshady)
* [Gutenberg Times](https://gutenbergtimes.com/author/jtadlock/)
* [WP Tavern](https://wptavern.com/author/justintadlock)
* [Twitter](https://twitter.com/justintadlock)
* [Facebook](https://facebook.com/justintadlock)
* [Goodreads](https://goodreads.com/justintadlock)
* [Amazon](http://a.co/02ggsr2)
