Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
By Dave Cohen on
I'm trying to create book nodes using drupal_execute (I'm importing a bunch of nodes from content stored in files). I've been trying everything I can think of to make this work and I'm really frustrated. I can create the nodes, but I can't make one page a child of another page. Instead nodes which should be parent-child are siblings under the top-level book node.
Here's a chunk of the code I'm using:
// values like $plid (nid of the parent page) and $bid (nid of the top-level book) have been set earlier in the code.
// Create a node based on the parsed content
$form_state = array();
module_load_include('inc', 'node', 'node.pages');
$node = array('type' => 'book');
$form_state['values']['title'] = $title;
$form_state['values']['body'] = $body;
$form_state['values']['name'] = 'superadmin';
$form_state['values']['op'] = t('Save');
$form_state['values']['book'] =
array('bid' => $bid,
'plid' => $plid,
'weight' => $weight,
);
drupal_execute('book_node_form', $form_state, (object)$node);
I saw a somewhat related post: http://drupal.org/node/252341, but the advice there did not help. I've tried the following code and it also does not work.
// Create a node based on the parsed content
$form_state = array();
module_load_include('inc', 'node', 'node.pages');
$node = array('type' => 'book');
$form_state['values']['title'] = $title;
$form_state['values']['body'] = $body;
$form_state['values']['name'] = 'superadmin';
$form_state['values']['op'] = t('Save');
$form_state['values']['book'] =
array('bid' => array('value' => $bid),
'plid' => array('value' => $plid),
'weight' => array('value' => $weight),
'module' => array('value' => 'book'),
);
drupal_execute('book_node_form', $form_state, (object)$node);
Comments
Skeleton
Funny. I was just looking through the (D5) code of Skeleton module, which deviantintegral is about to take over.
There is some code in http://drupal.org/project/skeleton which should be similar in D6 (if not identical).
See especially function skeleton_create_instance_form_submit(), which would actually be cleaner in D6, since you can use db_last_insert_id() to find the parent nid.
I ended up writing the data straight to the {book} table, since it was easier.
--
http://ken.therickards.com
turns out...
Turns out the book module creates a form in which plid is a value, not a select. So it can't be passed into drupal_execute. On a web page, that part of the form gets changed by ajax. (so without javascript, node/add/book will not work as expected. Bad form!)
My solution is to set some values in the $form_state passed to drupal_execute, and other values I keep a global variable. Then during my module's hook_form_alter I set the plid. (Which it turns out is not the nid of the parent, but the menu link id, ie $parent_node->book['mlid']). This is tricky, and a pain in the butt, but the best workaround I could come up with.
Trying to do the same thing
In your hook_form_alter, what form #type is plid?
TIA,
Karim
Bug filed?
Also, do you think this issue is worth filing a bug for?
Another solution
I followed your advice to use hook_form_alter, but in that function, I avoided using global variables:
That's a good idea, to grab
That's a good idea, to grab the data from #post rather than a global. Glad you got it working.
As for whether its a bug, I'm not sure. In Drupal its bad form to require javascript. Instead the form element could be a select of all possible plids, then javascript, if present, could narrow down the possibilities. However, there may have been a reason to do it this way, for example a site with thousands of book nodes might make that select element way too big. So I don't plan to submit an issue.
How do you implement this
Do you have to create a module to perform the imports?
Would it be possible to use drush to import a set of nodes?