Hello,

I made a module with two node types. One type is the parent type and the other is the children type. When creating a children type you have to choose the parent onde. The normal procedure is to use the hook_form to create a custom node form. And add a selection to let the user choose the right parent when creating a child node. Buy I don't like this method as there can be many parent nodes and choosing the right one is anoying. You have to remember the correct title of the desired parent. I fond it much easyer to create a hook_menu for the parent type node and add a "Add child" MENU_LOCAL_TASK, then get the children type form with drupal_get_form, and prefill the values with the current node id. This way the users just have to browse the parents nodes and click where the want to add child.
The problem with my implementation is that I cannot get the node form from the hook_menu of my module. The node forms require to include the node.pages.inc. I cannot define 'file' -> 'node.pages.inc' in my menu as drupal search in the module directory and not in others modules directories. An another solution would be to create custom forms with hook_forms and call these forms. But these forms would not heritate the node forms properties, and would require to copy many parts of the node form system.

So is there a better way to implement this prefilled node creation form ?

Help would be greatly appreciated,
Thanks.

Comments

terriea’s picture

Here is a piece of code that reproduce my problem :

function test_node_info() {
  return array(
    'testtype' => array(
      'name' => t('Test Type'),
      'module' => 'test',
      'description' => t('Test type from test module'),
      'has_title' => TRUE,
      'title_label' => t('Test title'),
      'has_body' => TRUE,
      'body_label' => t('Test body'),
    ),
  );
}

function test_form(&$node, &$param) {
  $type = node_get_types('type', $node);

  if ($type->has_title) {
    $form['title'] = array(
      '#type' => 'textfield',
      '#title' => check_plain($type->title_label),
      '#required' => TRUE,
      '#default_value' => $node->title,
      '#weight' => -5,
    );
  }

  if ($type->has_body) {
    $form['body_field'] = node_body_field($node, $type->body_label, $type->min\
_word_count);
  }

  $form['parentnid'] = array(
    '#type' => 'textfield',
    '#title' => t('Parent Node Id'),
  );
  return $form;
}

function test_menu() {
  $items['node/%node/child'] = array(
    'title' => t('Add children'),
    'page callback' => 'get_n_prefill_form',
    'page arguments' => array(1),
    'access callback' => 'node_access',
    'access arguments' => array('create', 'testtype'),
    'type' => MENU_LOCAL_TASK,
  );
  return $items;
}

function get_n_prefill_form($nodeid) {
  $form = drupal_get_form('testtype_node_form');
  $form['parentnid'] = array(
    '#type' => 'textfield',
    '#title' => t('Parent Node Id'),
    '#default' => $nodeid,
  );
  return $form;
}

and the error I get :

warning: call_user_func_array() [function.call-user-func-array]: First argument is expected to be a valid callback, 'node_form' was given in /Users/antoine/usr/Library/WebServer/Documents/includes/form.inc on line 359.
terriea’s picture

This second type of get_n_prefill_form function is a partial copy of node_add function and make a direct call to test_form function to avoid the drupal_get_form problem.

function get_n_prefill_form($nodeid) {
  global $user;

  $node = array('uid' => $user->uid, 'name' => (isset($user->name) ? $user->na\
me : ''), 'type' => 'testtype', 'language' => '');

  drupal_set_title(t('Create @name', array('@name' => $types[$type]->name)));
  $form = test_form($node);
  var_dump($form);

  return $form;
}

This provoques a similar error :

Fatal error: Call to undefined function node_body_field() in /Users/antoine/usr/Library/WebServer/Documents/sites/drawnstuff.com/modules/test/test.module on line 31

Of course we always get the same problem. We need a function that is in node.pages.inc that is not reachable. So how can I do the thig working ? Drupal should be able to do this simple process. Were I did wrong ?
Help !

terriea’s picture

The answer was : "use 'file path' => drupal_get_path('module', 'node')" :


function test_form(&$node, &$param) {
  $type = node_get_types('type', $node);

  if ($type->has_title) {
    $form['title'] = array(
      '#type' => 'textfield',
      '#title' => check_plain($type->title_label),
      '#required' => TRUE,
      '#default_value' => $node->title,
      '#weight' => -5,
    );
  }

  if ($type->has_body) {
    $form['body_field'] = node_body_field($node, $type->body_label, $type->min_word_count);
  }

  $form['parentnid'] = array(
    '#type' => 'textfield',
    '#title' => t('Parent Node Id'),
    '#default_value' => $node->parentnid,
  );
  return $form;
}

function test_menu() {
  $items['node/%node/child'] = array(
    'title' => t('Add children'),
    'page callback' => 'get_n_prefill_form',
    'page arguments' => array(1),
    'access callback' => 'node_access',
    'access arguments' => array('create', 'testtype'),
    'type' => MENU_LOCAL_TASK,
    'file' => 'node.pages.inc',
    'file path' => drupal_get_path('module', 'node'),
  );
  return $items;
}

function get_n_prefill_form($node) {
  global $user;

  $node = array('uid' => $user->uid, 'name' => (isset($user->name) ? $user->name : ''), 'type' => 'testtype', 'language' => '', 'parentnid' => $node->nid);

  drupal_set_title(t('Create Testtype'));
  $form = drupal_get_form('testtype_node_form', $node);

  return $form;
}