Loading Additional Stylesheets from an Options Panel

A common option in premium WordPress themes is the ability to select different design styles. Even “Twenty Eleven” has the option to use a “Light” or “Dark” color palette.

There are two main ways to apply these styles- either with body classes or by loading in a second stylesheet. This tutorial covers the stylesheet method.

I’m also assuming you’re using the Options Framework (theme or plugin version) to set up your options, though you could likely adapt the code if you are building your own panel from scratch.



The above screenshot shows two options for stylesheet loading. One uses pre-defined stylesheets that the developer selects. The other scans a specific directory for stylesheets and allows the user to pick anyone file that’s there (even if they added their own). Choose the method that works best for you.

Pre-Defined Stylesheets

Here’s how you would set up an option with predefined stylesheets. If you’re using the Options Framework this would go in options.php in the optionsframework_options function:

// Defined Stylesheet Paths
// Use get_template_directory_uri if it's a parent theme
	
$defined_stylesheets = array(
	"0" => "Default", // There is no "default" stylesheet to load
	get_stylesheet_directory_uri() . '/css/blue.css' => "Blue",
	get_stylesheet_directory_uri() . '/css/green.css' => "Green",
	get_stylesheet_directory_uri() . '/css/pink.css' => "Pink"
);

$options[] = array( "name" => "Select a Stylesheet to be Loaded",
	"desc" => "This is a manually defined list of stylesheets.",
	"id" => "stylesheet",
	"std" => "0",
	"type" => "select",
	"options" => $defined_stylesheets );

Notice that the first option is “default”, which for this example means that no additional stylesheet will be loaded.

The three stylesheet options are blue.css, green.css and pink.css- which reside in the “css” folder of the theme.

List all Stylesheets in a Directory

The other option is add as many css files as you want to a directory, and have the options panel automatically load those as an option in the select box. Here’s how you would do that:

// Generated list of stylesheets in the "CSS" directory
// Use template_directory paths if you're using a parent theme
	
$alt_stylesheets = options_stylesheets_get_file_list(
	get_stylesheet_directory() . '/css/', // $directory_path
	'css', // $filetype
	get_stylesheet_directory_uri() . '/css/' // $directory_uri
);

$options[] = array( "name" => "Automatically Load List of Stylesheets",
	"desc" => 'In this example the css files in the "css" directory are automatically loaded into the option.',
	"id" => "auto_stylesheet",
	"type" => "select",
	"options" => $alt_stylesheets );

Loading a list of files into an option could be used for other uses than just css, so I created a generic function that returns an array of files when pass the path to the directory, file type and directory uri.

This will also be needed for the above code to work:

/**
 * Returns an array of all files in $directory_path of type $filetype.
 *
 * The $directory_uri + file name is used for the key
 * The file name is the value
 */
 
function options_stylesheets_get_file_list( $directory_path, $filetype, $directory_uri ) {
	$alt_stylesheets = array();
	$alt_stylesheet_files = array();
	if ( is_dir( $directory_path ) ) {
		$alt_stylesheet_files = glob( $directory_path . "*.$filetype");
		foreach ( $alt_stylesheet_files as $file ) {
			$file = str_replace( $directory_path, "", $file);
			$alt_stylesheets[ $directory_uri . $file] = $file;
		}
	}
	return $alt_stylesheets;
}

Enqueue the Stylesheet on the Front End

Now that the options are available in the backend, you need to set up a function to actually load the stylesheet into the theme. This code can go in functions.php:

 /* 
 * The CSS file selected in the options panel 'stylesheet' option
 * is loaded on the theme front end
 *
 * If you'd prefer to use the 'auto_stylesheet' option, replace
 * of_get_option('stylesheet') with of_get_option('auto_stylesheet')
 *
 * If the "Default" option is selected, "0" is returned (equivalent to false),
 * which means no files will be registered or enqueued
 */
 
function options_stylesheets_alt_style()   {
	if ( of_get_option('stylesheet') ) {
		wp_enqueue_style( 'options_stylesheets_alt_style', of_get_option('stylesheet'), array(), null );
	}
}
add_action( 'wp_enqueue_scripts', 'options_stylesheets_alt_style' );

Warning

Loading multiple stylesheets might seem like a good way to give users more control of their themes but there is also a performance hit on the front end.

Every enqueued stylesheet is an additional file that needs to be loaded, so be judicious in where you use it, and try to keep the HTTP requests as low as possible.

Try it Out

If you want to see working code, I’ve also included this demo in the Options Kit and the Options Theme Kit, which are paid demo packages for the Options Framework.

About Devin

I'm a WordPress developer based in Austin, Texas. Follow my projects on GitHub, or more general WordPress ramblings as @devinsays on twitter.

27 Responses

  1. This is awesome. Thanks for all the great tutorials thus far as well! One question…I’ve seen multiple different themes with the option to load different slideshows/sliders (on to the home page) from the Options panel. Could you send me in the right direction to add this to my Options Framework? Thanks!

  2. In the case of wanting to offer users a dropdown with multiple stylesheets, wouldn’t it be easier to have an option like:

    http://pastebin.com/svF7UXwJ

    And then put something like:

    <link rel="stylesheet" type="text/css" href="/css/.css” />

    In the head, where /css contains the corresponding stylesheets?

    Of course, this way doesn’t involve wp_enqueue_style and isn’t perfect, but is my thinking practical?

    Thanks Devin!

  3. minacio

    Hello,

    I’m trying to implement this in a Thematic Child Theme without sucess… Everything seems to work but it doesn’t load the css file, it always use the default css.

    Is there a better solution to work with child themes? I tried the Plugin but i receive a message saying that the plugin can’t be used with my theme.

    Thanks for your great work and for your help.

    Minacio

      1. minacio

        Hi Devin,

        Thanks for the reply.

        I misunderstood how to work with the theme but I managed to install and adapt to my project.

        Now I have difficulty loading the stylesheets … After selecting everything seems fine but do not load …

        Thank you.

  4. minacio

    Hi again Devin,

    In the beginning I misunderstood how this could work and confuse the use of plugin and theme but finally everything works just fine. I’ve been reading most of your post in foruns and learning with people with similar doubts.

    Thanks for your great work!

      1. Sorry About that, here’s the new error i now get after the correction

        Warning: Cannot modify header information – headers already sent by (output started at C:\xampp\htdocs\development\wp-content\themes\new-theme12\functions.php:570) in C:\xampp\htdocs\development\wp-includes\pluggable.php on line 881

        Thanks for your help so far.

  5. Hi Devin!

    Nice tutorial, I was trying to use it for a custom theme but then made a small tweak. And as you mention that loading multiple CSS files increases HTTP requests.
    How about this:
    Instead of creating a separate CSS file for each color, simply create a CSS class and add all the required CSS to main Stylesheet.
    Now, instead of using wp_enqueue_style, we can use body_class filter to add custom CSS class to “body” :)

      1. Oh wow! I actually missed that you mentioned “body class” :)
        And yes, I agree if there are tens of color schemes or stylesheets it’s good to have additional HTTP request rather than a super long stylesheet with unused CSS.

  6. Excellent tutorial, and a very useful options framework. Took me about 15 mins to get my alternating css styles setup. As again about 4 hours of preparing and testing an admin options panel. I’m really going to dig into the other tutorials, as well as the actual framework.
    Thank you so much.

  7. Great article! I adapted some of this onto my own framework. Is there a way to have a default option for the dynamically populated option? I see how you have it on the static one, but I would want to pass that same “default” option to the array of stylesheets so I have the option of not enqueueing any.

  8. Hi Devin,
    Thanks for this. I am going to purchase the kit shortly. I downloaded the dev version from github, and am having a little difficulty getting this to work. I am still in the learning stages of theming. I have a website that I have created a child theme of. I have the Theme Options showing up fine in the dashboard, and I have followed the instructions for the functions.php file, by changing get_template_directory to get_stylesheet_directory but I am not totally sure what to do with the OPTIONS_FRAMEWORK_DIRECTORY.

    I am starting out by adding the option of changing style sheets, but when I select the option for the pink stylesheet and save options, my website on the front end doesnt change. I am wondering if I need to specify anything else on the functions.php page?

    (I have uploaded a new stylesheet that is visually different and have pointed the options.php file to the correct location as far as I can see)

  9. I do have this in my functions.php file.

    function options_stylesheets_alt_style() {
    if ( of_get_option('stylesheet') ) {
    wp_enqueue_style( 'options_stylesheets_alt_style', of_get_option('stylesheet'), array(), null );
    }
    }
    add_action( 'wp_enqueue_scripts', 'options_stylesheets_alt_style' );

  10. Ok, I had a look and see that it is loading the custom css file that I pick from the option panel, but it is also loading the default style.css too so the default file must be taking priority over the newly loaded “style-red.css” or “style-blue.css”

  11. I found a file in the parent theme that was enqueuing a style called at-main (the default style) so I added this:

    wp_dequeue_style( 'at-main' );
    wp_deregister_style( 'at-main' );

    And it seems to be working fine now ! Thanks very much!

Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>