Adding custom controls to your Customization API

Image displaying various stars

In the last post, I talked about what the built in Customization API is and how to use it in your theme. Besides the built in customizer options like input fields, check boxes etc., there are few built in controls that you can use. But what if you want to enhance few of them, or add new ones? Then you’ll have to build your own.

Notice: This article was written in 2016. WordPress has changed a lot since then, so take this article with a grain of salt…

In your customizer.php right before you add the function for setting up your custom control (or at the top of the file), you’ll need to add

require_once 'custom_controls.php';

This will call for the aforementioned file, that is in the same place where our customizer.php  is, where we’ll define our custom controls. In the js folder you can place custom_controls.js and in the css folder custom_controls.css . In those files we’ll add any css styling and custom JavaScript that we might need for our controls.

Essentially, we’re adding custom controls in our customizer.php  with this kind of code:

$wp_customize->add_control(new MY_NEW_Custom_control($wp_customize, 'control_name',
    array( /*labels and additional description goes here*/
)));Code language: PHP (php)

But for it to work, we need to extend the built in WP_Customize_Control class with our own. Then when we want to add it, we create a new object out of our control. This way you can reuse this code as many times as you want (yay for object-oriented programming :D).

Let’s get on with our custom controls. If you know all about the ins and outs of custom controls, and just want to see what controls I have so far, just head on to my git repository and download the files. I update it when I find out some new and cool controls.

Custom check box switch

In your custom_controls.php  file wrap the whole thing in

if (class_exists('WP_Customize_Control')){}

to avoid any errors if the customizer isn’t present. The first control that we’ll create is the custom check box. Regular check boxes can be a bit dull. Why not add a bit of life to them? The full code is

class Toggle_Checkbox_Custom_control extends WP_Customize_Control{
	public $type = 'toogle_checkbox';
	public function enqueue(){
		wp_enqueue_style( 'custom_controls_css', get_template_directory_uri().'/inc/customizer/css/custom_controls.css');
	}
	public function render_content(){
		?>
		<div class="checkbox_switch">
			<div class="onoffswitch">
			    <input type="checkbox" id="<?php echo esc_attr($this->id); ?>" name="<?php echo esc_attr($this->id); ?>" class="onoffswitch-checkbox" value="<?php echo esc_attr( $this->value() ); ?>" <?php $this->link(); checked( $this->value() ); ?>>
			    <label class="onoffswitch-label" for="<?php echo esc_attr($this->id); ?>"></label>
			</div>
			<span class="customize-control-title onoffswitch_label"><?php echo esc_html( $this->label ); ?></span>
			<p><?php echo wp_kses_post($this->description); ?></p>
		</div>
		<?php
	}
}Code language: JavaScript (javascript)

So, we’ve created a Toggle_Checkbox_Custom_control . Inside each control we’ll enqueue our .js and .css files (if necessary). In our case we only need css, because we’re making styling changes after all. You’ll need to set up a type, and a method (a function) that will render your new control. In our case we’re added some additional wrappers to our check box. Remember, in the customizer.php we’re adding these controls by creating new objects. So $this will be a reference to that particular object. The usual object oriented approach. Now this is pretty straight forward. On to the css

.customize-control-checkbox label{
	margin-left: 0;
	padding-top: 0;
	padding-bottom: 0;
	line-height: 28px;
}

.onoffswitch_label{
	display: inline-block;
    vertical-align: top;
    margin-top: -1px;
    width: 200px;
}

.onoffswitch {
	position: relative;
	width: 40px;
	display: inline-block;
	float: right;
	-webkit-user-select:none;
	-moz-user-select:none;
	-ms-user-select: none;
}

.onoffswitch-checkbox {
	display: none!important;
}

.onoffswitch-label {
	display: block;
	overflow: hidden;
	cursor: pointer;
	height: 18px;
	padding: 0;
	line-height: 18px;
	border: 2px solid #9E9E9E;
	border-radius: 18px;
	background-color: #9E9E9E;
	transition: background-color 0.2s ease-in;
}

.onoffswitch-label:before {
	content: "";
	display: block;
	width: 18px;
	margin: 0;
	background: #EBEBEB;
	position: absolute;
	top: 0;
	bottom: 0;
	right: 20px;
	border: 2px solid #9E9E9E;
	border-radius: 18px;
	transition: all 0.2s ease-in 0s;
}

.onoffswitch-checkbox:checked + .onoffswitch-label {
	background-color: #42A5F5;
}

.onoffswitch-checkbox:checked + .onoffswitch-label,
.onoffswitch-checkbox:checked + .onoffswitch-label:before {
	border-color: #42A5F5;
}

.onoffswitch-checkbox:checked + .onoffswitch-label:before {
	right: 0;
}Code language: CSS (css)

I’ve borrowed the css from this freebies page. Now all you need to do is to add the newly created control to your main file.

/**
Custom Checkbox
**/
$wp_customize->add_setting('custom_checkbox', array(
	'default'           => false,
	'sanitize_callback' => 'mytheme_checkbox_sanitization',
));
$wp_customize->add_control(new Toggle_Checkbox_Custom_control($wp_customize, 'custom_checkbox', array(
	'label'    		=> esc_html__('Check me', 'mytheme'),
	'type'     		=> 'checkbox',
	'settings'		=> 'custom_checkbox',
	'section'  		=> 'section_custom_controls',
)));Code language: PHP (php)
Custom checkbox control
Our newly styled checkbox. Much better than the regular boring one :D

Custom information control

Next control will be a simple one – information. Say you just want to put a small notice in your section about the next few controls. This control will give you the option to do so.

class Info_Custom_control extends WP_Customize_Control{
	public $type = 'info';
	public function render_content(){
		?>
		<span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
		<p><?php echo wp_kses_post($this->description); ?></p>
		<?php
	}
}Code language: JavaScript (javascript)

This one doesn’t need any css – it’s just text after all. Add your control and voila!

/**
Info
**/
$wp_customize->add_setting('custom_info', array(
	'default'           => '',
	'sanitize_callback' => 'mytheme_text_sanitization',

));
$wp_customize->add_control(new Info_Custom_control($wp_customize, 'custom_info', array(
	'label'    		=> esc_html__('A custom notice', 'mytheme'),
	'description' 	=> esc_html__('There are times that you just need to say something.', 'mytheme'),
	'settings'		=> 'custom_info',
	'section'  		=> 'section_custom_controls',
)));Code language: PHP (php)
Custom information control
Custom control when you want to add some kind of notice text

Separator control

Next one is also a simple one – a separator


/* Custom Separator */

class Separator_Custom_control extends WP_Customize_Control{
	public $type = 'separator';
	public function render_content(){
		?>
		<p><hr></p>
		<?php
	}
}Code language: PHP (php)
/**
Separator
**/
$wp_customize->add_setting('separator_1', array(
	'default'           => '',
	'sanitize_callback' => 'esc_html',
));
$wp_customize->add_control(new Separator_Custom_control($wp_customize, 'separator_1', array(
	'settings'		=> 'separator_1',
	'section'  		=> 'section_custom_controls',
)));Code language: PHP (php)
custom separator control
You never know when you’ll need a separator

Multi input field

The next control is a multiple input field. Basically a type of repeater, when you need to add a list or what ever you might need (in the themes I was working on we used this to add new sidebars).

/* Multi Input field */

class Multi_Input_Custom_control extends WP_Customize_Control{
	public $type = 'multi_input';
	public function enqueue(){
		wp_enqueue_script( 'custom_controls', get_template_directory_uri().'/inc/customizer/js/custom_controls.js', array( 'jquery' ),'', true );
		wp_enqueue_style( 'custom_controls_css', get_template_directory_uri().'/inc/customizer/css/custom_controls.css');
	}
	public function render_content(){
		?>
		<label class="customize_multi_input">
			<span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
			<p><?php echo wp_kses_post($this->description); ?></p>
			<input type="hidden" id="<?php echo esc_attr($this->id); ?>" name="<?php echo esc_attr($this->id); ?>" value="<?php echo esc_attr($this->value()); ?>" class="customize_multi_value_field" data-customize-setting-link="<?php echo esc_attr($this->id); ?>"/>
			<div class="customize_multi_fields">
				<div class="set">
					<input type="text" value="" class="customize_multi_single_field"/>
					<a href="#" class="customize_multi_remove_field">X</a>
				</div>
			</div>
			<a href="#" class="button button-primary customize_multi_add_field"><?php esc_attr_e('Add More', 'mytheme') ?></a>
		</label>
		<?php
	}
}Code language: JavaScript (javascript)

For this control you’ll need some JavaScript

jQuery(document).ready(function($) {
    "use strict";

    // *************  Multi_Input_Custom_control  *********************

    function customize_multi_write($element){
        var customize_multi_val = '';
        $element.find('.customize_multi_fields .customize_multi_single_field').each(function(){
            customize_multi_val += $(this).val()+'|';
        });
        $element.find('.customize_multi_value_field').val(customize_multi_val.slice(0, -1)).change();
    }

    function customize_multi_add_field(e){
        e.preventDefault();
        var $control = $(this).parents('.customize_multi_input');
        $control.find('.customize_multi_fields').append('<div class="set"><input type="text" value="" class="customize_multi_single_field" /><a href="#" class="customize_multi_remove_field">X</a></div>');
    }

    function customize_multi_single_field() {
        var $control = $(this).parents('.customize_multi_input');
        customize_multi_write($control);
    }

    function customize_multi_remove_field(e){
        e.preventDefault();
        var $this = $(this);
        var $control = $this.parents('.customize_multi_input');
        $this.parent().remove();
        customize_multi_write($control);
    }

    $(document).on('click', '.customize_multi_add_field', customize_multi_add_field)
               .on('keyup', '.customize_multi_single_field', customize_multi_single_field)
               .on('click', '.customize_multi_remove_field', customize_multi_remove_field);

    $('.customize_multi_input').each(function(){
        var $this = $(this);
        var multi_saved_value = $this.find('.customize_multi_value_field').val();
        if(multi_saved_value.length>0){
            var multi_saved_values = multi_saved_value.split("|");
            $this.find('.customize_multi_fields').empty();
            $.each(multi_saved_values, function( index, value ) {
                $this.find('.customize_multi_fields').append('<div class="set"><input type="text" value="'+value+'" class="customize_multi_single_field" /><a href="#" class="customize_multi_remove_field">X</a></div>');
            });
        }
    });

    // *************  Multi_Input_Custom_control END *********************

});Code language: JavaScript (javascript)

Basically adding, removing and writing to our custom control. In your customizer.php you’ll add

/**
Multiple input field
**/
$wp_customize->add_setting('multi_field', array(
	'default'           => '',
	'transport'         => 'postMessage',
	'sanitize_callback' => 'mytheme_text_sanitization',
));
$wp_customize->add_control(new Multi_Input_Custom_control($wp_customize, 'multi_field', array(
	'label'    		=> esc_html__('Multiple inputs', 'mytheme'),
	'description' 	=> esc_html__('Add more and more and more...', 'mytheme'),
	'settings'		=> 'multi_field',
	'section'  		=> 'section_custom_controls',
)));Code language: PHP (php)
Multiple input control field
Multi input custom control – you can add any kind of text here that can be used in a different ways

Sidebar drop down control

This control comes in handy when you want to define which sidebar will go with certain page/blog layout. In my case I used it when I wanted to separate shop pages sidebar from single product page sidebar, so you can add this control to choose which one you’ll use on certain page.

/* Sidebar Dropdown field */

class Sidebar_Dropdown_Custom_Control extends WP_Customize_Control{
	public $type = 'sidebar_dropdown';
    public function render_content(){
	?>
		<label class="customize_dropdown_input">
			<span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
			<p><?php echo wp_kses_post($this->description); ?></p>
			<?php
			global $wp_registered_sidebars;
			 ?>
			<select id="<?php echo esc_attr($this->id); ?>" name="<?php echo esc_attr($this->id); ?>" data-customize-setting-link="<?php echo esc_attr($this->id); ?>">
			<?php
			$sidebar_shop = $wp_registered_sidebars;
			if(is_array($sidebar_shop) && !empty($sidebar_shop)){
				foreach($sidebar_shop as $sidebar){
					echo '<option value="'.$sidebar['name'].'" ' . selected( $this->value(), $sidebar['name'], false ) . '>'.$sidebar['name'].'</option>';
				}
			}
			?>
			</select>
			<br>
		</label>
	<?php
    }
}Code language: JavaScript (javascript)

And adding the control is

/**
Sidebar dropdown
**/
$wp_customize->add_setting('sidebar_dropdown', array(
	'default'           => '',
	'sanitize_callback' => 'mytheme_text_sanitization',
));
$wp_customize->add_control(new Sidebar_Dropdown_Custom_Control($wp_customize, 'sidebar_dropdown', array(
	'label'    		=> esc_html__('Sidebars', 'mytheme'),
	'description' 	=> esc_html__('Choose sidebar for the page you specify', 'mytheme'),
	'settings'		=> 'sidebar_dropdown',
	'section'  		=> 'section_custom_controls',
)));
Code language: PHP (php)
Sidebar drop down control
Sidebar drop down control

This is kind of a variation on built in ‘dropdown-pages’ type control, just with sidebars. You could do the same for categories, custom taxonomies etc. Just tweak the code a bit.

Image radio buttons

The last custom control I’ll add is the image radio buttons. Now this one is a bit different, because you’ll need to include the images for your image select. This is basically radio button re-vamped, kinda like what we did with the check box. This control is a good way to give user a ‘preview’ of sorts. Remember how they say that the image is worth a thousand words? Well that’s absolutely true. When the user sees a radio button for, let’s say layout style in a shop, he only has a written descriptions that should be as concise as possible. Layout right or sidebar right is kinda dry. But if he sees a little image with what the layout can look like, he gets the picture (no pun intended :D). So on to our custom control

/* You need to include the images you want to select. Add as many as you want to. In this example there are 3 images, that are supposed to go in 3 columns in one row.*/

class Image_Select_Custom_Control extends WP_Customize_Control{
	public $type = 'image_select';
	public function enqueue(){
		wp_enqueue_style( 'custom_controls_css', get_template_directory_uri().'/inc/customizer/css/custom_controls.css');
	}
	public function render_content(){
	?>
		<div class="customize_image_select">
			<span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
			<p><?php echo wp_kses_post($this->description); ?></p>
				<label>
					<input type="radio" name="<?php echo esc_attr($this->id); ?>" value="1" data-customize-setting-link="<?php echo esc_attr($this->id); ?>" <?php checked('1', esc_attr($this->value()) );?>/>
					<img src="<?php echo get_template_directory_uri().'/images/image_1.png'?>" alt="<?php esc_attr_e('Option 1', 'mytheme'); ?>" title="<?php esc_attr_e('Option 1', 'mytheme'); ?>" />
				</label>
				<label>
					<input type="radio" name="<?php echo esc_attr($this->id); ?>" value="2" data-customize-setting-link="<?php echo esc_attr($this->id); ?>" <?php checked('2', esc_attr($this->value()) );?>/>
					<img src="<?php echo get_template_directory_uri().'/images/image_2.png'?>" alt="<?php esc_attr_e('Option 2', 'mytheme'); ?>" title="<?php esc_attr_e('Option 2', 'mytheme'); ?>" />
				</label>
				<label>
					<input type="radio" name="<?php echo esc_attr($this->id); ?>" value="3" data-customize-setting-link="<?php echo esc_attr($this->id); ?>" <?php checked('3', esc_attr($this->value()) );?>/>
					<img src="<?php echo get_template_directory_uri().'/images/image_3.png'?>" alt="<?php esc_attr_e('Option 3', 'mytheme'); ?>"  title="<?php esc_attr_e('Option 3', 'mytheme'); ?>" />
				</label>
		</div>
	<?php
	}
}Code language: JavaScript (javascript)

Customizer

/**
Image control
**/
$wp_customize->add_setting('image_options', array(
	'default'     => '2',
	'sanitize_callback' => 'mytheme_text_sanitization',
));
$wp_customize->add_control(new Image_Select_Custom_Control($wp_customize, 'image_options', array(
	'label'     	=> esc_attr__( 'Layout', 'mytheme' ),
	'description'   => esc_attr__( 'Choose the layout for your blog', 'mytheme' ),
	'settings'  	=> 'image_options',
	'section'   	=> 'section_custom_controls',
)));
Code language: PHP (php)

And of course, the styling

.customize_image_select label{
	display: inline-block;
	margin-right: 3px;
	margin-bottom: 5px;
}

.customize_image_select label:last-of-type{
	margin-right: 0;
}

.customize_image_select label input{
  display:none;
}

.customize_image_select label input + img{
  	border-color: #d3dad7;
  	border-width: 3px;
  	border-style: solid;
}

.customize_image_select label input:checked + img{
  	border-color: #0074a2;
  	border-width: 3px;
  	border-style: solid;
}Code language: CSS (css)

And you have yourself a cool image radio box to choose

Image radio buttons
Image radio buttons. Much better than the old ones.

And this is it so far. There are others interesting controls out there to add, like Google Fonts one – a colleague of mine created this control, so I’ll need to see how to add it myself first before adding that to my git repo. The Google Fonts is a bit tricky, because you need to add the API key for it, so that you can get a list of all the google fonts. But you can really add what ever kind of control that you can think of.

Implementation of these controls is the same as with the other ones – get_theme_mod().

I hope this was an interesting tutorial, if you have a comment or a question, leave it below :)

23 responses

  1. ahmed Avatar
    ahmed

    Awesome

  2. Excelente. Muchas gracias por ayudar!

  3. Thanks a lot

  4. […] control in our Theme customizer. You can learn all about it in my previous posts here and here. In our customizer.php we’ll add a separate Fonts section, and in it we’ll add one […]

  5. David Morgan Avatar
    David Morgan

    This is awesome! Thanks! :)

    1. No problem, happy to help :)

  6. Ben Sibley Avatar
    Ben Sibley

    Thanks so much for publishing this. I was trying to figure out a good way to add repeating fields to the Customizer. The method here is quite clever ;) Just made use of it in a new theme.

    1. Hi! Glad I could help :)

  7. Great post Denis! Do you think that Multiple input fields could be used to dynamically generate page sections for example on One-Page style themes or did you maybe came across a solution for dynamically adding wp customizer sections per user input? Pozdrav :)

    1. What comes to mind is to use the multiple input fields and change input to page dropdown, or posts dropdown. Then in each page you could create some content, then use customizer
      to order the pages and then show that customizer field on a page template to render content from these fields like described here: https://madebydenis.com/adding-page-content-to-your-category-page/. A bit complicated but it’s possible. This would also save any content on theme switch, which is a requirement on wp.org themes :) You could also make them sortable so that you can reorder those easily.

      1. Thanks for quick replay :) Actually I was thinking about to use this approach, saw a couple of wp.org themes using it, It does the job done just a bit more time consuming. Maybe it would be better to use SiteOrigin builder instead, saw org themes using it just not sure how theme reviewers will react. Thanks for response and maybe we’ll see each other on WordCamp Zagreb, if so the beer is on me :)

        1. I don’t think that you can bundle SiteOrigin’s builder in the theme, but you can recommend it (using TGM plugin). I’m giving a talk on WordCamp Zagreb so feel free to talk to me afterwards :D

  8. Thank you for your information.
    So I have a question: When you say “For this control you’ll need some JavaScript” in the part of Multi input field, in what file do you add the code to?

    1. All custom control javascript should be put inside custom_controls.js file inside your customizer folder. You can check the example here: https://github.com/dingo-d/wordpress-theme-customizer-extra-custom-controls

      1. Ok. Thanks again.
        I copied the files, just as you have them. My controls continue to appear in Customizer and they work, but the new controls do not appear.
        Can you help me?

        1. The best thing would be to post on stackoverflow. I cannot help you because I don’t have all the details of your problem (code)

          1. Here my functions.php and customizer folder with my customizer.php and your code: https://github.com/Mteresamtnzj/Mi-tema
            When I try to enter in WordPress’ Customizer, it displays “Fatal error: Class ‘Multi_Input_Custom_Control’ not found in D:xampphtdocswordpresswp-contentthemesmitemacustomizercustomizer.php on line 36”

          2. You removed require_once( get_template_directory() . '/inc/customizer/custom-controls.php' ); from customizer.php

            https://github.com/dingo-d/wordpress-theme-customizer-extra-custom-controls/blob/master/inc/customizer/customizer.php#L21

  9. sonia maklouf Avatar
    sonia maklouf

    Hi Denis I read both of your tuto on customization api. And I found them great so I decided to go further and to read some other tuto about customizer and I found this https://developer.wordpress.org/themes/advanced-topics/customizer-api/
    They’re saying ‘Customizer options can be granted to users with different capabilities on a granular basis’ and they’re giving an example at the end in

    Allow Non-administrators to Access the Customizer but I didn’t understand there example.

    For example if I had a portfolio site of photograph and I want each photograph being able to choose the layout of his presentation page with your radio button. I want the photograph to only have access to the photograph section. How could I do this ? To sum up how could I give to some user the capacity to see some section according to their user role.
    I find my example a little bit tricky but I think you understand what I mean :)

    1. I think you’d need to custom create a role and then add the capability of edit_theme_options (https://codex.wordpress.org/Roles_and_Capabilities) to that role, and disable the other capabilities. This still gives them the options to change menus and widgets which is not preferred. If each photographer has access to its own page, then maybe it’s better to create metabox on that page so that they can choose layout there (the tutorial for creating metaboxes is here: https://madebydenis.com/adding-metaboxes-to-your-posts-or-pages-color-picker-metabox/)

      1. sonia maklouf Avatar
        sonia maklouf

        Thanks Denis for your reply.
        Is it possible to give access to each photographer to its own page via the customizer. Exactly like you do in the metabox I mean create a new page and choose layout but with customizer ?

        1. I never tried to but I guess something could be done. But it would take some time coding it. Maybe there is a plugin that has the capabilities that you described

          1. sonia maklouf Avatar
            sonia maklouf

            :-)

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.