User Tools

Site Tools


dr:themesettings

Adding settings on Drupal themes

WARNING

A module called themesettings by John Albin is now available on Drupal.org, with much more expanded functionality. The documentation on this page only applies to my initial proof-of-concept module, which should be considered obsolete now that this official module exists. The goals and basic mechanism are identical for additional settings, though, so you may want to read the explanation here since the code is in a much simpler form in the initial module.

Themes need settings

For some time now, I've been feeling the need to have some themes be more easily customizable by admins, without their needing to tweak files. Alas, the themeing system is normally limited to the smallest common denominator defined by <theme>_features, accessed from admin/themes/settings and admin/themes/settings/<theme>

Since tweaking the various themeing mechanisms seemed complicated, I took a short route, and created the “themesettings” proof-of-concept module. The idea is simple: if themes can't have settings, modules can register whatever path they want and then invoke whatever theme code they want to. So….

As the first step, we'll add new settings to a theme, by declaring a <theme>_settings function. The theme we'll be using for the demo is called “admin” and is basically the usual PHPtemplate-based box_grey from Drupal.org

Adding settingability to themes

Creating the settings function for theme "admin"

In the admin.theme file, we'll add the admin_settings function. If the theme is a plain PHP theme, it will already exist. If it is a PHPtemplate theme, as in the case of our “admin” theme, the file will have to be created.

function admin_settings()
  {
  $title = t('Extended settings for theme %theme', array('%theme' => 'admin'));
  drupal_set_title($title);
  $form = array();
 
  $form['admin_background'] = array
    (
    '#type'          => 'textfield',
    '#title'         => t('background-color'),
    '#default_value' => variable_get('admin_background', 'transparent'),
    '#description'   => t('CSS string for a background color. It will be applied to nodes.'),
    );
  return system_settings_form('admin_admin_settings', $form);
  }

Proof of concept example, no more: we just define a setting for the theme to use later on. In this case, it will be a CSS background color. NOTICE: a true world example should not take input and store it without some sanity checks.

Using the setting: node.tpl.php

With the “admin” theme being based on PHPtemplate, we'll modify node.tpl.php to apply our parameterized color to all nodes. This example just changes the first line with an inline style:

<?php
echo '<div style="background-color: ' 
  . variable_get('admin_background', 'transparent')
  . ' ! important"'
  . 'class="node' . ($sticky ? " sticky" : "")
  . '">' ;
if ($page == 0) ...
[...the rest of the file is unchanged...]

Ugly inline styling, but this is just a demo, so we don't care. I add the “! important” clause to make sure it is being forced even if rules cascade from elsewhere in the CSS files to change that background.

Hooking it up

At this stage, we obviously have a color-parametered node.tpl.php, and a form-generating function that could store and retrieve that color.

We now need to tell Drupal to stitch this together, and for this we'll need a module.

The themesettings module

// themesettings.module for Drupal 4.7
// (C) 2006 FG Marand 
// Licensed under the Cecill 2.0 license http://www.cecill.info/index.en.html
//
define(TSBASEPATH, 'admin/themes/settings2');
 
function _themesettings_themes()
  {
  static $ret ;
 
  if (isset($ret))
    { return $ret; }
 
  $ret = array();
  $themes = list_themes();
  foreach ($themes as $theme_key => $theme)
    {
    $function_name = $theme_key . "_settings";
    // Test taken from system.module, but probably incomplete/incorrect
    // We need to load the file for the function to be in memory, though
    // Having it in a separate file avoids loading the full theme
    if (file_exists($file = dirname($theme->filename) .'/' . $theme_key . '.theme'))
      {
      include_once "./$file";
      }
    if (function_exists($function_name))
      {
      $ret[$theme_key] = $theme;
      }
    }
  return $ret;
  }
 
function themesettings_help($section)
  {
  switch ($section)
    {
    case 'admin/modules#themesettings':
      $ret = 'themesettings';
      break;
    case 'admin/modules#description':
      $ret = t('This module allows themes to include additional settings beyond the default features like logo, slogan, or mission');
      break;
    }
  return $ret;
  }
 
 
function themesettings_menu($may_cache)
  {
  $items = array();
 
  if (!$may_cache)
    {
    $access = user_access('administer site configuration');
 
    $items[] = array(
      'path'         => TSBASEPATH,
      'title'        => t('Extended theme settings'),
      'type'         => MENU_NORMAL_ITEM,
      'access'       => $access,
      'callback'     => 'themesettings_page',
      );
    foreach (_themesettings_themes() as $theme_name => $theme)
      {
      $items[] = array(
        'path'       => TSBASEPATH . "/$theme_name",
        'title'      => $theme_name,
        'callback'   => $theme_name . '_settings',
        'access'     => $access,
        'type'       => MENU_LOCAL_TASK,
        );
      }
    }
  return $items;
  }
 
function themesettings_page()
  {
  $ret = t('<p>Please select one of the themes having extended settings below.</p>');
  $links = array();
  foreach (_themesettings_themes() as $theme_name => $theme_name)
    {
  	$links[] = l($theme_name, TSBASEPATH . "/$theme_name");
    }
  $ret .= theme('item_list', $links);
  return $ret;
  }

How does it work ?

There's nothing magic to the module:

  • it registers a set of paths in the admin area by implementing hook_menu
  • to know which themes implement this non-standard extension, it needs to know whether the <theme>_settings function is defined, so it loads the .theme file : by default only the current theme is loaded, and storing the function in the .theme file allows a minimal system load.
  • for PHPtemplate themes, the .theme file won't be loaded except for admin/theme/settings2/* pages, meaning this has absolutely no additional load on the system when not performing configuration.
  • for plain PHP themes, the .theme file is already loaded anyway, so parsing this function only adds a few CPU cycles, but no additional file inclusion, so the additional load remains minimal too.

Please try it and comment on my blog, or on IRC (I'm fgm #drupal).

dr/themesettings.txt · Last modified: 2012/01/13 16:37 by fgm