Cleaning Up Node Edit Forms

Every time you build a new application in Drupal you *always* have to carefully govern the number of options available to normal site editors, or their heads will explode. (Literally. I've seen it.)

Almost every module you install will put something more on the node forms, until you end up scrolling forever just to reach the Save button. Not to mention most of this stuff you won't want them playing with anyway.

Of course a lot of this "tidying" can be done with roles and user permissions. You can hide most stuff from Joe Editor this way, but sometimes the form is still pretty long and unwieldy. So how do you make prettier node forms?

Step 1, Vertical Tabs!
http://drupal.org/project/vertical_tabs

This cool little utility is core in Drupal 7.x (cue jig for joy here) but in Drupal 6.x it's contrib, so go and install it. Now!

It provides a neat little check-box mechanism on the content type edit form allowing you to specify which fieldsets presented by other modules on the node form are ok to become tabs instead. I check all the boxes. The result, our ugly fat node form becomes a set of pweddy widdle tabs under the content body field. Nice! =)

There are some issues though. I don't know about the new core version, but sometimes modules present their options outside of a fieldset and the Drupal 6.x version of Vertical Tabs can't do much with them. Other times Vertical Tabs simply doesn't recognise a fieldset as one that can become a tab (seems the Twitter module is a case in point). I think this is down to whether the module implements hook_content_extra_fields() properly or not (which, for the record, every Drupal 6.x module putting stuff on the node add/edit forms should - I lecture myself there too).

Then there are custom requirements due to specific client work-flows. For example, my client requested publishing options, URL alias settings and post to Twitter options to all be in one fieldset (or tab, as it now is) because these represented his most common tasks and having to switch tab to do them was a pain. He also wanted a Related Items CCK field (a nodereference field pulling up other content on the site in the same categories) to sit with Taxonomy, again, to reduce the number of clicks and because it feels right that it's there.

Fortunately there's good old hook_form_alter() for just this sort of thing. Here's the code I used to shunt things around and push stuff in to vertical tabs that weren't appearing as tabs already:

<?php
/**
* Implementation of hook_form_alter().
*/
function economistconferences_features_form_alter(&$form, $form_state, $form_id) {
 
 
/*
   * Alter the node form to group things more intuitively
   */
 
if ($form['#id'] == 'node-form') {
   
   
// Move all path options to publishing options
   
if ($form['path']) {
     
$form['options']['path'] = $form['path'];
      unset(
$form['path']);
    }
   
   
// Move all twitter options to publishing options
   
if ($form['twitter']) {
     
$form['options']['twitter'] = $form['twitter'];
      unset(
$form['twitter']);
    }
   
   
// move related items box in with Taxonomy
   
if ($form['field_related'] && $form['taxonomy']) {
     
$type = content_types($form['type']['#value']);
     
$field = content_field_form($form, $form_state, $type['fields']['field_related']);
     
$form['taxonomy']['field_related'] = $field['field_related'];
      unset(
$form['field_related']);
     
     
// make tab title more descriptive
     
$form['taxonomy']['#title'] = t('Categories &amp; related items');
    }

   
// we need to add a validate function so we can remove our CCK
    // field from Taxonomy and put it where it should be in $form_state
   
$form['#validate'][] = 'economistconferences_features_node_form_validate';
   
  }
 
}
?>

I'm not going to explain how the hook works, because there's loads of other blog posts and the API docs for that. If you're familiar with the hook already, you'll notice I'm just pushing stuff in to fieldsets that already exist and Vertical Tabs knows about, then removing them from the main form. No rocket science there.

A word of warning. If you're going to engage in this sort of jiggery pokery, you should expect the unexpected. On the whole this just works - the values go in to $form_state as you'd expect and the various modules do their thing - but some modules might expect $form_state to have a specific structure in order to function correctly. An examples of this is Taxonomy.

You'll notice the last bit of my form altering code adds a validate function, which looks like this:

<?php
/**
* This additional validate function for the node forms takes
* the Related Items CCK field values out of the Taxonomy
* collection of values and puts it where it should be in the
* $form_state collection, to avoid Taxonomy module errors.
*/
function economistconferences_features_node_form_validate($form, &$form_state) {
 
$form_state['values']['field_related'] = $form_state['values']['taxonomy']['field_related'];
  unset(
$form_state['values']['taxonomy']['field_related']);
}
?>

If we leave the Related Items CCK field where it is, in $form_state['values']['taxonomy']['field_related'] then the Taxonomy module tries to process it as though it were a vocabulary. We don't want that, but fortunately it only happens on submit, so we have time to do something about it in a validate function, which is exactly what the above function does. Simply takes the CCK values out of the Taxonomy values and puts them back where CCK expects to find them.

You may need to do something similar with the values for some other modules. Taxonomy was the only one I came across, but there will surely be others that require a specific structure in the form values. Organic Groups feels like it might well be another case, given my fun and games with it and node forms in the past.

So, all done, I've tested this and it works. Client is happy, because this simple UI change is a real time-saver. Oh, and Vertical Tabs rocks! Very happy it's now core. =)

Edit: A wee follow-up. Follow this issue for the CCK module's fieldgroup.module, still not core in Drupal 7.x, which would address this in the UI. Please support:
http://drupal.org/node/404528#comment-1801420

You can also force something

You can also force something into a tab by adding a fieldset to it. My example is having the Vocabulary show in a tab when only one vocab exists for a content type. It didn't add the fieldset by default.

// If only one taxonomy, no fieldset is created
// force taxonomy into a fieldset if only one taxonomy exists
// this will add it to vertical tabs
if( isset($form['taxonomy']['#type']) )
{
  $form['taxonomy']['#type'] = 'fieldset';
  $form['taxonomy']['#title'] = 'Vocabularies';
}

Is there a better way to do this?

I'm using this

I'm a drupal developer and use the vertical tabs - I think they're a really good way of tidying up the space on a web page. Definately worth trying.

Cheers.

The Interface Module

Michael Haggerty over at Trellon released a module called interface that allows you to modify drupal forms (including node add/edit) via a drag and drop interface. I have not used it, but did watch a screen cast, and it looked pretty awesome. It lets you customize to the look of the form, much in the way you could use panels to modify a node edit form (in panels2, i haven't looked at that in panels3 yet).

Theme function overrides

When I need to rearrange the output of my form elements I prefer to use theme overrides (theme_NODE_FORM_ID()).

The advantage is that you are only manipulating output and not screwing around with the underlying $form array which, as mentioned above, other modules might be relying on. It also avoids using the validate function to fix up the array structure which is a bit of a hack.

hook_form_alter() is great for changing properties of form elements i.e #type, #title and #access but in the case of node forms, I'd avoid using it to rearrange structure as much as possible.

In some cases, It's probably

In some cases, It's probably because you need to tell Vertical tabs which fieldsets you want included. You have to edit the content type and adjust the Vertical tabs setting.

Absolutely

You're correct - in most cases it will just be editing the content type. There seem to be just a few annoying exceptions. =/

Removing fields/fieldsets

There are also cases where you want to remove fields or fieldsets from the form, like the menu or path settings for example. Rather than using unset(), you can use:

$form['menu']['#access'] = FALSE;

The advantage is that if the element has default values that are set, they will be preserved. Note that this method can still break in a few cases, the "word of warning" from the article is also valid here.

The node form columns module

The node form columns module is also a very useful and easy way to reorganize/hide/collapse/expand fields on the node edit form, although it provides no way to manage fieldsets. Very handy for simple needs.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • 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> <blockquote>
  • Lines and paragraphs break automatically.
  • You may post code using <code>...</code> (generic) or <?php ... ?> (highlighted PHP) tags.

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
Image CAPTCHA
Enter the characters shown in the image.