Hey,

I am writing a module that takes some content from a parent node, manipulates it, then adds the manipulated content to child nodes.

There is a lot of documentation/tutorials on how to create a node/modify a node/add stuff to cck/etc... with a script... but didnt really see any thing for this module.

How would I go about setting the parent of a node from a script?

Normal nodes are something like this:

<?php
// Construct the new node object.
$node = new stdClass();

// Your script will probably pull this information from a database.
$node->title = "My imported node";
$node->body = "The body of my imported node.\n\nAdditional Information";
$node->type = 'story';   // Your specified content type
$node->created = time();

CCK something like this:

<?php
$node->field_text_field[0]['value'] = "value 1";
$node->field_text_field[1]['value'] = "2nd value";
$node->field_nodereference[0]['nid'] = 58;
?>

(on a side note... If anyone is interested, I got this code from here: http://acquia.com/blog/migrating-drupal-way-part-i-creating-node ).

How would I do this w/ node hierarchy?

Comments

that0n3guy’s picture

Soooo yeah, I just guessed and gave it a shot... and it worked :)

I decided to go w/ drupal_execute from this guide: http://thedrupalblog.com/programmatically-create-any-node-type-using-dru...

Here is what I came up with:

// create $form_state
$form_state = array();
$form_state['values'] = array(
    'title' => t('MyTitle ') .$i, // 'i' is just a counter, I have this in a loop.
    'body' => spin($string, false),
    'name' => $myuid, //this var is the user ID pulled from a database
    'parent' => $mynid,  //var is also pulled from a database, its the node id of the parent I want.
    'op' => t('Save'),
);

/* add CCK fields -- used later for 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 = 'article';

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

// create node using drupal_execute
drupal_execute('article_node_form', $form_state, $node);

The 'parent' is what I used and set it as the nid.

Hope this helps someone :).

andreiashu’s picture

Hi,

Just in case there is someone else that is using the 2.x branch (which is a lot better) here is what I came up with to create a new child when a node (of a certain type) is created.
If you know a better way of doing this please post a reply here.

/**
 * hook_nodeapi
 */
function myModule_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  if($op == 'insert' && $node->type == REPLACE_THIS_WITH_YOUR_NODE_TYPE) {
    global $user;

    $nid = @$node->nid;

    $plid = _nodehierarchy_get_node_mlid($nid);
    $nodehierarchy_menu_links = _nodehierarchy_default_menu_link($nid, $plid);
    $nodehierarchy_menu_links['hidden'] = FALSE;

    $nodehierarchy_old_menu_links = $nodehierarchy_menu_links;
    $nodehierarchy_old_menu_links['enabled'] = TRUE;
    unset($nodehierarchy_old_menu_links['hidden']);
    unset($nodehierarchy_old_menu_links['link_path']);
    $nodehierarchy_old_menu_links['link_title'] = '';
    $nodehierarchy_old_menu_links['expanded'] = '';
    $nodehierarchy_old_menu_links['description'] = '';
    $nodehierarchy_old_menu_links['customized'] = '';

    // This is the child node
    $std_node = new stdClass();
    $std_node->title = 'The node\'s title';
    $std_node->type = 'page';
    $std_node->uid = $user->uid;
    $std_node->nodehierarchy_menu_links[] = $nodehierarchy_menu_links;
    $std_node->nodehierarchy_old_menu_links[] = $nodehierarchy_old_menu_links;
    node_save($std_node);
  }
}
that0n3guy’s picture

The way I'm using this (w/ NH 1.2), I have a parent, which is created by users, and then they push a button (on a different page) and there parent is analysed and 100's of children are spit out.

Since I am also using batch api, I have to pass $nid (the parent nid) from previous functions.

function add_new_node($title, $myusername, $nid, $body, $descr, $refbox) {

/**
* Saving current user, then loading user w/ permissions to change author and pick parent nodes
* I have to do this because normal users don't have the permissions to set the author of a node.
* I want the children author to be the same as the parents author, even if someone else generates the children.
*
*/
global $user;
//save current user name
$current_user = $user -> name;
//load user with permissions to do everything on here
$user = user_load(array('name' => 'spincreator_donttouch'));
  $node = new StdClass();
  $node->type = 'auto_spun_article';
  $node->status = 1;
  $node->promote = 0;
  $node->format = 1;
  $node->title = $title;
  $node->name = $myusername; //used a username pulled from a query of the parent
 
// This is where I set the parent node id for the child... that simple
 $node->parent = $nid;
  $node->field_spun_ref_box[0]['value'] = $refbox;
  $node->field_spun_desc[0]['value'] = $descr;
  $node->field_spun_article_body[0]['value'] = $body;
  $node = node_submit($node);
  if ($node->validated) {
    node_save($node);
  }
  //load old user back in
  $user = user_load(array('name' => $current_user));
}	

I stopped using drupal_execute because a) it sometimes hates on cck fields b) its kinda funky with batch api... (plus I noticed it doesnt have a D7 section in the api http://api.drupal.org/api/function/drupal_execute/6 ... )

I didnt even look at the 2.x version yet.... I didn't realize it was changed so much. Hmmm.... maybe I should look at it instead.

andreiashu’s picture

I didnt even look at the 2.x version yet.... I didn't realize it was changed so much. Hmmm.... maybe I should look at it instead.

Before starting playing with it have a look at this patch first:#623300: SQL errors in the latest 2.x dev from 2009-Nov-01

Cheers

dhope’s picture

Version: 6.x-1.2 » 6.x-1.3

Hi all,

I'm also attempting to create child nodes but it doesn't want to work. Here's the code snippet:

/////////// save sub node

	$node = new stdClass();

	$node->type = 'allgemein';  
	$node->title = $src_title . ' - Allgemein';
    	$node->field_citydesk[0]['value'] = $maintext;

	$node->parent  = $mainnid;

	$node->created = time();
	$node->changed = $node->created;
	$node->status = 1;
	$node->promote = 1;
	$node->sticky = 0;
	$node->format = 1;       // Filtered HTML
	$node->uid = 1;          // UID of content owner

	node_submit($node);
	if ($node->validated) {
		node_save($node);
		}

The node gets created correctly except no parent is assigned.
Manually assigning the parent works fine.
$node->parent is set correctly prior to the call to node_save but turns up empty afterwards.

Guess I could work around it by writing to nodehierarchy directly but then I'd run into problems with URL alias which is supposed to assign an alias based on the parent name.

Tearing my hair out already here. Any views why this may not work?

EDIT: never mind, it needed the user_load piece.

spacegoat1701’s picture

I'm using the latest 2.x dev, and I have tried andreiashu's pattern, but I can't get it to work.

Specifically, here's my code ($par_nid is a node ID loaded from the database):


$plid = _nodehierarchy_get_node_mlid($par_nid);
$nodehierarchy_menu_links = _nodehierarchy_default_menu_link($par_nid, $plid);
$nodehierarchy_menu_links['hidden'] = FALSE;
$nodehierarchy_old_menu_links = $nodehierarchy_menu_links;
$nodehierarchy_old_menu_links['enabled'] = TRUE;
unset($nodehierarchy_old_menu_links['hidden']);
unset($nodehierarchy_old_menu_links['link_path']);
$nodehierarchy_old_menu_links['link_title'] = '';
$nodehierarchy_old_menu_links['expanded'] = '';
$nodehierarchy_old_menu_links['description'] = '';
$nodehierarchy_old_menu_links['customized'] = '';

$node->nodehierarchy_menu_links[] = $nodehierarchy_menu_links;
$node->nodehierarchy_old_menu_links[] = $nodehierarchy_old_menu_links;

zeezhao’s picture

Hi. Please has anyone been able to do this with latest 2.x? I could not get it to work too.

I tried both methods i.e #2 and #3

The breadcrumb is set though in the child. But the child is not linked to parent node, and hence does not show up under parent. Looks like there is still one more setting to do...

edit: Also was running it as admin, so permissions should be fine...

also tried:

....
	$node->nodehierarchy_menu_links[0]['pnid'] = $pid;
	$node->parent = $pid;

    	node_save($node);

where $pid is nid of parent. Created breadcrumbs ok, but parent still not set....

dca123’s picture

@zeezhao

Can you post the code you have working? I'm having the same problem as well using #2 except the breadcrumb doesn't even appear...

dca123’s picture

as well, @zeezhao

Can you confirm that the children don't exist by going to the parent node and clicking on the 'Children' tab? I've had it happen where no default view has been set to view the children on the same node display as the parent.

dca123’s picture

Version: 6.x-1.3 » 6.x-2.x-dev
Component: Documentation » Miscellaneous

I finally got this working on 2.x

Code below is based off of andreiashu's. Is tested and works...

<?php

//$nid is the parent nid from wherever you get it

global $user; //assuming you're logged in with the right permissions

$plid = _nodehierarchy_get_node_mlid($nid,true); //    <-------- Important don't forget the 'true'.

$node = new stdClass();
$node->type = 'subnodetype';
$node->title = 'title';
$node->created = time();
$node->changed = $node->created;
$node->status = 1;
$node->promote = 0;
$node->sticky = 0;
$node->format = 1;       // Filtered HTML
$node->name = $user->name;     // <----- use $user->name otherwise you get 'Anonymous'
$node->language='en';
node_submit($node);
node_save($node); // <--- Save the node now

$nodehierarchy_menu_links = _nodehierarchy_default_menu_link($nid, $plid);
$nodehierarchy_menu_links['pnid']=$nid;   // <----- Give the menu link the parent id
$nodehierarchy_menu_links['hidden'] = FALSE;
$nodehierarchy_menu_links['enabled'] = TRUE; //  <------ Make sure the menu link is enabled 
  
//Is $nodehierarchy_old_menu_links necessary? Doesn't look like it...but keep it just for kicks 
$nodehierarchy_old_menu_links = $nodehierarchy_menu_links;
$nodehierarchy_old_menu_links['enabled'] = TRUE;
unset($nodehierarchy_old_menu_links['hidden']);
unset($nodehierarchy_old_menu_links['link_path']);
$nodehierarchy_old_menu_links['link_title'] = '';
$nodehierarchy_old_menu_links['expanded'] = '';
$nodehierarchy_old_menu_links['description'] = '';
$nodehierarchy_old_menu_links['customized'] = '';

$node->nodehierarchy_menu_links[] = $nodehierarchy_menu_links;
$node->nodehierarchy_old_menu_links[] = $nodehierarchy_old_menu_links;

_nodehierarchy_save_node($node); // <---- Let nodeheirarchy do it's thing

?>
zeezhao’s picture

Thanks for this! Will try it out.

I looked into what I was doing last night and these are the additional issues...:

1. The way I did it before actually created the children under the new parent, and was visible from the "Children" tab. but not showing up in the view. So had to do:
$node->nh_children_view_display = 'default';

2. Now after doing that, because the new parent was cloned in code, for some reason its view was pointing to view of node from which it was cloned, but still had correct children under its "Children" tab! So some settings were not right on the clone.

Hope you stuff clears it up for me. Thanks.

rvarkonyi’s picture

Version: 6.x-2.x-dev » 6.x-1.3
Component: Miscellaneous » Documentation

Make sure you add this:


$std_node->nodehierarchy_menu_links[0]['plid'] = $plid;
$std_node->nodehierarchy_menu_links[0]['pnid'] = $nid;

Should work.

zeezhao’s picture

Thanks for all your help and comments. Got it to work eventually... As I was also cloning existing nodes, had to add some extra steps:
For cloned child:

.....
        //to ensure stuff from clone not carried forward
	$node->nodehierarchy_menu_links = NULL; 
	$node->nodehierarchy_old_menu_links = NULL;

	$plid = _nodehierarchy_get_node_mlid($pid, TRUE);
	node_submit($node);
	node_save($node);

	$nodehierarchy_menu_links = _nodehierarchy_default_menu_link($pid, $plid);
	$nodehierarchy_menu_links['pnid']= $pid;
	$nodehierarchy_menu_links['hidden'] = FALSE;
	$nodehierarchy_menu_links['enabled'] = TRUE;
 	$nodehierarchy_old_menu_links = $nodehierarchy_menu_links;
	$nodehierarchy_old_menu_links['enabled'] = TRUE;
	unset($nodehierarchy_old_menu_links['hidden']);
	unset($nodehierarchy_old_menu_links['link_path']);
	$nodehierarchy_old_menu_links['link_title'] = '';
	$nodehierarchy_old_menu_links['expanded'] = '';
	$nodehierarchy_old_menu_links['description'] = '';
	$nodehierarchy_old_menu_links['customized'] = '';
	$node->nodehierarchy_menu_links[] = $nodehierarchy_menu_links;
	$node->nodehierarchy_old_menu_links[] = $nodehierarchy_old_menu_links;
	_nodehierarchy_save_node($node);	

For cloned parent, since it was also cloned from another parent node, and was not going to have any parent itself, I had to do:

.....
	$node->nodehierarchy_menu_links = array();
	$node->nodehierarchy_menu_links[0]['pnid'] = 0;
	$node->nodehierarchy_menu_links[0]['plid'] = 0;
	$node->nodehierarchy_menu_links[0]['mlid'] = 0;
	$node->nodehierarchy_menu_links[0]['enabled'] = TRUE;
        node_save($node);
	_nodehierarchy_save_node($node);	
.........
achton’s picture

Version: 6.x-1.3 » 6.x-2.x-dev
skaught’s picture

i can't say it enough
thankyou thankyou thankyou
i've spent alot of time trying to make this happen!! cheers.

dreamingX’s picture

#13 works in D7 too!

Thank you! this saved me hours...

jbylsma’s picture

Title: Programmically assign parent when creating a node from script in D6 » Programmically assign parent when creating a node from script
Status: Active » Fixed

Made the title more ambiguous to hopefully steer future searchers.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

chichilatte’s picture

Sorry to reopen the issue, but it might be useful to point out that (in D6.2, NH 6.21 at least) if you do the node hierarchy changes after node_save(), the path alias doesn't take into account the hierarchy. Based on comment#10, just putting the nodehierarchy_menu_links array into the $node before saving worked perfectly for me...

	// Create your node as mentioned above
	$node = new stdClass();
	// ...etc.

	// Then, with your $parent_nid...
	$plid = _nodehierarchy_get_node_mlid($parent_nid,true);
	$nodehierarchy_menu_links = _nodehierarchy_default_menu_link($parent_nid, $plid);
	$nodehierarchy_menu_links['pnid']=$parent_nid;
	$nodehierarchy_menu_links['hidden'] = FALSE;
	$nodehierarchy_menu_links['enabled'] = TRUE;
	$node->nodehierarchy_menu_links[] = $nodehierarchy_menu_links;

	if ($node = node_submit($node)) {
		node_save($node);
		// Note: _nodehierarchy_save_node($node) doesn't seem to be required.
	}
ksemihin’s picture

PDOException: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'link_title' cannot be null: INSERT INTO {menu_links}

What is wrong ???

 // Get the menu link id of the parent
        $plid = _nodehierarchy_get_node_mlid($parent_nid, TRUE);

        $nodehierarchy_menu_links = _nodehierarchy_default_menu_link($node->nid, $plid);
        $nodehierarchy_menu_links['pnid']= $parent_nid;
        $nodehierarchy_menu_links['hidden'] = FALSE;
        $nodehierarchy_menu_links['enabled'] = TRUE;
        $nodehierarchy_menu_links['link_title'] = $node->title;

        $node->nodehierarchy_menu_links[] = $nodehierarchy_menu_links;
        _nodehierarchy_save_node($node);
emanaton’s picture

For anyone stumbling on this and hoping against hope that someone bothered to put in the D7 solution, today is your lucky day!

    // Save $node if it's not not already in order to populate the $node->nid property
    $node->nodehierarchy_old_menu_links = NULL;
    $nodehierarchy_menu_links = _nodehierarchy_default_menu_link($node->nid);
    $nodehierarchy_menu_links['pnid'] = $parent_nid;
    $node->nodehierarchy_menu_links = [$nodehierarchy_menu_links];
    // Save the $node object.