views:

73

answers:

3

I try to programmatically create a node of custom contenttype "location" in Drupal 6, with the node containing a location field (http://drupal.org/project/location) called "location" (yes I know, the nomenclature could be better, but I am just experimenting on this at the moment).

Creating the node works just fine, but I cannot find a way to set the contents for the location field - i.e. the node is created with all content but the value for then location field.

I try creating the node like this:

        $newNode = (object) NULL;
        $newNode->type = 'location';
        $newNode->title = $locationName;
        $newNode->uid = $userId;
        $newNode->created = strtotime("now");
        $newNode->changed = strtotime("now");
        $newNode->status = 1;
        $newNode->comment = 0;
        $newNode->promote = 0;
        $newNode->moderate = 0;
        $newNode->sticky = 0;

        $newNode->field_location[0]['street'] = 'Teststraße';
        $newNode->field_location[0]['postal_code'] = '12345'; 
        $newNode->field_location[0]['city'] = 'Musterstadt'; 

        node_save($newNode);

The node gets created with the correct title, but the location fields remain unset.

How can I programmatically set the location-related fields?

Thanks in advance!

+1  A: 

I have done this, only not with a CCK field but the default location option you can add to nodes.

What I did to make it work, was to first save the location (there's an API function for it) and then add the location id from the saved location.

Sample code:

Note, $center is from an external source, so it's not Drupal related. I know all my locations are from Denmark in my example, so that part is just hardcoded.

When you don't use a CCK field, you don't need to save the location data on the node, instead you can just save the location and pair the location yourself. It's a quick solution, instead of running through the node form like suggested. For complex nodes, that might be the better choice, but when it's simple, this is done faster.

// Update the location data.
$location = is_array($node->location) ? $node->location : array();
$location += array(
  'street' => $center->address->address2,
  'city' => $center->address->zipName,
  'postal_code' => $center->address->zip,
  'country' => 'dk',
  'country_name' => 'Denmark',
);
location_save($location);

// Insert location instance, if it's not set yet.
$criteria = array(
  ':nid' => $node->nid,
  ':vid' => $node->vid,
  ':lid' => $location['lid'],
);
if (!db_result(db_query("SELECT COUNT(*) FROM {location_instance} WHERE nid = %d AND vid = %d AND lid = %d;", $criteria))) {
  db_query("INSERT INTO {location_instance} (nid, vid, lid) VALUES (%d, %d, %d)", $criteria);
}
googletorp
Sounds like a possibilty - I have to investigate whether this would be suitable for the site I am building. Do you by chance have any sample code for the location-creation and the location id adding? Thanks! :)
Grimtron
Thanks for the guidance, I have added a code sample myself... seems like using the comments for this is rather difficult.
Grimtron
+2  A: 

Instead of node_save, many people recommend using drupal_execute to programmatically submit the node edit form. This gives you the benefit of form validation.

See http://thedrupalblog.com/programmatically-create-any-node-type-using-drupal-execute for an excellent example of using drupal_execute. Don't forget to look at the comment http://thedrupalblog.com/programmatically-create-any-node-type-using-drupal-execute#comment-70 to see some additional info on CCK fields.

The advantage of drupal_execute is that you get form validation also. So after the drupal_executestatement you can see if there were any errors using form_get_errors ( http://api.drupal.org/api/function/form_get_errors/6 ). See snippet (pasted below) from http://civicactions.com/blog/cck_import_and_update for an example of using form_get_errors

$node->type = 'yourtype';
$values = array();
$values[...] = ...;
drupal_execute('yourtype_node_form', $values, $node);
$errors = form_get_errors();
if (count($errors)) {
  // do something ...
}

Another very nice resource on programmatic submission of nodes using drupal_execute can be found at http://drupal.org/node/293663

Sid NoParrots
This is good advice but I would rather decouple the form API from node validation. You can use the validate operation in the node API with the same effect. Sadly, this not always implemented so your method is probably best. :)
Rimian
A: 

Wanted to add this as a comment, but it seems like putting code into the comment is rather problematic. So here we go: I changed the internas so that I do not use a cck field anymore, but use the default location option as suggested by googletorp.

The actual code to create a new location and assign this to a new node looks like this:

$location['street'] = "myStreet";
$location['postal_code'] = "12345";
...

$newLocationId = location_save($location);

$newNode = ...
$newNode->locations[0]['lid'] = $newLocationId;

node_save($newNode);

Thanks for the guidance :)

Grimtron