Theme Switching is the process of providing the ability for the user to change the presentation styles or “look” of your site with the use of a Theme Switcher. The process of changing your WordPress Theme by the site Administrator is not called theme switching.
~~[ WordPress Codex ]
If we wanted to switch themes or do theme switching, it seems like it would make sense to use the switch_theme WordPress command. However, this turns out not to be the case.
Switch_Theme Function
The switch_theme function is exactly what is called when an Administrator changes his WordPress Theme from the Appearance menu. Below is a code fragment from the wp-admin/themes.php file which shows the switch_theme function being called when a theme is activated from the WordPress Dashboard.
if ( 'activate' == $_GET['action'] ) { check_admin_referer('switch-theme_' . $_GET['template']); switch_theme($_GET['template'], $_GET['stylesheet']); wp_redirect( admin_url('themes.php?activated=true') ); exit; }
Therefore, if you want to do theme switching, or render different pages on your WordPress blog using different themes, then do not use the WordPress switch_theme command.
‘Real’ Theme Switching Functions
Proper theme switching is achieved by tying into the template and stylesheet filters.
add_filter( 'template', 'my_template_filter' ); add_filter( 'stylesheet', 'my_stylesheet_filter' );
These are the same filters that are used when you preview a WordPress theme. Note that during previews, the theme is only changed on the preview page. It does not have any effect on any other page and it does not have any effect on your WordPress Administration screens.
Another important thing to note is that these add_filter functions must be added when your main plugin file loads. If you call it during the init hook or the admin_init hook, then it is too late because these hooks only get called after theme setup occurs.
In fact, probably the best thing to do is to tie these theme switching filters to the setup_theme action hook. This is what occurs when we preview a theme.
add_action('setup_theme', 'theme_redirect'); function my_template_filter($current) { global $shiba_switch_theme; return (is_array($shiba_switch_theme) && isset($shiba_switch_theme['template'])) ? $shiba_switch_theme['template'] : ''; } function my_stylesheet_filter($current) { global $shiba_switch_theme; return (is_array($shiba_switch_theme) && isset($shiba_switch_theme['stylesheet'])) ? $shiba_switch_theme['stylesheet'] : ''; } function theme_redirect() { global $shiba_switch_theme; if ( isset($_GET['preview']) ) return; $theme_name = my_get_new_theme(); $current_theme = get_current_theme(); if ($theme_name == $current_theme) return; $theme_data = get_theme($theme_name); if (!is_array($theme_data)) return; // Switch theme - based on preview_theme function in wp-includes/theme.php $template = $theme_data['Template']; $stylesheet = $theme_data['Stylesheet']; $template = preg_replace('|[^a-z0-9_./-]|i', '', $template); if ( validate_file($template) ) return; $stylesheet = preg_replace('|[^a-z0-9_./-]|i', '', $stylesheet); if ( validate_file($stylesheet) ) return; if (!is_array($shiba_switch_theme)) $shiba_switch_theme = array(); $shiba_switch_theme['name'] = $theme_data['Name']; $shiba_switch_theme['template'] = $template; $shiba_switch_theme['stylesheet'] = $stylesheet; add_filter( 'template', 'my_template_filter' ); add_filter( 'stylesheet', 'my_stylesheet_filter' ); // Prevent theme mods to current theme being used on theme being previewed add_filter( 'pre_option_mods_' . $current_theme, '__return_empty_array' ); }
The theme switching code above is patterned after the preview_theme function in wp-includes/theme.php.
Line 16 – Don’t switch themes if we are in theme preview mode.
Line 17 – Get the theme we want to switch to. NOTE – at this point, the WordPress Loop has not been set up yet. In fact, the HTML address has not been translated, and the WordPress Loop query has not been run. The globals $wp and $wp_query exist, but they are both empty.
Line 19 – If new theme is already our current theme, then don’t do any theme switching.
Lines 21 to 22 – Get the theme data.
Lines 26-28 – Clean and validate the template name.
Lines 30-32 – Clean and validate the stylesheet name.
Lines 36-38 – Store the theme name, template, and stylesheet values in the $shiba_switch_theme array. We access this data later on in our my_template_filter and my_stylesheet_filter functions.
Line 39 – Add the ‘template’ filter.
Line 40 – Add the ‘stylesheet’ filter.
get_current_theme and get_theme_mod
The theme switching technique above does not change any theme options in the WordPress database. As a result, calling database dependent theme functions such as get_current_theme and get_theme_mod will not return values from the switched theme.
Navigation menus, for example, may not work because it may depend on the results returned by
get_theme_mod( 'nav_menu_locations');
If we want get_theme_mod and get_current_theme to reflect our switched theme, we can hook into the pre_option_stylesheet and pre_option_current_theme filters.
add_filter( 'pre_option_stylesheet', 'my_get_theme_stylesheet' ); add_filter( 'pre_option_current_theme', 'my_get_theme_name' ); function my_get_theme_stylesheet($value) { global $shiba_switch_theme; if (isset($shiba_switch_theme['stylesheet'])) return $shiba_switch_theme['stylesheet']; else return $value; } function my_get_theme_name($value) { global $shiba_switch_theme; if (isset($shiba_switch_theme['name'])) return $shiba_switch_theme['name']; else return $value; }
my_get_theme_stylesheet checks to see if we have switched themes, and if so, it returns the stylesheet of our switched theme.
my_get_theme_name checks to see if we have switched themes, and if so, it returns the theme name of our switched theme.
For example, the Twenty Ten theme has –
- theme stylesheet value = ‘twentyten’
- theme name value = ‘Twenty Ten’
Here are some example pages with theme switching –
Sean Langlands says
I have the same problem as RADU but with using the add_filters. It doesn’t seem to act like a child theme. Any way around this?
ShibaShake says
Hello Sean,
I have a working example of this in my Shiba Widgets plugin. It is a bit more complex than what is shown here, but contains all of the elements described. If you want, you can check it out by looking at the shiba-widget-gettheme.php file.
Sergey says
I found an error in your code.
39,40 strings in “theme_redirect” function. They call functions that does not exists. Error in functions names.
Radu says
I can’t seem to get this to work. 🙁
I made a theme with several child themes and I need to be able to change them when certain events are triggered. Thing is, since the theme I’m trying to load is a child theme, it should naturally preserve the functions defined in the functions.php parent theme folder.
If I do this the wp-admin back-end, it works perfectly. However, if I try changing it via switch_theme(), which according to this article does the exact same thing, all the functions in the parent functions.php file are lost and cannot be accesed in the child theme.
Any ideas why this happens?
Thank you in advance,
Radu