Category: 

Topics: 

To find what I needed was like opening random doors for small bits of info.
Aug
11

The Form Hunt

Finding the way to create custom form templates in Drupal 7

Sometimes getting started in Form API can be like opening random doors until you find a piece of what you are looking for. Then you have to put it all together. When I first discovered a preprocess function that allowed me to create Drupal forms in a template file, I finally felt that I had complete control of controling the user experience. Granted, there are modules that can help with the form displays, like Panels or Node Form Columns (which seemed amazing when I first discovered it), but to have complete control, you really need to get a grasp on Drupal's Form API.

Forms API and Drupal 6

For those of you who haven't discovered this yet, here is the preprocess function to declare your form template:

function YOURTHEME_theme($existing, $type, $theme, $path) {
  return array(
    // tell Drupal what template to use for the user register form
    'FORM_ID' => array(
      'arguments' => array('form' => NULL),
      'template' => 'TEMPLATE-NAME', // this is the name of the template
    ),
   
  );
}

This goes into your template.php file. If make sure you're theme doesn't already utilize the YOURTHEME_theme preprocess or you will get an error. If it does, add what's inside the function above to your existing funciton.

The hardest part about this can be determining the FORM_ID, but the best place to look is in the actual ID attribute of the form you want to customize. Make sure your replace the dashes (-) with underscores (_). Also, if you're customizing a node form, try adding the content type's machine name in front of node_form so if it is a content type of post, it would be post_node_form.

Then create a file using the template name you placed in your preprocess function (with the above code it would be TEMPLATE-NAME.tpl.php). I generally start with this to test it:

<div class="post-form">
  <h1>TEST</h1>
  <?php print drupal_render($form); ?>
</div>

Then replace the test with a script to print the variables using the Devel module.

<div class="post-form">
  <?php dsm($form);?>
  <?php print drupal_render($form); ?>
</div>

Then you use the variables that you find in the array to print your fields out exactly as you want it. Only print the fields that you need to be seperated from the main form. Leave the drupal render form at the bottom because that will print out what ever is left and make sure you aren't missing anything. You can also unset fields that you don't want to display, or edit specific parts of other fields. Here is the final example showing how you could edit a field setting, print a specific field,  and unset others (I only commented out the DSM in case I need to change this template later):

<div class="post-form">
  <?php //dsm($form);?>
  <div class="subtitle">
    <?php $form['field_subtitle']['#description'] == 'describe the subtitle';?>
    <?php print drupal_render($form['field_subtitle']);?>
  </div>
  <?php unset($form['field_image'];?>
  <?php print drupal_render($form); ?>
</div>

This is only an example. I recommend you check out the Form API Quickstart Guide to see how you should arrange your arrays within the drupal_render to get the desired output. This approach can be particularly useful in customizing things like the global search, login form, and specific node forms that require better mockup represenation than what the CCK display settings can provide.

Now Forms in Drupal 7

Recently, I attempted to bring this approach to a Drupal 7 installation. I hit a few roadblocks that probably took longer to figure out than they should have, so naturally I am going to post that information here.

In order to get this to work in Drupal 7, I had to add a little bit more to the preprocess function. Particularly, the 'render element' and the 'path' had to be added to my array in order for Drupal 7 to read my form template. It looked something like this:

function MYTHEME_theme($existing, $type, $theme, $path) {
  return array(
    'FORM_ID' => array(
        'arguments' => array('form' => NULL),
        'path' => drupal_get_path('theme', 'MYTHEME') . '/templates',
      'template' => 'TEMPLATE-NAME',
        'render element' => 'form',
    ),
  );
}

Notice the path had to target the templates folder inside my theme. This worked just fine for rendering the form and wrapping divs around it. I ran into an issue when I tried to do a DPM (like the dsm for drupal 6, i use dpm for drupal 7) of the $form. Even printing a <?php dpm('Hello World!');?> did not result in anything when placed in my newly created TEMPLATE-NAME.tpl.php file.

The only way I was able to print the form variables was to create another preprocess function in my template.php file, this time targeting my custom form specifically:

function MYTHEME_form_FORM_ID_alter(&$form, &$form_state, $form_id) {
  // Stuff with your variables
  dpm(get_defined_vars());
}

This successfully printed the variables on the specific form that I needed to create my template file. This form alter function is another way to customize specific parts of fields without cluttering up your TEMPLATE-NAME.tpl.php file.

From there I had to use drupal render a little differently. Here's how you can print your form in Drupal 7:

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

The drupal_render_children applies to the fields as well as you print specific fields in your template file.

This may be a lot to take in at once, but hopefully this information will help you to better control your forms in Drupal. If you know a better way to do form templates with Drupal 7, I hope you will leave a comment and let us know!

Do you have an opinion or something to say about this?
comments

Leave A Comment