Customizable Header Images for Your Drupal Theme

Meet your new friend: theme-settings.php

Drupal themes get a number of configurable settings options for free. For example, most provide toggle switches for the search box, site slogans, user pictures, and so on. Similarly, most provide file uploading widgets to add a custom logo or favicon. These settings are easy: Drupal will add them to the theme's configuration page by default, so it takes no extra work. We want to create our own custom setting, however -- one that adds another field to the Theme configuration form. To do that, we'll need to add a new file to the theme: theme-settings.php.

This file's only job is to implement a single Drupal hook: hook_settings(). Its job is to take an array of settings for the theme, and return a custom FormAPI form that allows users to edit them. Drupal will automatically save the values that users enter into it for later retrieval: managing the form itself is this code's only task.

  
/**
 * Implementation of hook_settings() for themes.
 */
function MYTHEMENAME_settings($settings) {
  // This ensures that a 'files' directory exists if it hasn't
  // already been been created.
  file_check_directory(file_directory_path(), 
    FILE_CREATE_DIRECTORY, 'file_directory_path');

  // Check for a freshly uploaded header image, save it to the
  // filesystem, and grab its full path for later use.
  if ($file = file_save_upload('header_image',
      array('file_validate_is_image' => array()))) {
    $parts = pathinfo($file->filename);
    $filename = 'MYTHEMENAME_header_image.'. $parts['extension'];
    if (file_copy($file, $filename, FILE_EXISTS_REPLACE)) {
      $settings['header_image_path'] = $file->filepath;
    }
  }

  // Define the settings-related FormAPI elements.
  $form = array();
  $form['header_image'] = array(
    '#type' => 'file',
    '#title' => t('Header image'),
    '#maxlength' => 40,
  );
  $form['header_image_path'] = array(
    '#type' => 'value',
    '#value' => !empty($settings['header_image_path']) ?
      $settings['header_image_path'] : '',
  );
  if (!empty($settings['header_image_path'])) {
    $form['header_image_preview'] = array(
      '#type' => 'markup',
      '#value' => !empty($settings['header_image_path']) ? 
		  theme('image', $settings['header_image_path']) : '',
    );
  }
  return $form;
}
  

In the code above, loosely adapted from Development Seed's Singular theme, we've defined three specific form elements. The first, header_image, is a file upload widget that lets users post a file: it's pretty straightforward.

The second form element is header_image_path. It's a 'value' field that stores the actual location of the uploaded file on the server. It will never be displayed directly to the user, but because it is present in the form, it will be saved in the theme's settings and can be used later.

The third form element is header_image_preview. If an image path exists, it simply spits out an image tag containing a preview of the uploaded header image.

The only other code is the snippet at the beginning: it checks to see whether the form has just been submitted, along with a file upload. It ensures that the file itself gets saved correctly, and the path is extracted and handled properly.

Teach your theme new tricks: template.php

Now that the settings form has been created, administrators can upload new header images at will. The theme doesn't actually do anything with those fresh images, however: that's something we'll need to add ourselves. We'll do that in the template.php file, where your theme can store custom "Preprocess" functions that prepare variables for use in your HTML templates.

  
/**
 * Implementation of hook_preprocess_page().
 */
function MYTHEMENAME_preprocess_page(&$variables) {
  $settings = theme_get_settings('MYTHEMENAME');
  if (!empty($settings['header_image_path'])) {
    $vars['header_image_path'] = $settings['header_image_path'];
  }
  else {
    $variables['header_image_path'] = path_to_theme().'/head.jpg';
  }
}
  

This function is pretty straightforward. When the theme's page.tpl.php file is about to be called, rendering the entire page into HTML, this function will fire -- it gets a chance to add or alter the $variables collection that will be passed on to the template.

To make the magic happen, we're calling theme_settings(), a Drupal API function that conveniently retrieves all of the settings that our form allowed site administrators to change. Then we look for the header_image_path setting, and if it exists, we add the custom path to the $variables array that will be handed off to the template. If the setting doesn't exist -- in other words, if the administrator hasn't uploaded a custom image -- we use the default header image that ships with the theme.








theme-header-setting.png

Pulling it together

We've added the settings page to our theme, we've added a new $header_image_path variable to the page template's list of pre-built data, and we're ready to rock. All that's left now is printing it out at the proper location in the theme's page.tpl.php file instead of a hard-coded reference to a static header image.

These same techniques can be used to expose more advanced settings. The NineSixty Robots theme we build in our Advanced Theming DVDs, for example, exposes configuration options for a Twitter-driven slogan rotator. Because we're exposing the header image as a page template variable, other Drupal modules can intercept and modify it. For example, a site's custom module could use the hook_preprocess_page() function to change the header image depending on the section of the site that's being viewed, or the time of day.

Of course, themes don't have to be that complex! Even simple uses of theme settings -- like this swappable header -- can put a lot of personalization power in the hands of site builders.

Get in touch with us

Tell us about your project or drop us a line. We'd love to hear from you!