Note: Everything I’m talking about here, including the code, is in beta mode. It will be subject to change. I’ll update this post after release to fix any code changes that may occur between now and then. I’m releasing this post now so that theme authors can start looking at their themes and thinking about how they might want to change the way they do options pages.
So, WordPress 3.4 has this nifty new feature you can find on the main Theme selection page. It’s a link next to each theme labeled “Customize”. This is the new Theme Customizer, and it’s way cool.
In fact, you can’t see what it does with a simple picture, so here’s a video. It’s available in HD if you want to go full screen.
So, now you know what it does, and if you’re a theme author, you’ve probably just gotten some great ideas. Here’s how you can implement those ideas in your theme.
First, note that if you already support the built in Custom Header and Custom Background functionality the WordPress core provides, then those will magically show up and work in the theme customizer. No extra code needed on your part.
Existing Options
Now, the first thing you’ll probably want to do is to take note of how your existing settings in the theme work. You have three main options for theme settings, realistically. I’ll go over them briefly.
1. “Theme mod”. This uses the set_theme_mod and get_theme_mod functions. It’s rare that themes actually use these since I wrote about the Settings API, but it is there and if you use these normally then it is supported by the Theme Customizer (in fact it’s the default).
2. Individual Settings. If you store your theme’s settings in the options table as individual rows, one per setting, then that works fine with the customizer. This is not the preferred way of doing things in themes, however, and not the most common. Still, some themes do this, so if you’re one of them, it’s supported as well.
3. Serialized Settings. This is the way I explained in my Settings API Tutorial and the method recommended by the Theme Review guidelines, as well as the way Chip described in his own tutorial for theme settings. Essentially, you store your settings in an array, then store that array using set_option or get_option, as one row in the database. This method is supported and it’s the way I’ll primarily cover in this article. I’ll briefly mention the other two methods when appropriate.
Once you know how your settings are stored, then you’ll know what to fill in at certain spots in the code. More on this when we get to it.
Object Orientation
Now, the Theme Customizer is very object oriented, and while you don’t necessarily need to understand this to implement the basics of it, you might need to understand it if you’re going to make something completely custom. Just a warning.
First, we’ll look at the left hand side of the customizer screen. Notice that the left hand side is divided into sections. Actually, that’s their name: WP_Customize_Section. In each of these sections is one or more controls; or rather, WP_Customize_Control. Finally, each of these controls one of more settings on the page: aka WP_Customize_Setting.
The Sections organize the controls. The Controls get input and pass it to the settings. The Settings interface with your existing options in the theme.
To make new stuff here for your own custom options, you need to know where to add it. That place is the customize_register action hook.
add_action( 'customize_register', 'themename_customize_register' ); function themename_customize_register($wp_customize) { // ... do stuff ...
The function gets a parameter of the main $wp_customize object. This is the interface point where you will do everything like adding sections and controls and such.
Sections
So, first thing to do is to add a section. Here’s one way to do it:
$wp_customize->add_section( 'themename_color_scheme', array( 'title' => __( 'Color Scheme', 'themename' ), 'priority' => 35, ) );
The first parameter is a unique ID for the section that you’ll need later (when you’re putting controls into it). The second parameter is an array of options for the section. Sections don’t have a lot of options, really. You can give them a title, you can give them a “description” if you need some explanatory text in them. The priority setting determines their order in the list.
You can also give sections a “capability” if you have a special case. Generally speaking, most sites require the “edit_theme_options” capability to have users edit this sort of thing, and this is the default capability that the sections use. However, if you have options that anybody can edit, or which should only be managed by administrators, changing this capability will prevent the section from appearing to users who can’t change those settings anyway.
One final thing you can add to a section is a “theme_supports” option. This will make the menu not appear unless the theme supports something. If you’re putting this code in a theme itself, then you already know what the theme supports, so it doesn’t make much sense. The core uses this to not show the header and background options if the theme doesn’t support them.
Settings
Next, let’s configure some settings. Yes, the settings, not the controls. See, the controls need to know what settings they’re changing, so we have to attach the settings up first.
To declare a setting, you do it like this:
$wp_customize->add_setting( 'themename_theme_options[color_scheme]', array( 'default' => 'some-default-value', 'type' => 'option', 'capability' => 'edit_theme_options', ) );
In this case, I’ve declared that the setting I’m interested in is in an option, the option is named “themename_theme_options” in the database, and it’s serialized, and the actual array key in there is “color_scheme”. Remember that talk we had before about the Settings API and how you store your settings? This was method 3.
Here’s method 2 (one option per database entry):
$wp_customize->add_setting( 'themename_color_scheme', array( 'default' => 'some-default-value', 'type' => 'option', 'capability' => 'edit_theme_options', ) );
And here’s method 1 (using theme_mod):
$wp_customize->add_setting( 'color_scheme', array( 'default' => 'some-default-value', 'type' => 'theme_mod', 'capability' => 'edit_theme_options', ) );
This setting basically tells the theme customizer where the option is stored, and how to change it’s value so that your theme displays with the changed option.
Here’s the good bit about this: You’re telling the theme customizer where the option is. You don’t have to change the way the existing option works at all.
You already have a theme options page, right? So somehow, you’re saving those options. And in the theme, it’s reading those options using get_theme_mod or get_option, right? The way the theme customizer works is that it intercepts that call using a filter, changes the option for the previewer case only, and then passes the new option along to the theme. So the theme has no idea that the value it’s getting isn’t in the database, but one the user just selected. That’s the magic trick and why themes don’t have to dramatically change to support this sort of thing. All they have to do to make custom sections is to tell the theme customizer code what options they’re using and how, and it changes those options directly for the previewer.
(Note of clarification here: The “default” setting above should be a default value, not the current value. The difference is a subtle one, but the point is that you don’t actually need to get the current value of the option from the DB and put it in here. The WP_Customize_Setting takes care of all that jazz for you. The “default” is what should be used if the value doesn’t exist in the DB at all.)
There’s one more bit to the add_setting call that we’ll come back to later when I get around to explaining postMessage.
Controls
Finally, we come to the controls. Controls can look one of a lot of ways, obviously. The simplest controls are just checkboxes, or text fields. However, colors are something that change a lot, so there’s color wheel controls too. In fact, WordPress defines a number of possible controls. Let’s go over a few:
A radio selection:
$wp_customize->add_control( 'themename_color_scheme', array( 'label' => __( 'Color Scheme', 'themename' ), 'section' => 'themename_color_scheme', 'settings' => 'themename_theme_options[color_scheme]', 'type' => 'radio', 'choices' => array( 'value1' => 'Choice 1', 'value2' => 'Choice 2', 'value3' => 'Choice 3', ), ) );
Pretty simple. It’s referencing the section it’s in, the setting that it’s going to change, and then it has the radio type and the list of choices along with their associated values.
How about a checkbox instead? This one comes straight from core:
$wp_customize->add_control( 'display_header_text', array( 'settings' => 'header_textcolor', 'label' => __( 'Display Header Text' ), 'section' => 'header', 'type' => 'checkbox', ) );
A checkbox is on or off, true or false. It needs no real values.
How about a selection dropdown box? Here’s an example:
$wp_customize->add_control( 'example_select_box', array( 'label' => 'Select Something:', 'section' => 'nav', 'type' => 'select', 'choices' => array( 'value1' => 'Choice 1', 'value2' => 'Choice 2', 'value3' => 'Choice 3', ), ) );
The default type of control is actually type = ‘text’, and it creates a text box control. One more type of control is the “dropdown-pages” type, which creates a dropdown list of the WordPress Pages.
But that’s not all. There’s actually several more, but because they’re so custom, they’re declared differently. Here’s where we get all object oriented on ya…
$wp_customize->add_control( new WP_Customize_Color_Control( $wp_customize, 'link_color', array( 'label' => __( 'Link Color', 'themename' ), 'section' => 'themename_color_scheme', 'settings' => 'themename_theme_options[link_color]', ) ) );
Whoa, what’s with the new class? The WP_Customize_Color_Control is a class that is extending the built in WP_Customize_Control class. It adds the color wheel jazz to places where color selection is needed. Note that the class is being created here with new, and so it has to get the $wp_customize passed to it directly, so it knows where to hook in. (Note: This may change before final 3.4 release.)
Other controls of note:
- WP_Customize_Upload_Control – This gives you an upload box, for allowing file uploads. However, you probably won’t use this directly, you’ll extend it for other things… like:
- WP_Customize_Image_Control – This gives the image picker and the uploader box. It extends the upload controller. You can see it in action on the custom background piece, where a user can upload a new file to be the background image.
- WP_Customize_Header_Image_Control – Because of the resizing action of the header piece, it needs a bit of special handling and display, so the WP_Customize_Header_Image_Control extends the WP_Customize_Image_Control to add that functionality. You can see it in action on the custom header piece, where a user can upload a new file to be the header image.
So, the way to create a custom controller to do whatever you want is to make a new class of your own which extends WP_Customize_Control and adds the bits you want. How to do that is a bit complex, so I’ll save that for another tutorial. For now, you’ve got image handling, color wheels, text boxes, radios, dropdowns, and checkboxes. I think that should be enough to get started with.
End of tutorial?
Not quite. Everything I went over above is enough to add new sections to the customizer, put controls in them, and then to have the preview show your changes after a slight delay when the page refreshes. All you have to do is to call those functions with the proper parameters, in the proper place, and it’ll work.
However, note that I said “when the page refreshes”… C’mon… this is the year 2012. We don’t have flying cars, and we still have to wait a whole second or two?
Nope.
Enter postMessage
Back when I mentioned the $wp_customize->add_setting function call, I mentioned “one more bit”. That one more bit is the option called “transport”.
Transport defines how your setting change gets from the place where you changed it into the preview pane. The default setting for this is “refresh”. An alternative setting is named “postMessage”.
The postMessage transport makes it such that the setting is instantly sent into the other frame, where javascript can adjust the page on-the-fly using this new information.
An example:
Let’s say we have a setting to change the colors of the titles. All the titles on the page are in some tag that has a class of posttitle, perhaps. The option normally just saves the HTML color chosen, then outputs some inline CSS in the header.php to basically do this:
.posttitle { color: #abcdef; }
Or whatever the option actually is for that color.
We have hooked our setting to that option, and hooked our WP_Customize_Color_Control up to it, and now when we change it, it works and we can see the color change. Note that this is easiest to do with already working customizer options, so the best way to do it is to get it working normally first, then add on this next bit.
Now, we have the working option in the customizer, so to take away that refresh delay, we’ll add this new option to the add_setting call:
'transport' => 'postMessage',
This tells the customizer that the setting will be sent directly to the frame via javascript. However, for that setting to work, we need javascript in the frame itself to receive it.
So, back in our main function… remember that? It started like this:
add_action( 'customize_register', 'themename_customize_register' ); function themename_customize_register($wp_customize) { // ... do stuff ...
Right at the end of that function, we’re going to add this code:
if ( $wp_customize->is_preview() && ! is_admin() ) add_action( 'wp_footer', 'themename_customize_preview', 21);
This is going to add a new function call to our preview frame’s footer. It only gets added with the preview frame, so the live site and others won’t see it, because they don’t need to see it. This is where we’re going to output our javascript to make things happen in real-time.
Here’s our function:
function themename_customize_preview() { ?> <script type="text/javascript"> ( function( $ ){ wp.customize('setting_name',function( value ) { value.bind(function(to) { $('.posttitle').css('color', to ? to : '' ); }); }); } )( jQuery ) </script> <?php }
As you can see, it just outputs a bit of javascript. This code won’t change much, ever, so let’s go over just two pieces of importance:
- ‘setting_name’ is the name of the setting, as added by the $wp_customize->add_setting call.
- The entire line starting with jQuery(‘.posttitle’) is our custom bit of code. It gets the “to” variable, which will be the color chosen by the user, and it sets the posttitles on the page to have that color, using the css modifying functionality of jquery.
Those are the only two bits you need to change, really. The rest is pretty copy-pasta. For each real-time setting, you can dupe this bit of code in the script.
Here’s another thing: You can change pre-existing refresh settings to be postMessage ones. Take the Site Title and Tagline elements in the Header section, for example. These are refresh settings, and the reason they are is because each theme implements them differently. There’s no way for the core to know the javascript code needed for any particular theme.
But if you’re a theme author, then you’re not writing for a generic theme. You’re writing for your particular theme. You know how the site title and tagline are displayed. There’s no reason you can’t make those update in real time. And while you’re at it, the header_textcolor setting can be real time too, since you know the theme code.
In your main function again, add these three lines of code:
$wp_customize->get_setting('blogname')->transport='postMessage'; $wp_customize->get_setting('blogdescription')->transport='postMessage'; $wp_customize->get_setting('header_textcolor')->transport='postMessage';
That changes the transport on those core settings to be postMessage. Now you need to add the javascript code to actually do the refreshing in your theme. Here’s an example of TwentyEleven doing this (with the patch I wrote for it):
function twentyeleven_customize_preview() { ?> <script type="text/javascript"> ( function( $ ){ wp.customize('blogname',function( value ) { value.bind(function(to) { $('#site-title a').html(to); }); }); wp.customize('blogdescription',function( value ) { value.bind(function(to) { $('#site-description').html(to); }); }); wp.customize( 'header_textcolor', function( value ) { value.bind( function( to ) { $('#site-title a, #site-description').css('color', to ? to : '' ); }); }); } )( jQuery ) </script> <?php }
For the blogname, it changes the HTML inside the “#site-title a” link. For the description, it changes the tag with #sitedescription. For the color of those, it simply targets both of them and alters their CSS.
Core has to try to be generic across all themes. But themes have more knowledge of how they work and can change things to target themselves in better ways. A theme adding controls knows what those controls change, so if it’s something simple like CSS or even something more complex like HTML, if you can write javascript code to make that modification in real time, then you can use postMessage and eliminate that refresh delay.
Hopefully this explains some of the theme customizer. Was it as clear as mud? Take a look at my patch to Twenty Eleven to add some of the theme options from its existing options screen into the customizer. You can find it on this ticket: http://core.trac.wordpress.org/ticket/20448.