Let me clarify staright away that the code below has been tested successfully against Drupal 6 only. But I believe it should work with Drupal 7 also with minor changes (if any required). Okay now, let’s come to the point.

“Save as Draft” as you can imagine is a pretty handy option for content authors. It allows them to save their unfinished work mid-way and come back to it later. Drupal as such provides a “Published” option out-of-the box for nodes, which works similar to “Save Draft” functionality. Nodes that are not published as yet are not available to general audience for viewing and are accessible to authorized users only (those with the “edit any content_type” permission for the corresponding content type).

But the major problem with Drupal’s published option is that even if a node is not published (thus meaning that either the author is not finished with it, or the entire content for the node is not available etc), Drupal fires all validations on the node while it is being saved (it does not matter if you have published on or off, Drupal always validates the node content and would not allow saving if validation fails).

This was where a client of mine hit a major hiccup. They were having multiple content types, with a couple of them having insanely large number of data entry fields (needless to say added through CCK to the content types). And it happened that their authors did not have all the required information while they were adding content, i.e. they wanted to add the content to the node fields iteratively as more details become available but the node should be available on the site only when they have completed all the fields properly. Sometimes the authors needed to leave as they were entering data in (pretty long) node forms and hence again wanted the ability to save the form with the currently entered data, come back to it later and complete it.

The ability to make it available on site when desired was easily achievable with the Drupal core’s Published flag. The problem was validations on fields that were marked required or other validations on the fields were preventing the form from saving even with “Published” turned off. As already said, the data was either not available to fill-in at the time, or they needed to save and return back to it later.

The essence is I needed to allow them to save the node bypassing all validations (whether they are for core Drupal fields or for fields added by modules like CCK) when the node was not published.

My initial instinct was that this should be a pretty common requirement and some contributed module for Drupal should be available that by-passes all validation providing a true “Save Draft” functionality for nodes. I came across 3 modules on Drupal that went by saying to provide a “Save Draft” functionality for nodes, but none of them bypassed validation. The node was allowed to be saved only when it successfully passed all validations defined on the node.

And I now knew this needed some custom development. Okay so, I said to myself, let’s see how can I bend and transform Drupal to make it work for me (I anticipated this might require some real improvisation and hacking into how Drupal works).

My first approach was to replace the default Drupal validation methods for a node form. So I used hook_form_alter and overrode the validation methods on the node form, something like:

 

{syntaxhighlighter brush: php;fontsize: 100; first-line: 1; }function mymodule_form_alter(&$form, &$form_state, $form_id) {
switch($form_id) {
case ‘artist_node_form’:
$form[‘#validate’] = array(‘mymodule_custom_validation’);
break;
}
}

function mymodule_custom_validation($form, &$form_state) {
$status = $form_state[‘values’][‘status’];

if($status == 1) {
//Here I manually called the original validation methods for the node form as the status is Published.
//I have not shown in this code, but I preserved the default validation methods array in hook_form_alter above which I now called in a loop.
}
}{/syntaxhighlighter}

Notice in the above code that I am completely replacing the #validate methods with my own validation method instead of adding to the existing validation methods.

However this approach did not work. I am not sure why but the default validation methods were always called even after I had replaced them with the code above. I tried various forms of this approach, like assigning the validation methods in #after_build method, assigning validation method explicitly for the “Submit” button itself, and other such options based on replacing Drupal’s validation methods. But none of this worked (to my surprise).

After not being able to succeed with this approach, I thought of trying another completely different alternative. That of allowing Drupal to carry on its normal process and validations, but after Drupal had done so, manually clear all errors for the node form if the status was unpublished.

So, this time I came up with the following code:

 

{syntaxhighlighter brush: php;fontsize: 100; first-line: 1; }function mymodule_form_alter(&$form, &$form_state, $form_id) {
switch($form_id) {
case ‘artist_node_form’:
$form[‘#after_build’][] = ‘mymodule_after_build’;
break;
}
}

function mymodule_after_build($form, &$form_state) {
$form[‘#validate’] = array(‘mymodule_custom_validation’);

return($form);
}

function mymodule_custom_validation($form, &$form_state) {
$status = $form_state[‘values’][‘status’];

if($status == 0) {
//Reset form errors.
form_set_error(NULL, ”, TRUE);
//Clear error messages.
drupal_get_messages(‘error’);
}
}{/syntaxhighlighter}

And yes, this approach worked perfectly to my great relief. Now here, I first use hook_form_alter for the desired node form to register an #after_build method for the form. In the #after_build method, I further register (rather override) the #validate method for the form (To understand why I register the #validate method in #after_build method and not directly in hook_form_alter method, see my previous blog post here).

In my custom validation method, I first clear all errors that have been registered by the previous validation methods using: form_set_error(NULL, ”, TRUE);

The documenation for form_set_error clearly states that passing TRUE as the last argument clears out all errors previously set through a call to form_set_error for the current form submission.

This is actually all we need to do to bypass validation and allow the node form to be saved even when it violates the rules. But to prevent the messages for the validation errors registered earlier (and cleared using form_set_error as explained above), I also placed a call to drupal_get_messages passing ‘error’ as the type. This removed all ‘error’ messages that are implicitly created with a call to form_set_error from getting displayed on the next screen. And viola, it works perfectly as desired!!!

I am thinking of rolling this up in a module and publish it on drupal.org. But because of my current too hectic schedule, and the fact that the actual code is hardly 10-15 lines, I have decided to publish the technique to only my blog currently.

Please let me know (via comments below) if you think this deserves to be a module on its own. If enough people agree, I might well release a module for the same.