Last updated March 16, 2007. Created by Lionfish on March 6, 2007.
Log in to edit this page.

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);
}
?>

Looking for support? Visit the Drupal.org forums, or join #drupal-support in IRC.

Comments

I'm doing some cck node reference research and wondering what direction this project took for D6. It would be valuable for me and others to get some insight in the comments here.

Be well,
R.J. Steinert III
RjSteinert.com

"Happiness is the process not the place."
-Diener