Addnode
Addnode is a widget which allows users to create nodes, rather than select them from a list.
Acknowledgements
Development was aided by help and moral support from:
merlinofchaos, fago, eaton, jacobredding, emspace, eric_, webchick and others.
The project is funded by obslogic
Creating the form
Summary
The main idea is that the function retrieves the form arrays for the various types that node-reference can reference (by calling the _retrieve_subform_function below).
These subforms are then added to the main form, in a 'branch' of the tree (to avoid conflicts with the items already in the array).
Fixed Problems
- Concerned names still conflict on page.
- Originally just regexp and shoved in html into form to add the subforms (this didn't work - not surprising :)
- Form returned appears to just be the basic node creation form and not the whole form. This seems to be because static $forms in the drupal_retrieve_form function is already populated. Hence it thinks it doesn't need to make the form maybe???? Need to know how to get around this: I needed to call "function drupal_prepare_form($form_id, &$form)" to finish the form off.
- Unexpectedly $op=='form' in the call to the function! This breaks stuff
- Something breaks in submission - probably in validation? (but it silently fails...)
- It is displayed in the configuration window. Why is $op == 'form' even called in the config window?!?
- Submitted form was handled by the subform handler! Fixed by replacing drupal_prepare_form with home-made code.
- Added node needs selecting from the list once it's made
- Need to test multiple addnodes work on the same form
The _retrieve_subform function
Creates a node and retrieves the subform using it.
<?php
function _retrieve_subform($type)
{
global $user;
$node = array(
'uid' => $user->uid,
'name' => $user->name,
'type' => $type,
);
$args = array(
$type.'_node_form',
$node);
$form = call_user_func_array('drupal_retrieve_form', $args);
return $form;
}
?>Step by Step
Below I've gone through the addnode_widget function, cutting just the most relevant code, to try to explain its function...
If $op = 'form'... Then we need to generate and return a form array, describing how to build the widget:
First we get a list of potentially selected items: (put it in $options)
<?php
$options = _nodereference_potential_references($field, true);
foreach ($options as $key => $value) {
$options[$key] = _nodereference_item($field, $value);
}
?>We also get the list of types we can select (or create!): (put it in $type_list)
<?php
foreach ($field['referenceable_types'] as $ref_type)
{
if ($ref_type)
{
$type_list[] = $ref_type;
}
}
?>Next a load of prefix and suffix stuff is made to surround our select list.
<?php
$fieldname=$field['field_name'];
$createmsg=_create_new_message($type_count, $fieldname, $typedesc, $type_list);
$title=t($field['widget']['label']);
$prefix = "";
$prefix.= "<b>$title:</b>";
...blah...
...blah...
$subsuffix.= "</table>";
?>We next create the form array:
<?php
$form[$fieldname] = array('#tree' => TRUE);
$form[$fieldname]['nids'] = array(
'#type' => 'select',
'#title' => '',//$title
'#default_value' => $node_field['default nids'],
'#multiple' => $field['multiple'],
'#options' => $options,
'#required' => $field['required'],
'#description' => $field['widget']['description'],
'#prefix' => $prefix,
'#suffix' => $suffix,
'#size' => 15,
'#weight' => $field['weight'],
'#attributes' => array(
'style' => 'width:100%',
'class' => "addnode_select",
'id' => "$fieldname",
),
);
?>Now we need to add the subforms (of the items we could create).
The _add_subform function is called add the subform to the form.
<?php
foreach ($type_list as $atype)
{
$subform = _retrieve_subform($atype);
//manipulate subform items and add to the main form
_add_subform($form, $subform, $fieldname, $atype, $subprefix, $usesuffix, $weight);
}
?>The form has its standard submit method overridden:
<?php
$form['#submit']['node_form_submit'] = array();
$form['#submit']['addnode_subform_submit'] = array();
?>And that's it, for creating the form.
Submission
Current code: Currently hardwired for 'pots'.
<?php
function addnode_subform_submit($form_id, &$form_values)
{
$node = array ('type' => 'pot');
$vals = _form_values_flatten($form_values['field_test']['pot']);
$errors = drupal_execute('pot_node_form',$vals,$node);
}
?>