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

agentrickard’s picture

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

Dave Cohen’s picture

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.

infojunkie’s picture

In your hook_form_alter, what form #type is plid?

TIA,
Karim

infojunkie’s picture

Also, do you think this issue is worth filing a bug for?

infojunkie’s picture

I followed your advice to use hook_form_alter, but in that function, I avoided using global variables:

function mymodule_form_alter(&$form, $form_state, $form_id) {
  if ($form_id == 'mymodule_node_form') {
    if ($form['#post']['book']) {
      $form['book']['bid'] = array(
        '#type' => 'hidden',
        '#value' => $form['#post']['book']['bid'],
      );
      $form['book']['plid'] = array(
        '#type' => 'hidden',
        '#value' => $form['#post']['book']['plid'],
      );
    }
  }
}
Dave Cohen’s picture

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.

illmnec’s picture

Do you have to create a module to perform the imports?
Would it be possible to use drush to import a set of nodes?