The problem with using a good web framework... or how to fix the Node Add form

One of the problems with working on a great web framework is one makes assumptions about where the bugs lie. It is much easier to believe that the code I've written has a bug than that framework has a bug. Compounding the problem when you check out a website like Drupal.org and don't find a mention of the problem that perhaps you're the only one who has ever had the problem.

Such is the way I spent the morning. Working on a site and watching chunks of hair turn grey while searching for my mistake. Then in the latter stages of testing, having eliminated my code and all the modules that one starts to look at Drupal Core with a questioning eye. And that is when I found the bug, with comments and all, hanging out in the node module.

Allow me to back up here a bit and explain that the current undertaking includes making changes to the Publishing Options section of the node add form. There are plenty of changes you can make but one critical one you can't. You can change the code of the section, add information and change the settings. Unfortunately no matter how many times you change the #weight parameter it doesn't do anything. This also affects the Author Information section and the buttons at the bottom of the page. For a current project we want to have the publishing options near the top of the page. This should be a simple call to a hook_form_alter(). Alas altering the form doesn't affect the output.

The offending code is in the theme_node_form() function. Here's that function:

<?php
function theme_node_form($form) {
 
$output = "\n<div class="node-form">\n";

 
// Admin form fields and submit buttons must be rendered first, because
  // they need to go to the bottom of the form, and so should not be part of
  // the catch-all call to drupal_render().
 
$admin = '';
  if (isset(
$form['author'])) {
   
$admin .= "    <div class="authored">\n";
   
$admin .= drupal_render($form['author']);
   
$admin .= "    </div>\n";
  }
  if (isset(
$form['options'])) {
   
$admin .= "    <div class="options">\n";
   
$admin .= drupal_render($form['options']);
   
$admin .= "    </div>\n";
  }
 
$buttons = drupal_render($form['preview']);
 
$buttons .= drupal_render($form['submit']);
 
$buttons .= isset($form['delete']) ? drupal_render($form['delete']) : '';

 
// Everything else gets rendered here, and is displayed before the admin form
  // field and the submit buttons.
 
$output .= "  <div class="standard">\n";
 
$output .= drupal_render($form);
 
$output .= "  </div>\n";

  if (!empty(
$admin)) {
   
$output .= "  <div class="admin">\n";
   
$output .= $admin;
   
$output .= "  </div>\n";
  }
 
$output .= $buttons;
 
$output .= "</div>\n";

  return
$output;
}
?>

Yup right there in all it's well-commented glory is the reason my code wouldn't work. No matter what the weight assigned to the Publishing Options they are not going to budge. The issue for fixing this in Drupal 7 is http://drupal.org/node/296918. (Please feel free to review and comment on that patch).

The patch could fix the situation going forward but what to do about those who need the functionality now? Fortunately because this is a theme() function it is easy to fix. The following code, added to a site module, will solve the problem for all themes using the PHP Template theme engine:

<?php
function phptemplate_node_form($form) {
 
$output = "\n<div class="node-form">\n";

 
$output .= "  <div class="standard">\n";
 
$output .= drupal_render($form);
 
$output .= "  </div>\n";
 
$output .= "</div>\n";

  return
$output;
}
?>

Sharp-eyed readers will note this does eliminate the admin class so if your theme depends on this some additional work will be necessary. Also you're likely to note that after implementing this the buttons and sections are out of order. Adding #weight parameters to the field sets will help with this. Lullabot has a good post about modifying forms if you need additional information.

Category: