background image
HomeRecent PostsDrupalSearchTagsRSSContactAboutAccount

Programmatically create any node type using drupal_execute

Eric.London's picture

Here are some tips on how to create a node programmatically in a Drupal module. The safest way to create a node is to use the drupal_execute() function which simulates the submission of a form [see API documentation]. This function accepts a variable number of arguments: 1) $form_id; 2) $form_state; and 3) any additional arguments. When creating a new node, the 3rd argument should be a $node object.

The $form_id should be formatted: NODETYPE_node_form. To confirm this, you could use hook_form_alter to show the form IDs for the current page (NOTE: you'll have to be on node/add/NODETYPE to display the node form ID).

<?php
function MYMODULE_form_alter(&$form, $form_state, $form_id) {
  echo
$form_id . "<BR>";
}
?>

For the second argument, you'll have to create an array that contains $form_state values (the data submitted from the node/add/NODETYPE form). Here is a basic $form_state array:

<?php
$form_state
= array();
$form_state['values'] = array(
 
'title' => t('MYTITLE'),
 
'body' => t('MYBODY'),
 
'name' => $GLOBALS['user']->name,
 
'op' => t('Save'),
);
?>

If you are creating a more complex node type, you'll want to include more information in in the $form_state['values'] array. I find it helpful to view the submitted node form data using the following code:

<?php
function MYMODULE_form_alter(&$form, $form_state, $form_id) {
 
// ensure we are modifying the right node type
 
if ($form_id == 'NODETYPE_node_form') {
   
// add an additional validation handler
   
$form['#validate'][] = '_MYMODULE_node_form_validate';
  }
}

function
_MYMODULE_node_form_validate($form, &$form_state) {
 
// display the submitted data and then die
 
echo "<pre>";
 
print_r($form_state['values']);
  echo
"</pre>";
  die;
}
?>

Now, if you create a test node (node/add/NODETYPE), you'll see the data that's being submitted from the form. NOTE: be sure to remove these two functions when you are familiar with the structure of the $form_state variable.

The 3rd argument will be a (mostly) empty $node object containing the node type:

<?php
$node
= new StdClass();
$node->type = 'NODETYPE';
?>

Here's a code snippet that shows all the pieces together:

<?php
// create $form_state
$form_state = array();
$form_state['values'] = array(
 
'title' => t('MYTITLE'),
 
'body' => t('MYBODY'),
 
'name' => $GLOBALS['user']->name,
 
'op' => t('Save'),
);

// create $node
$node = (object) NULL;
$node->type = 'NODETYPE';

// include node file, necessary for node generation
module_load_include('inc', 'node', 'node.pages');

// create node using drupal_execute
drupal_execute('NODETYPE_node_form', $form_state, $node);
?>

How to update the form using it

I need to update the node instead of adding new one. Is it possible in the drupal_execute()?

Updateing a node

I had imported about 1500 cck nodes using node_import. Because node_import did not run all the hooks on creating the nodes (some error checking may have prevented a critical hook from running). Opening and saving a node was effective at triggering the processing, but not feasible for 1500 nodes. Node_save did not do the job (same problem as node_import).

The following turned out to be effective. There were two challenges 1) to figure out what to put into module_load_include for a CCK field and 2) to get a $form_state to pass to drupal_execute. I tried to get the form pre-populated using drupal_get_form($form_id,$node) which did pre-populate the form, but returned the form rendered into html. I ended up adding a dvr($form_state) statement into one of the hooks and looking at the output. I was thinking that I might have to add all the fields into the function, but it seems that drupal_execute does not alter the fields that were not included in the $form_state.

I did add the $form_state['values']['op']='save' which seemed to be necessary to start the processing. An empty $form_state did not work. I don't know if $form_state['values']['type'] or $form_state['values']['form_id'] where needed but I saw them in the $form_state that was generated by node/nnn/edit and added them before I got the rest of the script working.

function ucount_process_imported_node($nid){
  //maybe this should be hooked to cron
  module_load_include('inc', 'node', 'node.pages');
  $node = node_load($nid);
  if (($node->type == "participant") ){
    $form_state = array();
    $form_state['values']['op'] = t('Save');
    $form_state['submitted'] = 1;
 
    $form_state['storage']= NULL;
    $form_state['values']['submit']=  'Save';
    $form_state['values']['form_id']=  'participant_node_form';
    $form_state['values']['type']= 'participant';
    $form_state['values']["field_ucount_barcode"][0]["upcfield_group"]["auto_value"]= "1";
    drupal_execute('participant_node_form', $form_state, $node);
    }
}

I ran this from the devel Execute PHP Code form, but I think next time I will try drush something like:
drush -r /var/www/testsite scr demo.php

Eric.London's picture

node_save

node_save is a great alternative to drupal_execute. In this tutorial, I wanted to show how to use drupal_execute. I find myself using node_save more these days...

-Eric

Thanks so much

I just keep coming back to this blog post again and again. Very informative. And since this post comes up so often while Googling, it makes it much easier to find!

sohbetim

thanks brother.nice sharing.thanks for admin.

How can I access the 'nid' of the node just created?

I have made a custom form to create the node, and I need to combine the 'nid' of the node that is created with drupal_execute() with a value from the submitted form to create a cross-reference. Since I don't have $form_state in scope during the insert op in hook_node_api(), I need to handle in my submit function.

Any reliable way to get the 'nid' of the node we just created with drupal_execute()?

Thank you.

Eric.London's picture

return value

Unfortunately, drupal_execute() will not supply what you are looking for, since the executed form has no standard return value. You could query the database using the submitted data from the custom form.

Is this a CCK node? Another approach would be to use the CCK node form and use hook_form_alter() to modify the form to your liking.

The nid of the newly created

The nid of the newly created node will exist in $form_state['nid'] after running drupal_execute

No useful return value?

You seem to know a lot about drupal_execute, and there is something I've been trying to figure out for a long time now, because I've been programatically creating nodes like this on a few different projects. How do i know if the node was created successfully? I know it returns any exceptions if they occur, but shouldn't it return something useful if the form was submitted without any problems? Like the newly created nid? This has really been driving me nuts.

drupal_execute versus node_save when creating new nodes?

Is there any benefit in using drupal_execute() over a simple node_save() when creating new nodes programmatically?

Thanks,
Bogdan.

Eric.London's picture

first thing that comes to mind

Hi Bogdan,

The first thing that comes to my mind is the validation handlers.

Regards,
Eric

Isn't node_submit() supposed

Isn't node_submit() supposed to perform validation? As in the code below:

$node = node_submit($node); // performs validation
if ($node->validated) {
node_save($node); //Actually save the node
}

Eric.London's picture

yes

Yes, thanks for pointing that out. A simple node_save() command will not suffice.

Eric.London's picture

More Info

Sorry everyone, I just realized I did not show where to put your CCK field data. This snippet shows how you could add some simple CCK field data to your node:

<?php
// create $form_state
$form_state = array();
$form_state['values'] = array(
   
'title' => t('MYTITLE'),
   
'body' => t('MYBODY'),
   
'name' => $GLOBALS['user']->name,
   
'op' => t('Save'),
);

// add CCK fields
$form_state['values']['field_MYFIELD1'][0]['value'] = "blah";
$form_state['values']['field_MYFIELD2'][0]['value'] = "wee";

// create $node
$node = (object) NULL;
$node->type = 'MYNODETYPE';

// include node file, necessary for node generation
module_load_include('inc', 'node', 'node.pages');

// create node using drupal_execute
drupal_execute('MYNODETYPE_node_form', $form_state, $node);
?>

Hope this helps!

Multiple values and select boxes

How would I go about adding a value to a select box that allows multiple values.

This does is for a simple select box with only one value permitted:

$form_state['values']['field_MYFIELD3']['value'] = KEY;

Node references

Eric,

Could you write a couple of words on how to add node references?

I tried

<?php
$form_state
['values']['field_YOURFIELD'][0]['nid'] = YOURNID;
?>

but it didn't work...

We're you able to get Node Reference to work?

I've got the same problem. I don't know how to reference the nodereference widget.

subscribe

First of all THANK YOU for the article. I saved a lot of time!
I need to add some node_references as well.
How can I do?
Thanks in advance.
Max

Error when running drupal_execute

I've been searching for days on a solution for an error I'm getting when running drupal_execute on D6. I followed your code example verbatim (with the exception of changing the node names, user, etc) and keep getting a:

"Fatal error: Unsupported operand types in ".../form.inc on line 511"

Have you encountered this? I've asked in other forums, IRC, etc. to no avail.

I got this error when I used the above code with a webform

Fatal error: Cannot unset string offsets in /var/www/hkcec/sites/all/modules/cck/includes/content.node_form.inc on line 71

Any suggestions will be appreciated.

Thanks!

I believe I figured out the

I believe I figured out the problem, though I'm having issues formulating the solution.

I was trying to save a CCK field as a string. In fact it appears that the field needs to be formed as an array.

Pulling a node gives me this:

[field_headline] => Array
        (
            [0] => Array
                (
                    [value] => My test string
                )

        )

Attempting to submit the post as an array eliminates the error on line 71.

Having said that, I'm having trouble forming the array and object in order for it to work. In my case using services I need to post as a JSON string. I'm sure I'll get it, in any case –– this should help the previous poster move forward on his / her problem.

I'm getting the same error

I'm getting the same error when using services node.save.

Fatal error: Cannot unset string offsets in /var/www/vhosts/mysite.com/modules/cck/includes/content.node_form.inc on line 71

It appears to be a CCK issue. Any insight or resolution in your issue?

Eric.London's picture

hmm

Post your code and I'll be happy to take a peak.

HI,Eric. Can you tell me how

HI,Eric.
Can you tell me how can I do in drupal 7 ?
and field UI. not cck

Thanks.

how to populate form field after submit event

I need to populate the form fields programmatically in drupal. I understand that there are 2 approaches:

using drupal_execute($form_item,value,$form_state) // please note i am not using nodes for this example, so the node approach will not work

using form_set_value($form_id,$form_state)

Any working examples would be helpful

I tried the following code which gives the drupal white screen of death

<?php
function form_validate($form, &$form_state){
$form_id ='myform';
$form_state['values'] = array( 'name' => 'Test',
);
drupal_execute($form_id, $form_state); // this statement leads to white screen of death }
?>