How to embed a node form with drupal 6.
Developers often want to embed a node form. So I'll try to work out, how this is done best in drupal 6. For 5.x I provided the subform element module, which was an easy way to do it. However recently I found out, that embedding fully working node forms in 6.x isn't so easy any more. The funky JS stuff of node forms, which relies on the #ahah form API property, fails if $form doesn't look that way it expects.
So how to embed a node form with working AHAH?
Fortunately, it's not that hard either. We must just ensure to keep the structure of $form as in the original form. So don't move the embedded form in $form['fieldgroup'] - or it's #ahah stuff gonna break.
So let's show how to embed a node creation form. First off we have to get the form array of the node form:
<?php
// Initialize new node:
$node = array('uid' => $user->uid, 'name' => $user->name, 'type' => $type);
$form = drupal_retrieve_form($type .'_node_form', $form_state, $node);
drupal_prepare_form($type .'_node_form', $form, $form_state);
?>Now we have the form array, already altered by hook_form_alter() implementations. We could just go and use it - even its validation and submit handlers would be invoked. But we face two problems:
How to add own elements at the top and the bottom of the form?
That's not really hard. We have to add our #theme function that renders our own elements first and inserts the rendered, embedded form in the middle. Furthermore we make sure that the embedded form looks right by applying it's theme function.
So we add our own #theme function and save the #theme property of the embedded form for later:
<?php
// Preserve the old #theme property.
$form['#theme_saved'] = $form['#theme'];
$form['#theme'] = 'embed_example_node_form_reuse';
?>Then we make sure the embedded form is themed too:
<?php
/**
* Themes the form to put the custom parts of the form to the top and the bottom.
*/
function theme_embed_example_node_form_reuse($form) {
$top = drupal_render($form['top_example']);
$bottom = drupal_render($form['bottom_example']);
if (isset($form['#theme_saved'])) {
// Apply the theme of the embedded form
$form['#theme'] = $form['#theme_saved'];
unset($form['#theme_used']);
}
return $top . drupal_render($form) . $bottom;
}
?>How to keep control over the form?
If the form comes with it's own validation, submit handlers and different buttons with different handlers it can be quite cumbersome to make sure that a own handler gets executed.
So one can use a #after_build callback to just add the own handlers after the form API has determined the handlers, which are to be invoked.
<?php
// Register an after build callback
$form['#after_build'][] = 'embed_example_after_build';
?>When the #after_build callback gets executed, all button presses have been already detected, apart from a special case which fixes submitting single button forms for IE users. Usually this is not the case for node forms, but this code deals with this case too:
<?php
/**
* After build callback for the form.
*
* This is used to register our own #validate and #submit handlers, which are invoked
* regardless which button is pressed. So we keep control over the form.
*/
function embed_example_after_build($form, &$form_state) {
// Call the ie cleanup first, so that all buttons are detected now.
_form_builder_ie_cleanup($form, $form_state);
$form_state['submit_handlers'][] = 'embed_example_form_submit';
$form_state['validate_handlers'][] = 'embed_example_form_validate';
return $form;
}
?>That's it.
I've put this all together in a small example module, which can be found in my sandbox.
more.zites.net
Comments
silly me!
First argument is expected to be a valid callback
will this work for existing nodes?
not CCK aware
post issues
hmm.. and now works
<code>
fdfsdfsdd fsdjfh
How to embed a node form into a page in Druapl 6
very nice blog number one