[Drupal] How to create Theme Switcher module for Drupal 7 Part 1

| | 4 min read

This article will be explaining a module we implemented in site Free Drupal Themes, its called Theme Switcher. This module helps in switching between any enabled themes without logging in. In previous article How to enable multiple themes using command promte? I had explained how to enable multiple themes using drush.

When we create a custom module to be in order first create a folder named "fdt_theme_switcher" in "sites/all/modules". Now lets start with info file named "fdt_theme_switcher.info". Here we are naming the module as FDT Theme Switcher for drupal 7. Also calling a css named "bar.css" for styling the block.

/*fdt_theme_switcher.info*/
  name = FDT Theme Switcher
  description = Enables the theme switching functionalities.
  package = FDT
  version = VERSION
  core = 7.x
  stylesheets[all][] = css/bar.css

Now lets create our module file named "fdt_theme_switcher.module". First will create a hook function called hook_page_build(). In this will call the function fdt_theme_switcher_generate(), to get theme switcher form. To display this in page top we assign it to variable '$page['page_top']['theme_switcher']'. $pagetop is displayed in sytem module html.tpl.php file. In fdt_theme_switcher_generate() it will return the form as a string. Will be calling the necessory js files also here.

/**
 * Implements hook_page_build().
 */
function fdt_theme_switcher_page_build(&$page) {
  //if(!user_access('administer')){
  if(user_is_anonymous()){
    $page['page_top']['theme_switcher'] = array(
      '#markup' => fdt_theme_switcher_generate());
    drupal_add_js(drupal_get_path('module', 'fdt_theme_switcher').'/js/themeSwitcher.js');  
  }
}

/**
 * themeSwitcher.js
*/

(function ($) {
  Drupal.theme_switcher = Drupal.theme_switcher || {};
  Drupal.behaviors.theme_switcher = {
    attach: function () {
       $('select#edit-theme').change(function() {
          $(this).closest("form").submit();
      });
    }
  };
})(jQuery);

In fdt_theme_switcher_generate() its gets the value of current theme, and display theme switcher form.

function fdt_theme_switcher_generate()
{

    global $current_theme;
    $fdtpath="http://www.freedrupalthemes.net/customize-theme?n=$current_theme";
    $output="";
    $output.="<div id='top-bar'>";
    $output.='<h2>Customize this theme</h2>';
    $output.="<div id='top-bar-sub'>";
    $output.=/*"".*/drupal_render(drupal_get_form('fdt_theme_switcher_themeswitcher_form'));
    $output.="</div>";
    $output.="</div>";
    return $output;
}

Now lets call the form fdt_themeswitcher_form. In this form there is a select box to select the enabled themes and a button

  • Switch -> To switch to new selected theme

See the form below

function fdt_theme_switcher_themeswitcher_form($form, &$form_state) {
  
  global $current_theme;
  $options = fdt_theme_switcher_options();
  
  $form['themeswitcher']['theme'] = array(
    '#type' => 'item',
    '#markup' => '<p>Select a theme</p>'
  );

  $form['themeswitcher']['theme'] = array(
    '#type' => 'select',
    '#title' => t('Select a theme'),
    '#default_value' =>  $current_theme,
    '#title_display' => 'attribute',
    '#options' => $options,
    '#required' => TRUE,
  );
  
  $form['themeswitcher']['actions'] = array('#type' => 'actions');

  $form['themeswitcher']['actions']['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Switch'),
    '#id' => 'fdt_theme-submit',
  );
  
  return $form;
}

Here we store current theme name to variable $current_theme and passed it as global. Now to display all the theme names in select box a function fdt_theme_switcher_options() is called and the value is stored to variable $options.

See the code below

function fdt_theme_switcher_options() {
  $options = array();
  $themes = list_themes();
  foreach ($themes as $name => $theme) {
    if ($theme->status) {
      $options[$name] = $theme->info['name'];
    }
  }
  return $options;
}

Now comes the form submit. When we submit function is called, values passed are themename, and baseurl as a global variable. Here will store the theme name to variable $themeurl in format t/<theme_name>. Now the function return will call drupal_goto() with coressponding theme name and enable it.

See the submit fuction for each buttons

function fdt_theme_switcher_themeswitcher_form_submit($form, &$form_state) {
  
  global $base_url;
  $themeurl="t/".$form_state['values']['theme'];
  $options = array(
      //'fragment' => '', 
      'query' => '',
      'absolute' => TRUE, 
      'alias' => FALSE, 
      'prefix' => 'goto',
      'external' => FALSE
  	);
 	drupal_goto($themeurl,$options);
}

Ok, now we have enable the theme. But the problem comes when we go to inner pages for each theme we have to attach the theme name along with the url and when we click a link and goto external page the attached themename must be removed. In order to get this done we uses two hooks

  • hook_url_inbound_alter() -> Will strip the "t/<theme_name>" from the urls internally
  • hook_url_outbound_alter() -> Rewriteall urls in the site to include the t/<theme_name>

In function url_inbound_alter() will get the theme name as a global variable, if not admin pages will return node values to variable result and when we are opening the page for the first time garland theme is set as default theme.

In function url_outbound_alter() will set the path as $base_url."/t/".<theme_name>.

See the code below.

/**
 * Implements hook_url_inbound_alter()
 *
 */
function fdt_theme_switcher_url_inbound_alter(&$result, $path, $path_language) {
    global $current_theme;
    // All requests should have theme name and theme version except admin urls
    if ($path != 'admin' && (substr($path, 0, 6) != "admin/") && preg_match("/^t\/([^\/]*)\/?(.*)/", $path, $matches)) {
      $current_theme=$matches[1];
      $result = $matches[2];
      if ($result == '') {
        $result = "node";
      }
    }
    else {
      if ($current_theme == '') {
        $current_theme='garland';
      }
    }
  }

/**
 * Implements hook_url_outbound_alter()
 *
 */

function fdt_theme_switcher_url_outbound_alter(&$path, &$options, $original_path) {
  
    global $current_theme, $base_url;
    if($original_path == 'http://www.freedrupalthemes.net') {
      $fdturl='http://www.freedrupalthemes.net';
      return $fdturl;
    }
  
    if ($options['prefix'] == 'goto') {
      $options['prefix']='';
      return;
    }
  
    if ($original_path == '') {
      $path=$base_url."/t/".$current_theme;
      $options = array(
        'fragment' => '', 
        'query' => '',
        'absolute' => TRUE, 
        'alias' => FALSE, 
        'prefix' => '',
        'external' => TRUE
  	  );
      return;
    }
    // Add theme name and theme version to all urls except admin urls
    if ($path != 'admin' && substr($path, 0, 6) != "admin/" && $current_theme != '') {
      if ($path == '<front>' || $path == '' || $path == '/') {
        $path = "t/$current_theme/";
      }
      else {
        $path = "t/$current_theme/$path";
      }
    }
  }

Now to display this in a fixed postion we have to gave the styles accordingly. Feel free to test this module in our site Free Drupal Themes, and let me know your feedback.