WordPress provides theme developers with a powerful system for creating easy-to-use theme option systems via the Theme Customizer. While the customizer provides an excellent real-time preview system and a great overall user experience, defining the output of options set in the customizer can get messy.
In this tutorial, I will show you how to simplify getting color options that are set in the customizer into CSS in the front-end. This simple system can be adapted for use with other CSS properties as well as. This means that you can use these techniques to work with options set via other methods than the Theme Customizer.
What We Are Trying to Avoid
Too often, getting colors and other options set in Theme Customizer involves messy code mixing PHP and CSS.
For example:
add_action( 'wp_head', 'slug_theme_customizer_css' ); function slug_theme_customizer_css() { ?> <style type="text/css"> h1.site-title a { color: <?php echo get_theme_mod( 'site_title_color', '#ff0000' ); ?>; } h3.site-description { color: <?php echo get_theme_mod( 'site_description_color', '#000' ); ?>; } </style> <?php }
The problem with this code is not purely aesthetic, or that it is hard to read. It's too easy to make a mistake. For example, closing PHP tags, followed by closing the CSS declaration leads to this:?>;
, which looks wrong, but is technically correct.
While you could start this function by getting all of the color values you need into variables, you'd still need to open PHP tags to echo their values in the CSS. Still, that's a good start. The ability to put CSS color values into variables, of course, is one of the many great things about using a CSS preprocessor.
While adding a full-blown Sass or LESS processor to your theme is possible, and there are plugins to do it, that's going overboard for a simple task of converting a few variables to hexadecimal values. Instead, I'm going to show you how to create a simple preprocessor in your theme with just a few lines of code.
Better CSS Markup
The first thing you are going to need to do is create a file in your theme called customizer.css
. This file really could have any extension, but giving it a css
extension means that your code editor or IDE will treat it as a CSS file making it easier to work with.
In customizer.css
you can reformat that ugly code from the previous example into this:
h1.site-title a { color: [site_title_color]; } h3.site-description { color: [site_description_color]; }
As you can see, you are now able to write CSS as if it was CSS. You simply replace the values that will be set from the customizer with the name of the theme_mod
in brackets. These strings will be replaced by our preprocesser with their value from the database. The most important thing here is that you use the name of your theme mods as your substitution value in the unprocessed CSS.
Building Your Preprocessor
The preprocesser itself is actually incredibly simple as it takes the contents of your customizer.css
and uses the PHP str_replace()
function to replace the values in brackets with values from the customizer.
The whole system involves one simple class with three methods and one function outside of the class, hooked to wp_head
to output processed and optimized CSS. Keep in mind that this code presumes all of the data we need is stored in theme mods, which is the default for the theme customizer. You may need to replace get_theme_mod()
with get_option()
in your code, depending on your exact needs.
This class uses a foreach
loop in each method. If you are not familiar with how foreach
loops, I recommend taking a look at my article on working with loops and arrays. Also, if you are not familiar with PHP classes or object-oriented PHP (OOP) in general, you should check out Tom McFarlin's introductory series on OOP.
To begin, in a your functions.php
or in a file included in it, create an empty class called slug_theme_customizer_output
replacing "slug" with your theme's unique slug. It should look like this:
class Slug_Theme_Customizer_Output { }
The first method in the class will be where you set the theme mods that you will be using, as well as default values for each theme mod. You set each one in an array in the form of theme_mod => default
. Sticking with the same two settings as before, it would like this:
function theme_mods() { return array( 'site_title_color' => '#ff0000', 'site_description_color' => '#000' ); }
The next step will be to get the current value of each theme_mod
and put that in an array that we can use in our actual preprocessor. This method simply gets each value from the theme_mods()
method and passes the key as the first argument, which is the theme_mods name to get_theme_mods()
while passing the default value as the second argument, which will be returned if there is nothing set in that theme mod. It will look like this:
function prepare_values() { $colors = array(); // Get our theme mods and default values. $theme_mods = $this->theme_mods(); // For each theme mod, output the value of the theme mod or the default value. foreach( $theme_mods as $theme_mod => $default ) { $colors[ $theme_mod ] = get_theme_mod( $theme_mod, $default ); } return $colors; }
Now we have an array in the form of 'theme_mod_name' => 'value to replace'
and our ready to process the CSS in the third and final method of this class.
In the foreach
loop in this method, we are taking advantage of the ability that PHP gives us to treat the array's key and value as separate variables. This is a really powerful feature of PHP foreach
loops that requires a little planning in how each array is structured and makes life much easier.
The first step will be to use file_get_contents()
to convert the customizer.css
file into a string and store it in a variable. Since this function will cause a fatal error if it can't find the file, we need to wrap all code in this method in a test if the file exists at all.
Note that this code assumes that customizer.css
is in the same directory as the class, you may need to adjust for your theme's file structure. Here is how we begin this method:
function process() { $css = ''; // Modify this filename and / or location to meet your needs. $theme_customizer_file = trailingslashit( dirname( __FILE__ ) ) . 'theme_customizer.css'; // Make sure the file exists. if ( file_exists( $theme_customizer_file ) ) { // Get contents of the file. $css = file_get_contents( $theme_customizer_file ); } }
As I said before, this whole method is wrapped in a check if the file exists. That means that it will return false
if the file doesn't load. Keep that in mind as we will need to account for that possibility later.
Now that we have the CSS as a string, we will need to get our arrays of substitution values from the prepare_values()
method. Again, we will be using the array key and variable as separate variables in the foreach
loop. For each theme_mod
we have to add brackets around it then we can use it to replace the substitution string in the CSS with str_replace()
, like this:
// Get our colors. $colors = $this->prepare_values(); // Replace each color. foreach ( $colors as $theme_mod => $color ) { $search = '[' . $theme_mod . ']'; $css = str_replace( $search, $color, $css ); }
This loop will give us completely valid CSS with all of our bracketed theme mod names replaced with the correct hex codes for the colors. All that's left is wrapping the processed CSS in the appropriate style tags before returning it:
// Add style tags. $css = '<style type="text/css">' . "\n" . $css . "\n" . '</style>'; return $css;
That's the whole preprocessor. The only step left is to output our CSS itself. To do this, we can use a function, outside of the class that initializes the class and outputs it in the header of the theme.
This function looks like this:
add_action( 'wp_head', 'slug_theme_customizer_output' ); function slug_theme_customizer_output() { // Make sure our class exists. if ( class_exists( 'Slug_Theme_Customizer_Output') ) { // Initialize the class and get processed css. $class= new Slug_Theme_Customizer_Output(); $css = $class->process(); // To be safe, make sure `process` method didn't return false or anything other than a string. if ( $css && is_string( $css ) ) { echo $css; } } }
If you may remember from before, the method process()
can return false if the CSS file couldn't be loaded. In order to account for this possibility, before echoing the value of the process()
method, it is important to make sure that it neither returns false, nor returns anything that is not a string.
Extra Bonus Optimization
While we could stop there, I'd like to make things a little more efficient. This system works perfectly fine, but it also does a lot of repetitive processing, complete with what could be several database queries on each page load. Personally, I'd rather skip running the whole class and instead just get one string from the database.
In order to accomplish this we can rework the output function to cache the CSS in a transient. That way when we can skip the entire preprocessor class if the transient has a value, if it doesn't then we can run the whole process and re-cache it. Here is the modified output function:
add_action( 'wp_head', 'slug_theme_customizer_output' ); function slug_theme_customizer_output() { // Either set css to the transient or rebuild. if ( false === ( $css = get_transient( 'slug_theme_customizer_css' ) ) ) { // Make sure our class exists. if ( class_exists( 'Slug_Theme_Customizer_Output') ) { // Initialize the class and get processed css. $class= new Slug_Theme_Customizer_Output(); $css = $class->process(); // Cache css for next time. set_transient( 'slug_theme_customizer_css', $css ); } } // To be safe, make sure `process` method didn't return false or anything other than a string. if ( $css && is_string( $css ) ) { echo $css; } }
Now, if there is a value set in the transient slug_theme_customizer_css
it can be echoed directly, after passing the same tests to ensure it is neither false
or not a string. The preprocessor class isn't loaded, and only one query is made to the database. If the transient returns false
, the process is run and the value is cached for next time.
Of course, we want to make sure that when theme mods are updated that we clear the transient so it doesn't output out of date settings. WordPress will process that whenever a specific option is updated.
We can use this action since theme mods are stored option named for the theme its associated with. For example, TwentyFourteen's theme mods are stored in the option theme_mods_twentyfourteen
. Here is how we use this action, to clear our transient:
/** * Reset the slug_theme_customizer_css transient when theme mods are updated. */ // Get current theme's name. $theme = get_stylesheet(); add_action( "update_option_theme_mods_{$theme}", 'slug_reset_theme_customizer_css_transient' ); function slug_reset_theme_customizer_css_transient() { delete_transient( 'slug_theme_customizer_css' ); }
Putting It to Use and Taking It Further
Now that you can write your CSS that gets updated form the theme customizer with variables, one thing you may want to consider is using one theme mod in many places.
For example, what about instead of setting a theme_mod for each and every color in the theme, and causing options overload, how about options for primary color, secondary color and accent color?
The system that I've shown you how to create here only works with color options, making it only really useful for CSS properties like color
, background-color
, border-color
, etc. You could extend it to be useful for other types of properties.
Just remember not to reinvent Sass or LESS, the point of this all was to avoid bloating your theme with a full PHP implementation Sass or LESS, which are already available as plugins.
Comments