An Introduction: Dominating the User Login Form

In this first tutorial, you will learn how to:

  1. override the default presentation of the user login form, and create a custom template for it.
  2. pass an editable node into the user login form
  3. alter the form’s values (such as text, and instructions)
  4. make the form available to page.tpl.php — as though it was something as simple as a footer.

Moreover, I will show you how bloody simple it is. Folks who follow this tutorial should already have:

  1. knowledge of PHP
  2. the ability to lie about a lack of knowledge of PHP
  3. some familiarity of the kindergarden basics of drupal theming
  4. Be working with drupal 4.7+

Step One: Override the deafult user login form

Overriding is always done in the theme’s template.php file (if you don’t have a template.php file, you may create a it now). Obviously, before you can override anything, you must first locate what you are trying to override. The best way to do this is to search a module for the $form variable.

Of course, the user module has no shortage of forms. However, eventually we come across function user_login:

(modules/user.module on line 868).

<?php
function user_login($msg = '') {
//…(omitted scary code)
 
return drupal_get_form('user_login', $form);
}
?>

So there you have it, the top and the bottom of the function. That’s all you really need to override it. Here’s the code:

template.php

<?php
function phptemplate_user_login($form) {
  return
_phptemplate_callback('user_login', array('form' => $form));
}
?>

Notice the scary looking _return_phptemplate_callback(‘user_login’,array(‘form’ => $form));? Oooohhh… scary… gonna cry? Your choice is simple, either you can hide under a blanket, or you can take a look at the pattern:
_return_phptemplate_callback(‘[the name of your .tpl.php file]’,array(‘[the name of the variable sent to your .tpl.php file]’ => [‘the actual variable that was returned from the function this code calls’]));

Before moving on, I want to remind you that you aren’t stupid. This doesn’t make immediate sense to anyone. So relax, and look for patterns in colors: they hold some big keys.

I’m now going to ask you to create a new tpl.php file called user_login.tpl.php.

So just to review your theme’s files should be:
/themes/yourtheme/template.php
/themes/yourtheme/user_login.tpl.php

user_login.tpl.php

Insert the code:

<h1>Hello world!</h1>
<?php
    print_r
(form_render($form));
?>

If all has gone according to plan, www.example.com/user/login now greats you with:

Amazing how sometimes, things can just start to make sense. YOu don’t need to understand it; you don’t even need to agree with it. Just accept it, and continue.

Part 2: Node the form up

The user login form usually needs some additional info, or links that drupal does not provide by default. If you were an amateur, you’d probably hardcode that extra info into the theme. However, since you’re an expert, you’re going to stick an editible node into the login area instead. Title your node, “Join the Revolution”, and stick this in the body:

<p>"The temptation to quit will be greatest just before you are about to succeed."
<em>-an old Chinese saying</em></p>

Now, let’s stick that node in the login form. This is going to be a two part process

template.php: make the node available to the login form

<?php
function phptemplate_user_login($form) {
       
/* PAY ATTENTION, $login_node is a fully loaded node.
        Note that in my tutorial site's case, the node's ID was 1
        (the URL is example.com/node/1… …"1" = my node's ID).
        */
 
$login_node = node_load(array( 'nid' => 1));
  return
_phptemplate_callback('user_login', array(
       
'form' => $form,
       
// LOOK! this sends the $login_node variable to user_login
       
'login_node' => $login_node
   
));
}
?>

user_login.tpl.php: print the newly available variables.

<h1><?php print $login_node->title; //Yes, that was the node's title: ?></h1>
<?php
   
//Yes, that is the node's body:
   
print $login_node->body;
   
//try uncommenting this code below to see what else is available:
    // print "<pre>"; print_r(get_object_vars($login_node));print "</pre>";
?>

<?php
    print_r
(form_render($form));
?>

And like magic, there is your node — AND it can be changed by a non-programmer.

Part 3: Alter the form

Say we wanted to display our form horizontally. CSS could do most of the heavy lifting. Unfortunatly, the descriptions (e.g. “enter your username here”) kind of get in the way. If we were amateurs, we’d copy and paste the form directly into our template, and call it a solution. But remember kids, we’re experts and do things the right way ;-).

The array_values for the username and password forms are as follows:

[13] => Array
        (
            [#type] => password
            [#title] => Password
            [#description] => KILL ME KILL ME KILL ME
            [#required] => 1
            [#attributes] => Array
                (
                    [tabindex] => 2
                )

            [#tree] => 
            [#parents] => Array
                (
                    [0] => pass
                )

            [#weight] => 0.001
            [#input] => 1
            [#size] => 30
            [#name] => edit[pass]
            [#id] => edit-pass
            [#value] => 
        )

As you can see, #description really wants to be killed in this case. As you are no doubt aware, this is going to take a lot of work to do… I mean, look WHAT we have to do to kill it.

Template.php

<?php
function phptemplate_user_login($form) {
 
$login_node = node_load(array( 'nid' => 1));
 
//We're removing the description text before the form is rendered
 
$form['pass']['#description'] = '';
 
$form['name']['#description'] = '';
 
//A friendlier name for our submit button:
 
$form['submit']['#value'] = 'Get yer ass in here';
  return
_phptemplate_callback('user_login', array(
       
'form' => $form,
       
'login_node' => $login_node
   
));
}
?>

You’ll also note that we changed the submit button to “get yer ass in here”. That is because we understand the importance of friendly interfaces. Now let’s rearrange our user_login.tpl.php file, and add some CSS:

user_login.tpl.php

<div id="user_login">
<h1><?php print $login_node->title; //Yes, that was the node's title: ?></h1>
<?php
//try uncommenting this code below to see what else is available:
// print "<pre>"; print_r(array_values($form));print "</pre>";
   
print_r(form_render($form['name']));
   
print_r(form_render($form['pass']));
   
print_r(form_render($form));
?>

<?php
//Yes, that is the node's body:
print $login_node->body;
//try uncommenting this code below to see what else is available:
// print "<pre>"; print_r(get_object_vars($login_node));print "</pre>";
?>

</div>

And now the CSS… put it in style.css for now:
#user_login {
font-size:11px;
        padding:6px 12px;
}
#user_login p {
font-size:9px;
}
#user_login h1,
#user_login .form-item,
#user_login label,
#user_login input.form-text {
display:inline;
}

The Final, Step

Folks, this is where it gets hard. Now, we want to display our new login form on every page. Be strong, you can do this: 1)open up page.tpl.php, and insert the following code directly below the “body” html tag.

<body>
<?php print $user_login_form;?>

Now we add the final step, we call the user_login() function from template.php, and pass it to page.tpl.php. Here it is.

template.php

<?php
function phptemplate_user_login($form) {
 
$login_node = node_load(array( 'nid' => 1));
 
//We're removing the description text before the form is rendered
 
$form['pass']['#description'] = '';
 
$form['name']['#description'] = '';
 
//A friendlier name for our submit button:
 
$form['submit']['#value'] = 'Get yer ass in here';
  return
_phptemplate_callback('user_login', array(
       
'form' => $form,
       
'login_node' => $login_node
   
));
}
// Will explain later.
function  _phptemplate_variables($hook, $vars) {
  global
$user;
  switch(
$hook) {
          case
'page' :
       
// SUPER IMPORTANT: These rules prevent you from crashing your server :-)
       
if (arg(0) != "user" && $user->uid == "0") {
           
$vars['user_login_form'] = user_login($msg = '');
        }
        break;
  }
  return
$vars;
}
?>

VERY IMPORTANT: YOU MUST DISABLE ANY ACTIVE user login BLOCKS — otherwise, it won’t work.

And the final product:

Final Word

As the title of this tutorial suggests, this is merely an introduction. Expect part 2 in the near future.

Questions are encouraged. Also, I’ve provided a working version of this tutorial’s code.

Download a working theme based on this tutorial