12 May 10

I was trying to override the login block displayed on one of my Drupal sites and I kept running into a lot of trouble. No matter what functions I tried overriding in my template.php, nothing was displaying. All the tutorials I could find online didn't take into consideration the specifics of using a Zen subtheme. Hopefully my guide here will avoid this problem.
This guide was particularly useful, but it didn't account for using a Zen subtheme, and neither did this one.
The first step in all the guides is to implement the hook_theme function. This function lets you signal to Drupal what core functions your template will override. If you're using a Zen subtheme, this has already been done for you. In your template.php, look for the following:
/** * Implementation of HOOK_theme(). */ function STARTERKIT_theme(&$existing, $type, $theme, $path) { $hooks = zen_theme($existing, $type, $theme, $path); // Add your theme hooks like this: /* $hooks['hook_name_here'] = array( // Details go here ); */ // @TODO: Needs detailed comments. Patches welcome! return $hooks; }
If you setup your theme properly, you should have already replaced STARTERKIT above with the safe name of your theme. As written, this function checks for overrides from Zen:
$hooks = zen_theme($existing, $type, $theme, $path);
What we're going to do is add additional function overrides to the list provided by Zen. On the next line, add the following:
$hooks['user_login_block'] = array( 'arguments' => array('form' => NULL), );
This tells Drupal to look for a new function called STARTERKIT_user_login_block(). The full STARTERKIT_theme() function should look like this. Don't forget to replace STARTERKIT with your theme's safe name.
/** * Implementation of HOOK_theme(). */ function STARTERKIT_theme(&$existing, $type, $theme, $path) { $hooks = zen_theme($existing, $type, $theme, $path); $hooks['user_login_block'] = array( 'arguments' => array('form' => NULL), ); // Add your theme hooks like this: /* $hooks['hook_name_here'] = array( // Details go here ); */ // @TODO: Needs detailed comments. Patches welcome! return $hooks; }
We now have everything in place to tell Drupal to look for our custom overrides for the User Login Block. The next step is to add the overrides using a theme_user_login_block() function. At the end of your template.php file, add the following function (again, remember to swap STARTKERKIT with your theme's name):
/** * Override the return of the User Login Block form * @param $form * An array representing the form */ function STARTERKIT_user_login_block(&$form) { // Modify the text of the submit button $form['submit']['#value'] = t('Login Now!'); return (drupal_render($form)); }
Now all you need to do is save your file, rebuild your theme registry and flush any theme caches (the admin_menu module makes this easy), and you should be displaying the modified form!
But what if I want to do more than just change the text or values of some of the form elements? What if I need to modify the HTML output to display the user login form block the way I want? This is relatively easy. Since we already used theme_hook() to indicate to Drupal that we are overriding the form preparation function, we can also tell Drupal to look for a template file instead of displaying its normal output. In your theme_hook() function, find the line we created that starts with 'arguments' and add this line after it:
// Template file, ex: user-login-block.tpl.php 'template' => 'user-login-block',
This tells Drupal that not only are we overriding the form preparation function, but we're also providing a template file that should be used called user-login-block.tpl.php. Your full theme_hook() function should now look like this:
/** * Implementation of HOOK_theme(). */ function STARTERKIT_theme(&$existing, $type, $theme, $path) { $hooks = zen_theme($existing, $type, $theme, $path); $hooks['user_login_block'] = array( 'arguments' => array('form' => NULL), // Template file, ex: user-login-block.tpl.php 'template' => 'user-login-block', ); // Add your theme hooks like this: /* $hooks['hook_name_here'] = array( // Details go here ); */ // @TODO: Needs detailed comments. Patches welcome! return $hooks; }}
Since we'll be providing our own template file, the theme_user_login_block() function we previously created will no longer work correctly. Instead, we'll need to create a theme_preprocess_user_login_block() function so that our changes to the $form structure will be inserted before the template file is processed. Find your theme_user_login_block() function at the bottom of your template.php file and replace it with this:
/** * Override the form pre-processing to include our changes * @param $vars * An array of variables to pass to the theme template. */ function STARTERKIT_preprocess_user_login_block(&$vars) { // Modify the text of the submit button $vars['form']['submit']['#value'] = t('Login Now!'); $vars['form_markup'] = drupal_render($vars['form']); }
Now, in your template folder, add a new file, user-login-block.tpl.php Whatever you put in this file will be used to output the form, just like any of your other template php files. Again, simply clear your caches and theme registry, and you should see this file working. Here's an example of my user-login-block.tpl.php file:
<div>
<div class="form-item" id="edit-name-wrapper">
<label for="edit-name">Username or e-mail: <span class="form-required" title="This field is required.">*</span></label>
<input maxlength="60" name="name" id="edit-name" size="15" value="" tabindex="1" class="form-text required" type="text">
</div>
<div class="form-item" id="edit-pass-wrapper">
<label for="edit-pass">Password: <span class="form-required" title="This field is required.">*</span></label>
<input name="pass" id="edit-pass" maxlength="60" size="15" tabindex="2" class="form-text required" type="password">
</div>
<input name="op" id="edit-submit" value="<?php print $form['submit']['#value'];?>" tabindex="3" class="form-submit" type="submit">
<div class="item-list">
<ul>
<li class="first"><a href="/user/register" title="Create a new user account.">Create new account</a></li>
<li class="last"><a href="/user/password" title="Request new password via e-mail.">Request new password</a>
</li>
</ul>
</div>
<input name="form_build_id" id="<?php print $form['form_build_id']['#id']; ?>" value="<?php print $form['form_build_id']['#value']; ?>" type="hidden">
<input name="form_id" id="edit-user-login-block" value="user_login_block" type="hidden">
</div>