User login

How to theme a Drupal form

Update: This tutorial has been revised significantly to provide a robust solution consistently works.

Define a function named your_theme_name_ or phptemplate_ plus name_of_form($form).

  • Tip: You can find out what the names of forms are by implementing hook_form_alter in a module and adding the code drupal_set_message("Form ID: " . $form_id);, as in the first commented out line in this example.

<?php
function phptemplate_user_register($form) {
    $variables = array('user' => $user, 'form' => $form);
    return _phptemplate_callback('user_register', $variables);
}
?>

Then create a .tpl.php file with that name.

In this case, user_register.tpl.php

We can use this PHP snippet:

<?php
drupal_set_message('< pre >'. var_export($variables,TRUE) .'< /pre >');
?>

This provides us with the variable names (inside the $form variable) that are available to "drupal render" at your own chosen place.

  • Tip: To preserve the functionality of Drupal's catch-all-remaining form elements, you must pass the the form values in from template.php in a broader variables array (as described above). This allows you to use a form variable with form element names as keys, rather than using form names directly. Form names directly will build the form, but without the ability to drupal_render all remaining form elements, and several hidden ones are essential to a functioning Drupal form.

Example of a form theming .tpl.php file:

<div id="regform1">
<fieldset class="group-account-basics collapsible"><legend>Account Basics</legend>

<?php print drupal_render($form['name']); ?>

<?php print drupal_render($form['mail']); ?>

<?php print drupal_render($form['pass']); ?>

<?php print drupal_render($form['field_user_picture']); ?>

<?php print drupal_render($form['field_city']); ?>

</fieldset>
</div>

<div id="regform2">
<fieldset class="group-story collapsible"><legend>My Story</legend>

<?php print drupal_render($form['field_storypic']); ?>

<?php print drupal_render($form['field_user_story_field']); ?>

</fieldset>
</div>

<?php print drupal_render($form['captcha']); ?>

<?php print drupal_render($form['submit']); ?>

<?php
unset($form['field_mostimportantlesson']);
print drupal_render($form);
?>

Note the last step: we unset any fields we don't want to show, and then print the remainder of the form. If you drupal_render($form) outputs something you don't want or in a place you don't want it, simply unset that field or drupal_render that field specifically where you do want it.

Modifying individual fields

That's great, we can put fields in any order, surround them with any markup we want, and skip ones we don't want. What about changing the output of a given field?

We will only discuss here the simple way, very similar to form_alter, yet powerful enough to almost certainly meet all your needs with the addition of CSS.

In this case, we want to do something special with the age at diagnosis field.

To see what we're doing and make an initial attempt which proved incorrect, we added this to our user_register.tpl.php file in our theme's directory:

<?php
drupal_set_message('<pre>'.print_r($form['field_ageatdiagnosis'],TRUE).'</pre>');
$form['field_ageatdiagnosis']['#suffix'] = ' '. t('years');
print drupal_render($form['field_ageatdiagnosis']);
?>

That printed "years" at the end of the whole form, not what we had hoped. We will be able to refine our attempt based on the output of drupal_set_message print_r on the field, below:

Array
(
[#tree] => 1
[0] => Array
(
[value] => Array
(
[#type] => textfield
[#title] => Age at Diagnosis
[#default_value] =>
[#required] => 0
[#description] =>
[#size] => 20
[#maxlength] => 11
[#attributes] => Array
(
[class] => number
)

[#field_prefix] =>
[#field_suffix] =>
[#post] => Array
(
)

[#programmed] =>
[#tree] => 1
[#parents] => Array
(
[0] => field_ageatdiagnosis
[1] => 0
[2] => value
)

[#weight] => 0
[#processed] =>
[#input] => 1
[#autocomplete_path] =>
[#name] => field_ageatdiagnosis[0][value]
[#id] => edit-field-ageatdiagnosis-0-value
[#value] =>
[#sorted] => 1
)

[#post] => Array
(
)

[#programmed] =>
[#tree] => 1
[#parents] => Array
(
[0] => field_ageatdiagnosis
[1] => 0
)

[#weight] => 0
[#processed] =>
[#sorted] => 1
)

[#post] => Array
(
)

[#programmed] =>
[#parents] => Array
(
[0] => field_ageatdiagnosis
)

[#weight] => 0.011
[#processed] =>
[#sorted] => 1
)

Based on this information, we revised our PHP to set #field_suffix:

<?php
$form['field_ageatdiagnosis'][0]['value']['#field_suffix'] = t('years');
$form['field_ageatdiagnosis'][0]['value']['#attributes'] = array('class' => 'number inline');
print drupal_render($form['field_ageatdiagnosis']);
?>

We could set #title and #size the same way.

As shown above, we can even add new classes by modifying the #attributes value (noting that in this case the number class was set in the #attributes array, and we would not want to unset it, so we list it again while adding the class inline):

Note: If you look at the HTML output for a form field, you may see additional classes. For instance, 'form-text' is supplied automatically by Drupal form_rendering, and does not need to be restated when adding a class attribute. Using the drupal_set_message('<pre>'.print_r($form['field_ageatdiagnosis'],TRUE).'</pre>'); trick to see what's there is a very good idea to make sure you don't overwrite any important attribute.

References:

Resolution

Searched words: 
Howto theme Drupal forms themeing input forms user_register with bio module

Comments

Themeing/Displaying form_set_error messages

Thanks for the great article. I have some problems displaying the form_set_error messages in my new form template -- is there an easy to have them display?
dp

Make sure you are printing the $messages variable

I'm pretty certain form_set_error messages uses the standard drupal_set_message system, and so will show up so long as your theme outputs the $messages variable in page.tpl.php.

For example, this is from bluemarine's page.tpl.php file:

      <div id="main">
        <?php print $breadcrumb ?>
        <h1 class="title"><?php print $title ?></h1>
        <div class="tabs"><?php print $tabs ?></div>
        <?php print $help ?>
        <?php print $messages ?>
        <?php print $content; ?>
        <?php print $feed_icons; ?>
      </div>

Update: absolutely certain

missed $messages

I used this example and thank you for it.

I had a little trouble getting $messages to show up when the form had a validation error (ie using form_set_error()).

I created a content type for form variables, then called page.tpl.php to build a form based on the CCK data. The errors wouldn't show up until the second time I submitted the form with the validation problem. The problem seems similar to http://drupal.org/node/304556 and I'm unsure of how to resolve it correctly.

I suppose that calling from form.tpl.php from settings.php from drupal_get_form() from page.tpl.php was messing with the session and $messages. So instead I loaded the template as a function call from hook_menu that sends the whole thing through theme('page'). This works, but it means my page.tpl.php can't mix up $messages in the middle of the page content the way I wanted to.

I don't know if it matters, but in my original page.tpl.php I wasn't calling $content, just building the form out of $node, so maybe a better approach would have been to call hook_nodeapi().

Do you have any thoughts about how to go about this the Right Honorable Drupal way?

the big question...

The $50,000 dollar question is, how do you achieve this in Drupal 6.x ?

Looking back, D5 was cake. That's progress for ya...

For $50,000 I answer that tonight!

Otherwise, it'll keep until we need it too ;-)

But the belief is that most everything theming-wise from Drupal 5 is still possible in 6, and frequently easier... I take it you've tried?

D6 custom node edit form

Yes I tried. I searched for clear articles and asked for help in chat, to no avail.

Outputting a custom content type in D6 is easy. Just create node-my_content_type.tpl.php and bam!, it works.

Controlling the edit form is not so simple...

In D6, you cannot add a snippet to the template.php and create node-my_content_type-edit.tpl.php. Apparently its much more complicated. I yearn for the good ol' days of D5. Great tutorial by the way.

If you know how to create a custom content edit form in D6 please share!

Adieu.

Of course you can theme forms in Drupal 6!

The best tutorial we've seen is Caroline Schnapp's Theming the register form in Drupal 6 which is the same process for theming any form, including node edit forms (I think the use of hook_theme, or rather THEMENAME_theme, is necessary for theming a custom node type's edit form.)

For theming forms in general, Agaric Design Collective's own Dan Hakimzadeh already had a Drupal 6 how-to up: theme the search form in Drupal 6.

The first example is like Dan's, and may not work for custom node forms. The second will work for any form no matter where a form is defined. In both, replace capitalized terms (EXAMPLETHEME, YOUR_FORM_ID) with your own values:

<?php
function EXAMPLETHEME_YOUR_FORM_ID($form) {
  // go wild
}
?>

or register your own. This will allow you to use a template file to theme your form:

<?php
function EXAMPLETHEME_theme() {
  return array(
    'YOUR_FORM_ID' => array(
      'arguments' => array('form' => NULL),
      'template' => 'your-form-id',  // following convention, replace underscores with dashes
    )
  )
}
?>

Form elements' theming can still be overridden with #theme.

<

h3>More Drupal 6 form theming resources:

<

h3>

http://api.drupal.org/api/group/themeable/6
http://api.drupal.org/api/file/developer/topics/forms_api_reference.html/6

Emma Jane's slides:
http://www.slideshare.net/emmajane/theming-drupal-6x-forms-presentation

I am unclear as to how to

I am unclear as to how to specify a specific content type 'node_form' for themeing in D6 with the function call in template.php when all of the forms appear to be 'node_form'. how do I tell the function to just use the new .tpl file for a specific content-type 'node_form' only?

form submit is not working while using custom user-register.tpl.

Hi,

I have used customization in user registration page

my code in template.php is

function CUSTOMTHEME _theme($existing, $type, $theme, $path) {
return array(

// tell Drupal what template to use for the user register form
'user_register' => array(
'arguments' => array('form' => NULL),
'template' => 'user-register', // this is the name of the template
),

);
}

and in user-register.tpl.php is

<?php
      print drupal_render($form['name']); // prints the username field
  
?>

<?php
      print drupal_render($form['mail']); // print the password field
  
?>

<?php
        print drupal_render($form['submit']); // print the submit button
    
?>

But the forms are displaying ( username + email + submit ) in q=user/register url

but while new user register submit button hits the values are not stored in database any solution plz help me to solve this issue

This was already covered in the post

Unset what you do not want, and print the rest of the form with drupal_render($form) -- or else hidden elements that the form needs to work are not included.

phptemplate_ name_of_form($form) is not working in my system

Hi Benjamin Melançon,

phptemplate_ name_of_form($form) is not working in my system.

Below is my code in template.php

function cricdee_comment_form($form) {
print_r($form);
exit;
}

when the page renders, this function is not getting called.
Can u pls tell me the issue with my code.

Register theme

You need to register the theme_hook "comment_form" using
function cricdee_theme($existing, $type, $theme, $path) {
return array(

'user_register' => array(
'comment_form' => array('form' => NULL),
'template' => 'comment-form', // Optional.. if used, hook is ignored
),

);
}

with this you can now do
function cricdee_comment_form($form) {
print_r($form);
exit;
}

and when you invoke the url using this hook u will get your results

Assuming that cricdee is

Assuming that cricdee is your theme name, then you are probably using Drupal 6 and should see the comment a little above yours, on theming forms in Drupal 6.

Nice explanation.......

I would be really interested to learn more from your up coming tutorial. please keep me inform cheers!

Wrong field id's

Hi,

I am using Drupal 6 and I am trying to theme my input form. I changed the template.php and created an tpl.php file. This works fine (I have tested it with some sample html in it). However I can't get the fields printed. I think I use the wrong id's.

This is what I have put in my tpl.php file:

<?php
print drupal_render($form['field_application']);
?>

<?php
print drupal_render($form);
?>

However, it still doesn't print the field_application.
I made an export of all my fields to this file (it's too big to post it in the comments section).

http://www.bizproc.nl/ListOfFields.txt

Can someone help me out?

Thanks!

Rendering form elements nested in arrays

Hi Paul,

Your form printout indicates that you have a number of fields, including field_application, nested inside fieldsets.

This is in a fieldset with the title Algemeen but as far as the array structure of the form it is simply index 2. I'm actually a bit confused by that, but I think you can render your field simply with:

<?php
  drupal_render($form[2]['field_application']);
?>

I've never tried this approach with fields within fieldsets, though. Good luck!

Rendering form elements nested in arrays

My fields are encapsulated in containers. If you refer to the container and then to the filename everything works fine.

<?php
print drupal_render($form['group_cpr_generic']['field_application']);
?>

Thanks for your help!

Pure and nice article.Thanks

Pure and nice article.Thanks man.gradually love drupal : )

I'm a bit stumped -- I'm

I'm a bit stumped -- I'm trying to edit a site's lengthy user registration form, but there's no file called user_register.tpl.php in the active theme directory. This snippet does appear in the template.php code:

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

But this is the only code in the user_login.tpl.php file:

<?php
    print drupal_render($form); // this displays the login form.
?>

<p><?= l(t('Forgot your password?'), 'user/password') ?></p>

Also, none of the other *.tpl.php files in the theme directory pertain to the registration form... any help would be greatly appreciated!

I never really understood

Nice understanding of Form mapped with themes

Hi,
The Documentation is really nice, it reduce lot of my time. for better understanding u can also give downloaded sample. so that on the fly every one will easy to use it.
Once again Thanks for the stuffs given.
Regards,
vivekanandan

Different admin theme

I'd like anonymous visitors to be able to add a content item. I can get the form to display using permissions. But the issue I'm having is that the form displays using the Admin theme (Garland). I need it to display in the custom Default theme. I don't see that covered here. Can you help me make it happen?

I know this is an old

I know this is an old article, but thanks, it helped me a lot.

There's a couple things I had to do to get it to work (with Drupal 7) though:

1) You must render the rest of the form with drupal_render_children($form). drupal_render($form) causes an infinite loop with drupal_render triggering the theme functions over and over again.

2) When you pass/assign the form array, make sure you do it by reference, or drupal_render_children will just print out the whole form again.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • You may post code using <code>...</code> (generic) or <?php ... ?> (highlighted PHP) tags.
  • You can use Markdown syntax to format and style the text. Also see Markdown Extra for tables, footnotes, and more.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <img> <blockquote> <small> <h2> <h3> <h4> <h5> <h6> <sub> <sup> <p> <br> <strike> <table> <tr> <td> <thead> <th> <tbody> <tt> <output>
  • Syntax highlight code surrounded by the {syntaxhighlighter SPEC}...{/syntaxhighlighter} tags, where SPEC is a Syntaxhighlighter options string or "class="OPTIONS" title="the title".
  • Lines and paragraphs break automatically.

More information about formatting options

By submitting this form, you accept the Mollom privacy policy.