Custom Customizer!

Namaste!

This tutorial is going to begin to tackle an integral part of the WordPress ecosystem, the theme customizer. While a portion of thie tutorial is custom to Divi, this tut can be applied to any WordPress theme you are designing. The customizer was introduced a number of years ago and provides a way for the end user to quickly modify the look of their pages. It is sort of like the Divi front-end builder with a lot less power! However, you can grant non-Admins access to the Customizer, meaning that you don’t have someone changing your basic layout. Fair warning, this is an advanced tut that assumes that you have some base knowledge of what php and javascript are, but I will walk you through any code that is introduced. Additionally, I am choosing to manipulate the customizer through adding a new class, but you could easily do this through a series of methods in your ‘functions.php’ file.

The Divi theme already has done a lot to customize the customizer. If you dig into the main ‘functions.php’ file you will see that there are literally hundreds of changes made to the customizer. Overall, the structure of the customizer can be broken down into four ‘objects’: ‘Panels’, ‘Sections’, ‘Settings’, and ‘Controls’. To give you concrete examples – using the theme customizer from a standard Divi install, when you first open it the very top item is ‘General Settings’. This is a ‘panel’. Within that panel are four additional selections that are each ‘sections’. Clicking on one of these causes it to open up to a whole set of ‘controls’ that can be used to modify the ‘settings’. 

Okay, let’s go ahead and add a whole new panel with two sections, each with multiple controls, just so that we get the idea of how they each work. However, the WordPress Codex states that themes generally should not register their own panels, but rather utilize the existing panels. Additionally, sections do not need to be in a panel, but can be a stand alone item in the customizer. Along the way to implementing our new controls, we will introduce another important part of the Customize API, the transport model.

Let’s imagine that we have a client with a shop and they want to be able to make changes to the landing page for holidays or other events on a regular basis. We could teach them to use the Divi builder, or we could set up a customizer panel for them. In this case, I just put a fullwidth section with a header, added a background photo and some section with a header, added a background photo and some landing page text. In order to be able to target it later in javascript I’ve added an ID of ‘header-module’. First up, we will create a custom php file for our modifications, enqueue it through our functions file and create a panel.

Fire up your favorite code editor and create a new php file – I titled mine, ‘class-divi-child-customizer.php’, indicating that I will use this file to define a new class. I saved it into a subfolder named ‘customizer’ in the ‘inc’ folder of child theme, but this isn’t needed, you can put it where ever you would like. 

Moving over to the ‘functions.php’ file.

You will need to modify your path suitably depending on where you saved the new php file you made. These two lines of code bring in and instantiate the class we will begin building. Now, we can begin building out our class. The first thing we will do is add a constructor to hook us into the ‘customize_register’ action.

So, what does this do? Going back to a previous tutorial, we are taking advantage of a built-in WordPress hook, specifically the ‘customize_register’ hook. When the ‘functions.php’ instantiates this class it fires off the __construct() action, which then hooks the ‘register_customize_panels’ (which we will begin writing next) to the ‘customize_register’ hook. First, an overview:

Walking through the code, first we pass the ‘$wp_customize’ object into our function. This allows us to use the various customize API functions. In this section of the code we will make use of the ‘add_panel()’ and ‘add_section()’ methods which do exactly what they say.

The first line tells WordPress to use the $wp_customize object method ‘add_panel()’. To that method I’m passing in an $id of ‘changing_header’, followed by an array of values. All of these arguments are actually optional, but for sake of completeness, I’m showing them here.  There are three additional arguments that could be passed, ‘description’, ‘type’, and ‘active_callback’. With regards to the ‘priority’, the value of 160 will put it after all of the built-in panels/sections except for the ‘Additional CSS’ section.  In the screenshot to the left we can now see our new panel. If you want it to appear after the “additional CSS’ item, give your panel a priority over 200. 

The code to add in new sections is quite similar. Again, we pass in an $id plus an array of values. In this case, I am adding in priorities to order how the sections show up in our panel, but this isn’t actually needed. The most important portion of this array is the ‘panel’ argument. This says that this section should be added to the panel we just created by passing in the ‘changing_header’ $id.

Finally, we add in a callout to add our various settings using the ‘heading_options_settings’ method from our class ($this). 

As an aside, the settings could be defined within this same function rather than a separate one, but I’m trying to be a little better about singlizing methods (OOP). Technically, I’ve already failed because I’m adding both a new panel and sections in this one function. Notice that in our callout we are passing in the $wp_customize object.

Moving on to the final section of php code:

In this method we are making use of two other WP_Customize_Manager methods, ‘add_setting()’ and ‘add_control()’. These two commands are paired with each setting receiving at least one control. For ‘add_setting()’ the first parameter passed in is an $id, this is used within the theme to store the values in an accessible array (more on this later). So, in this case, I’m using ‘divi_child_options’ to store all of the values and passing in a unique key for each setting.

The first setting field is going to be used to set the header image.

As a default, I’m passing in an image from my media library. You’ll have to modify this for your own installation. The only other important and possibly cryptic field here is the ‘transport’ argument. This can be set to either ‘refresh’ or ‘postMessage’. These transport methods determine how the Customizer will display the changes the user is making. The ‘refresh’ setting will reload the entire page every time the user makes a change, while the ‘postMessage’ will only alter the specific element the user is modifying. It is generally encouraged to use ‘postMessage’. However, this does mean we are going to have to set-up some javascript to handle the live preview.

There are two other important and possibly cryptic fields here. One is the ‘type’ and can be either ‘option’ or ‘theme_mod’. The ‘theme_mod’ (default) argument tells WordPress that the change you are making only applies to this particular theme. Whereas the ‘option’ argument will apply no matter what theme you are running – like the Site Identity which will be the same no matter the theme. The second field is ‘sanitize_callback’. This ensures that the data that is being submitted on the front-end isn’t deleterious.

There are two different controls that I’m adding here. The first is a link to the media library.

In order to do this we have to pass ‘new WP_Custom_Image_Control()’ into the ‘add_control()’ method. Again, we pass in the ‘$wp_customize’ object, followed by a specific $id that matches the key value passed in the ‘add_setting()’ method – in this case ‘header_image’. We then pass several arguments in an array, including a ‘section’ argument that establishes where our setting/control combo should be displayed, and a ‘settings’ argument that links it to the already defined setting. 

There are several other types of “custom” controls that WP makes available, including a color picker ( WP_Customize_Color_control), multimedia content (WP_Customize_Media_Control), file upload (WP_Customize_Upload_Control), and adding a photo with custom cropping (WP_Customize_Cropped_image_Control).

The other type of control I’m adding is a simple textarea. In this case, we can use the ‘$wp_customize’ methods directly without invoking a different method.   

Here we pass in an $id and array of arguments only. We have one additional argument here that we didn’t have for the image control, and that is ‘type’. There are a ton of different types including various input elements like ’email’, ‘date’, ‘password’ and ‘url’, plus other typical controls like ‘checkbox’, ‘radio’, ‘select’, and ‘dropdown-pages’. See the WP codex for a complete list. Okay, that wraps up our addition of controls to the Customizer, now we actually have to write some code to make them do something!

First, we have to write some code to give us a live update. All of our options are being stored away by WP for our easy access using wp.customize(). Create a new file – I called mine ‘jquery.customizer.live.preview.js’. Jump into your ‘functions.php’ file and add in the following to enqueue your new file:

This should look fairly familiar. The only change from our normal enqueueing process is the hook we are using. The ‘customize_preview_init’ hook will cause our javascript to load in only when the customizer itself is open. 

Jumping back into our preview.js file, we need to set up javascript/jQuery to target every single element we want to change. The code for doing this is pretty simple. 

So, we set-up a script that will fire when the page has fully loaded and then set the variable ‘api’ to ‘wp.customize’. Remember, all of our various control settings are being saved there by WordPress for easy access. In each case above we query the wp.customize database for the value of our settings. We then ‘.bind’ this value to a change in our DOM. In the first case, I’m using jQuery to find the module with the ID of ‘header-module’ and then modifying the styling to reflect the new background image using the ‘.css()’ method. For the other three controls I’m changing the text using, wait for it, ‘.text()’!

Okay, so at this point, when the user makes a change in one of our controls it shows up in the preview. However, if we were to save and exit our page would go back to the original design. Here is where our tutorial veers away from the ordinary WordPress tutorial about the Customizer. WP makes it relatively easy to incorporate the customizer changes into your custome page template. The problem here is that we are using Divi, rather then writing php to build each page. To get around this we will use some javascript and another WordPress function named ‘wp_localize_script’.

Jumping back over to our ‘functions.php’ file, we are going to enqueue a new javascript file and pass it some values:

We are enqueuing the script as normal with an ‘add_action(‘wp_enqueue_scripts’, function name)’. Inside the function, we are enqueing our javascript, but then we set some variables using the ‘get_theme_mods()’ method. WP makes this method available in the server side code – so our ‘functions.php’ file, as well as custom page templates. I’m querying this array to set variables for the image and each text element.To make the data available on the server side for javascript, after enqueueing the script, we can use ‘wp_localize_script()’. This method accepts the handle of the script it should pass data to – in this case ‘shd-theme-customizer-changes’. Next, it accepts a name for the data set – I’m using ‘shd_params’. Finally, it accepts an array of the actual values. As an aside, this code works, but I’m not sure it is the best form. For some reason I couldn’t access the ‘get_theme_mod()’ method directly in the ‘wp_localize_script()’ array like I would have prefered. I will update this if I figure out a better/more correct way.

Last, but not least, we need to write the ‘jquery.customizer.alter.pages.js’ file! 

Again, we set up our script to run after the page loads in. Next, we add the extra bits to the location of the header image so that we can add it in to our CSS. The next four lines of code, like in the live preview script, simply target and change the elements of our header. Simple, huh?

As usual, reach out through comment or e-mail if you need clarification, need some specific help, or see something incorrect. I’m trying to grow as a programmer, so my style is still in a little bit of flux! I hope this helps someone out there with their own web project. Going forward, I expect to write a follow-up to this tutorial using javascript only to create the Customizer panels/sections/settings/options. It has been incorporated into WP for awhile and represents the direction that WP is going toward being a Web App that you interact with soley through the API, e.g. Calypso.

Metta!!!

1 thought on “Custom Customizer!”

  1. Hi All, 

    Sting Thunderbolt over on Facebook brought up a good point about caching DOM elements in javascript. This practice eliminates the number of times your script has to traverse the DOM in order to find and change elements. So one usage is if you will be changing the same element over and over. This really isn’t applicable here as we are only truly firing once for each selector. The other usage, which does apply here, is when you are altering child elements of an element. Here is an altered ‘jquery.customizer.alter.pages.js’.

     

     So here, I’m defining the variable $header_module as the element with the ID, ‘#header-module’. Then, rather than having to look up that element when I want to target the children I can just use the variable name and chain the rest of my selectors. 

    The next question to ask, however, is whether this optimization makes sense in a small script. I wrapped both this code and  the original in a loop with a timer to record the difference. If I run that loop for 10,000x, the difference in time was 95ms. If I time how long it takes the loop to run once, the difference is .2ms. So, yes, I am making the script more performant. “So just do it this way every time!”, I hear you saying. But, there are some cons.

    First, in larger scripts you always have to consider whether your cache element will be changed. For example, if I was to use ‘.append()’ in my script on ‘$header_module’ subsequent DOM changes utilizing the cached element potentially might not work. It only has a snapshot at the time the query was made. In that case you would have to add in a function that recognizes that your cached version doesn’t match the current version and update. There are functions out there to do this (jQache is popular). But you always have to remember that more code written/utilized is more code to go wrong. So it is always important, I think, to balance micro-optimization with code simplicity and ease of reading.

     

Leave a Reply

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