Keeping Modules Themable

Submitted by Ron Golan on Mon, 10/31/2011 - 12:20pm
Ron Golan's picture

Making it possible to override a module's output using a template and CSS.

We know that modules should provide themable output so the presentation can be modified using functions, templates and CSS. In the tiny example module that I created in my last blog post, I didn't do that. Here I will address that deficiency and show an example of what needs to be added to the BC Reminder module to give themers a chance to customize the output to their desires.

The original version of the BC Reminder module had all the markup and inline styles included in the hook_form_FORM_ID_alter(). The only way to modify it was to edit the module code. By adding a BC Reminder theme hook, we can use either a function or template to provide markup. While both options are overridable, the function provides better performance and the template provides better ease of use for non-coders. Since this template would rarely be called and never more than once on a page, the ease of use outweighs the perfomance considerations.

Our theme hook is defined with the #theme attribute in hook_form_alter(). The Drupal Forms API Reference says that #theme defines a theme function but it seems to work when using templates also. I have no theme_bc_reminder() function and the module works fine.

The hook_theme() implementation will default to using a theme function if no template is specified. 'render element' defines which renderable element to render. It can be replaced with 'variables' as an associative array of parameters and default values which are passed to theme().

A preprocess function here named template_preprocess_bc_reminder() is used to feed the variables to the template and to contruct the link value. I've also used this function to add a small CSS file. Now that the styles aren't inline, they can be easily overriden.

As it works now, the template contains the text of the reminder notice. This too can now be changed without touching the module code. The only thing still hard coded in the module that would be nice to take out is the actual link information. Placing this into an administrative form would be a nice improvement.

bc_reminder.module

<?php
/**
* @file
* Binary Canary Reminder
*/

/**
* Implements hook_form_FORM_ID_alter().
*/

function bc_reminder_form_system_site_maintenance_mode_alter(&$form, &$form_state, $form_id) {
 
$form['binary_canary_reminder'] = array(
   
'#type' => 'markup',
   
'#theme' => 'bc_reminder',
  );
}

/**
* Implements hook_theme().
*/
function bc_reminder_theme($existing, $type, $theme, $path) {
  return array(
   
'bc_reminder' => array(
     
'template' => 'bc-reminder',
     
'render element' => 'binary_canary_reminder',
    ),
  );
}

/**
* Implements template_preprocess_hook().
*/
function template_preprocess_bc_reminder(&$variables) {
 
drupal_add_css(drupal_get_path('module', 'bc_reminder') . '/bc-reminder.css');
 
$link_text = 'Binary Canary';
 
$link_path = 'https://binarycanary.com/en/login-to-website-monitoring.cfm';
 
$link = l($link_text, $link_path);
 
$variables['link'] = $link;
}
?>

bc-reminder.tpl.php

<span id="bc-reminder">Disable <?php print $link ?> monitoring before switching to maintenance mode!</span>

bc-reminder.css

#bc-reminder {
  background-color: yellow;
  padding: 3px;
}

2 comments

Nice article, thanks.

Question:
is this D7 or D6 related??

Ron Golan's picture

by Ron Golan on Wed, 02/08/2012 - 8:30am

Thanks! The code is D7 but the principles apply to both D6 and D7.

Post new comment