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?