listen > understand > code > teach

Programmatically Creating Instances of CCK Types - Drupal 6

During the design phase of Composers' Village I devised a database schema for the musical data consisting of three CCK types: Villager, Tune, and Project. The reason for the Villager type was to contain a user's musical information, e.g., what Tunes they had contributed in a way that could persist after that user's account had been deleted. I basically wanted the database to stay consistent and well-linked even after a contributing user left and their account was deleted.

The difficulty of this design was that in early implementations the first thing a user had to do after setting up their account information was go to Create content and make a VIllager to represent themselves musically. It would hold a text blurb which was their musical bio but was mostly an empty container for information about any future musical contributions to Composers' Village. This was a usability problem because it was a real nuisance to have to go through this extra step when joining Composers' Village.

So I realized that the Villager for a user had to be created automatically for them when the account was made. In the Getting started page I could explain how to fill out the musical bio after creating account but having to teach the new user how to create an instance of Villager, as well, was definitely too much.

How to create an instance of a CCK type programmatically? What I did was implement hook_user() in the composers_village module. In my composers_village.module I added the following code:

function composers_village_user($op, &$edit, &$account, $category = NULL) {
  global $user;
 
  if ($op=='insert' && $account->uid) {  
    // a new user is being added, create a villager for them
    $node = new stdClass();
    // leaving the $nid out will tell node_save() it is a new node
    $node->type = 'villager';
    $node->language = '';
    $node->uid = $account->uid;
    $node->status = '1';
    $node->created = time();
    $node->changed = $node->created;
    $node->comment = '0';
    $node->promote = '1';
    $node->moderate = '0';
    $node->sticky = '0';
    $node->tnid = '0';
    $node->translate = '0';
    $node->revision_uid = $node->uid;
    $node->title = $account->name;
    $node->body = '';
    $node->teaser = '';
    $node->log = '';
    $node->revision_timestamp = $node->created;
    $node->format = '';
    $node->picture = '';
    $node->field_a4 = array();
    $node->field_c1 = array(array('value'=>null,'format'=>null));
    $node->field_a5 = array(array('nid'=>null));
    $node->field_a8 = array(array('nid'=>null));
    $node->field_a7 = array(array('nid'=>null));
    $node->field_c2 = array(array('url' => null,'title'=>null));
    $node->last_comment_timestamp = $node->created;
    $node->last_comment_name = null;
    $node->comment_count = '0';
    $node->taxonomy = array();
    node_save($node);
  }
}

My friend Barry Jaspan recommended this approach and tells me it does not work for all field types in Drupal 6 CCK. But, since I basically create an empty Villager, it works perfectly -- saving a step for new users of Composers' Village. Using CCK's ability to set permission by user role, I turned off the ability to create a VIllager for normal users of the site. Thus user of the site need not be concerned about the Village-type and there is always exactly one Villager submitted by a certain user (programmatically).

What I did to figure out what I structure I needed to create was to put in a temporary line of code like $test_node = node_load(193); (where 193 is the node-id of a some pre-existing Villager node) and a breakpoint just after this line. When I hit the breakpoint I looked at the structure of $test_node. Then all I had to do was recreate that structure in my new node and then do a node_save() on it. Voila!

Comments

cnc

I’m not big on commenting, but nice post. I always found good quality information from this site! I will keep visiting this blog very often.

Drupal SEO