Extreme Form Handling in Drupal
Drupal Form-Handling support goes far beyond just the documented part of so-called Forms API. You can do pretty much anything with forms in Drupal and you can use/display the forms anywhere. Here is an example. Let’s assume we want to construct a custom node type with custom fields, using CCK. Then we want to display this form into some non-standard page. To further complicate things, let’s assume we also want custom verification and processing routines. And last but not least – we want to use full power of Drupal and write a minimal amount of code.Drupal Form-Handling support goes far beyond just the documented part of so-called Forms API. You can do pretty much anything with forms in Drupal
and you can use/display the forms anywhere.
Here is an example. Let’s assume we want to construct a custom node type with custom fields, using CCK. Then we want to display this form into some non-standard page. To further complicate things, let’s assume we also want custom verification and processing routines.
And last but not least – we want to use full power of Drupal and write a minimal amount of code. Following is a snippet demonstrating key points to achieving this task (thorough understanding of Drupal is required):
$node = new StdClass();
$node->type = OUR_NODE_TYPE;
$form = node_form ( $node ) ;
drupal_prepare_form( OUR_NODE_FORM_ID, $form ); //Let all form hooks run
//— Indicate proper processor, submit function, validate function etc.
$form['#action'] = '/node/add/'.OUR_NODE_TYPE;
$form['#validate'] = array('ourmodule_ourvalidationfunc' => array());
$form['#submit'] = array('ourmodule_oursubmitfunc' => array());
ourmodule_form_disable_defaults( $form );
//— Render the form:
$form_html = drupal_render_form( OUR_NODE_FORM_ID, $form );
//— You just got a rendered HTML of the form in $form_html that you can
//— add to your output
.....
/**
* Disable some annoying default fields just for the
* kicks and to demo the power of what can be done.
*/
function ourmodule_form_disable_defaults ( &$form ) {
$form['attachments']['#collapsed'] = 0;
$form['body_filter']['format'] = null;
$form['format'] = array('#type' => 'hidden',
'#value' => 1);
$form['log'] = null;
$form['log'] = array('#type' => 'hidden',
'#value' => '');
$form['comment_settings'] = null;
$form['comment'] = array('#type' => 'hidden',
'#value' => 2);
$form['menu'] = null;
$form['body_filter']['body']['#rows'] = "5";
$authorname = $user->name;
$form['author'] = null;
$form['name'] = array('#type' => 'hidden',
'#value' => $authorname);
$form['options'] = null;
$form['path'] = null;
$form['status'] = array('#type' => 'hidden',
'#value' => 1);
$form['preview']=null;
}Please note that if your machine-readable name of the custom node type is something like “flight_schedule” then you will be defining the constants used in the code, as follows:
define ('OUR_NODE_TYPE', 'flight_schedule');
define ('OUR_NODE_FORM_ID', 'flight_schedule_node_form'); Also, both the custom validation and submit functions have similar signature:
function ourmodule_ourvalidationfunc ($form_id, $form_values)
// and
function ourmodule_oursubmitfunc ($form_id, $form_values)where $form_id is the Drupal form_id of the form and $form_values is an indexed array of submitted values. In the validation function you can set alert points using form_set_error() function like this:
form_set_error('field_flight_schedule', t('Flight Schedule ID must be unique.')); where field_flight_schedule is a form element ID coming from a CCK field.
Also, for node forms you can call the original submit function from your submit function, so that you don’t have to duplicate things it already does. You do it with something like:
$original_return = node_form_submit($form_id, $form_values); and you can end your _submit function with “return $original_return” so form submit redirects to where it would normally do.
The rest of the code should be self-explanatory, given a reader is proficient in Drupal. Also, you can leave comments here, if you have further questions.




Comments
context
Irakli, thanks for writing this, it’s just exactly the area I’m stuck on. Can you say a bit more about where to write this code, given that the contentType is defined in CCK. Do you write a module as well? So how do you link the module to to the CCK type? This is relevant here:
http://www.civicactions.com/blog/cck_import_and_update
Also perhaps you could say something about producing a confirmation page for a CCK add/node operation?
Matthew
CCK Import During Install
Matt,
yes, you should create a module and put such code into that module. In the .install file of that module you can import CCK definition with a code like:
function ourmodule_CCK_install() {
$modulepath = drupal_get_path ('module', 'ourmodule');
$cck_definition_file = $modulepath."/custom.cck";
$values['type_name'] = '<create>';
$values['macro'] = file_get_contents($cck_definition_file);
include_once( drupal_get_path('module', 'node') .'/content_types.inc');
include_once( drupal_get_path('module', 'content') .'/content_admin.inc');
drupal_execute("content_copy_import_form", $values);
}
where custom.cck under your module folder is the file that you can export from CCK if you have cck_content_copy module installed.
yeah I have to say
so far I have found that the webform module is a bit of a bust, it is great to be able to quickly build these forms and everything but it is completely useless if you cannot provide your own action for it.
easier way
wow, i wish there was an easier way. i’m proficient in drupal, but not APIs.
I’m looking to provide a feedback form that includes a specific subject line and ID. so the usr clicks on a node, the node has a unique id, and when the user clicks “email” or “contact,” the node ID is sent with the email.
WebForm Module
For something like that you do not need to write code. Take a look at the WebForm module: [ http://drupal.org/project/webform ]
webform won't work
Webforms won’t really work for what i’m doing. If I have 50 listings I’d have to create a web form for each listing.
create multiple cck nodes with single form?
Thanks very much for this extremely useful post!
I need a custom form that will create several related CCK nodes at the same time.
Can I use the approach described in this post (drupal_render_form, etc) to pull the standard node creation forms for several different content types onto a single page? And then could I allow the built-in CCK submit handlers to deal with creating the new nodes?
Appreciate any direction you can provide.
Should work
To be perfectly honest, this blog post is so old, I don't even remember if the code is compatible with Drupal6. If I had to guess, it's probably Drupal5 code, but in general - yes using roughly the approach described here (Forms API with appropriate combination of drupal_get() or drupal_prepare() and drupal_render()) and by writing a custom submit handler you should be able to get what you need. At some point you may need to also implement hook_form_alter() depending on what you are doing.
Post new comment