Adding custom controls to your Customization API
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.
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 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)
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)
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)
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)
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
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 :)
20 comments
Pingback: Adding Google Fonts to your WordPress theme | Made by Denis
David Morgan
onThis is awesome! Thanks! :)
Denis Žoljom
onNo problem, happy to help :)
Ben Sibley
onThanks 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.
Denis Žoljom
onHi! Glad I could help :)
Karlo
onGreat 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 :)
Denis Žoljom
onWhat 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.
Karlo
onThanks 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 :)
Denis Žoljom
onI 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
mt
onThank 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?
Denis Žoljom
onAll 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
mt
onOk. 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?
Denis Žoljom
onThe best thing would be to post on stackoverflow. I cannot help you because I don’t have all the details of your problem (code)
mt
onHere 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”
Denis Žoljom
onYou removed
require_once( get_template_directory() . '/inc/customizer/custom-controls.php' );
fromcustomizer.php
https://github.com/dingo-d/wordpress-theme-customizer-extra-custom-controls/blob/master/inc/customizer/customizer.php#L21
sonia maklouf
onHi 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 :)
Denis Žoljom
onI 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/)sonia maklouf
onThanks 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 ?
Denis Žoljom
onI 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
sonia maklouf
on:-)