WordPress Switch Theme plugin for DEVs

Sometimes, for testing purpose, we need a way to switch our theme on the run for a single page or for specific users, keeping the main theme for the others.

The fastest way to do it, suggested on several stackoverflow post is the following code

add_filter('template', 'change_theme');
add_filter('option_template', 'change_theme');
add_filter('option_stylesheet', 'change_theme');

function change_theme() 
{
    // Alternate theme
    return 'AwesomeTheme';
}

If you put a couple of if, it should work…. most of the time.

Eureka get_template_directory()

by me, one day on the toilet

The Plugin

You can get the plugin on my GitHub repository here
https://github.com/FInalmarco/wordpress-switch-theme-plugin

Note

This plugin is intended for developers and tester, is not supposed to run on a production environment

Plugin Features

  • Switch theme live to one ore more users (unaffecting the others)
  • Switch theme for a single page passing a get variable (?themeprev=1)
  • Compatibility with themes that use get_template_directory() and get_template_directory_uri()
  • No database interaction (wp_option)

Configuration

In the file includes/motore.php edit the following lines

	//Configuration
	public $user_diff_theme = [10710,10711]; //User ID who to change theme
	public $force_var = TRUE; //if true you can force a page with the new theme using ?themeprev=1 (any user)
	private $new_theme = 'understrap'; //New theme
	private $new_theme_child = 'understrap-child'; //new theme child
	//end config	

How to get theme info

The information about the working theme are stored in the wp_option db table, what the filters do, is override it on the run (not touching the database).
Information about the theme name, the directory can be retrieved in several way, from wp_get_theme() ( return a object with all theme info ) or from several functions like: get_theme_root(), get_template(), get_template_directory(), get_stylesheet_directory().

 //Theme info   
   $theme = wp_get_theme(); 
    echo $theme->name;
    echo $theme->parent_theme;
    var_dump($theme);

    echo '<pre>';
    echo 'get_template_directory() -->'.get_template_directory().'<br>';
    echo 'get_stylesheet_directory() -->'.get_stylesheet_directory().'<br>';
    echo 'get_theme_root() -->'.get_theme_root().'<br>';
    echo 'get_template() -->'.get_template().'<br>';

Why get_template_directory() could be a problem

If you run those method to get theme info, after our switch, you will get correct data ( so the data of the switched theme ) for most of the function but get_template() and get_template_directory(); those two will still print name and directory of the old theme.

The reason is that get_template(), from WordPress core, and (as now) not hoockable, return data from the option table (database) and get_template_directory() use get_template()

So why get_template(), get_template_directory() and get_template_directory_uri() could be problematic selective switching theme scripts?

Some themes require files using get_template_directory() like this:
$css_version = $theme_version . ‘.’ . filemtime( get_template_directory() . ‘/css/theme.min.css’ );
Those reference are often in the main theme and can not be overridden.
This mean that the new theme could not run correctly or not working at all.

For this reason we need another two filters to force the right root directory and and uri address

From my motore.php GSCambioTema Class

add_filter("template_directory", array($this,'wp_template_directory_filter'), 10,3);
add_filter("template_directory_uri", array($this,'wp_template_uri_filter'), 10,3);

public function wp_template_directory_filter( $template_dir, $template, $theme_root ){

			if ($this->_controllo() == true){
			
				$template     = $this->new_theme;
				$theme_root   = get_theme_root( $template );
				$template_dir = "$theme_root/$template";
			}	

		return $template_dir;
		}

As you can see the hook override the template dir getting the root of the new theme (note: always parent theme), same is made for the get_template_directory_uri()

Questions? Suggestions? Please leave a comment below.

Leave a comment