Creating nodes programmatically that have CCK image fields in Drupal 6
Posted on: Sunday, October 18th 2009 by Afraaz Ali

When creating nodes programmatically it's easy enough to give the node a
title, body, and type by using the following:


$node = new stdClass();
$node->title = 'title';
$node->body = 'body text';
$node->type = 'type';

These are simple properties that ALL nodes will have. What about nodes with CCK fields attached to them? Well for text fields we can simply use the following:


$node = new stdClass();
$node->title = 'title';
$node->body = 'body text';
$node->type = 'type';
$node->$field_name[0]['value'] = 'TEXT'

Where $field_name can take place of the internal CCK field name (field_XXX_XXX)

That covers the text fields but what about images? Here's a little background on the situation that was put infront of me. I had images on a different server which I needed to attach to an image field on one of our content types. So I used a combination of cURL and a CCK function in order to attach the images to the nodes.

First we'll start with the function that uses cURL in order to save the images to our server.


/**
* Allows us to save images from the phonedog webservice
*
* @param $img - The path of the image file
* @param $fullpath - The path to where the image will be saved
*
* @return none
*/
function modulename_save_image($img, $fullpath){
  $ch = curl_init($img);
  curl_setopt($ch, CURLOPT_HEADER, 0);
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
   curl_setopt($ch, CURLOPT_BINARYTRANSFER,1);
   $rawdata = curl_exec($ch);
   curl_close ($ch);
   if(file_exists($fullpath)){
     unlink($fullpath);
   }
   $fp = fopen($fullpath, 'x');
   fwrite($fp, $rawdata);
   fclose($fp);
}

This function will take a URL to the image and will save the image in a directory of your choosing. When I used this function I decided to use the temp directory of the Drupal instance. IE:


variable_get('file_directory_temp', '/tmp');

Thhis function will save all your images in your temp directory. Now that you have all your images in the tmp directory you can begin to save the node.

I used the following to save images to nodes:


$node = new stdClass();
$node->title = 'title';
$node->body = 'body text';
$node->type = 'type';
$filepaths = array('/tmp/foo.jpg', '/tmp/bar.jpg');
foreach ($filepaths as $filepath) {
  $field = field_file_save_file($filepath, array(), file_directory_path() .'/'. $directory);
  $node->$field_name[] = $field;
}
$node = node_submit($node);
node_save($node);

In the above code the $directory variable can be a sub folder for your images just so you can keep them organized. The $field_name variable is again the internal CCK field name (field_XXX_XXX). This method will support fields that allow for multiple images as well. The $filepaths variable in the above example is hard coded, of course you can create a function that will return an array of image paths.

Well that's how one would go about saving images to nodes programmatically. Please
feel free to let me know if there's a better way of doing the same thing.

The interweb my ~ away from ~

Comments

I find drupal_http_request() to be a much better choice than CURL. It's much easier to use and there's no dependency on a PHP module that may or may not be there.

Thanks for this useful article.
Can you, please explain a bit:
$node = node_submit($node);

Cool thank you. I'll look into using drupal_http_request.

The node_submit call just prepares the node object for the node_save call. Using the node object it returns, you can pass this into node_save which will allow other modules to modify the node object using hook_nodeapi.

Hey,

Thanks for the code. What if I'd like to use an image already in the right place? That is, I don't want to copy the image at all, but just get the array generated from this function.

Thanks,
~Matt

Thanks alot for the post! Really helped! I think the proper way to create a node via code is to use drupal_execute like:

drupal_execute('node_form', $form_state, $node);

I can't use:
$field_name = 'field_text';
$node->$field_name[0]['value'] = 'TEXT';
I get "PHP Fatal error: Cannot use string offset as an array ..."

Any ideas?

Nice, I've been looking for this, but what is the proper way to call this function modulename_save_image ?

Thanks,
-Kyle

Would this work in a situation where
-D6
-I already have a cck node type defined (node-pfdog.tpl.php)
-nodes populated by custom Feeds mapping
-pics are hosted on another site so defined in tpl
-want those pics to be cck so I can do slideshow/view of all pics

Just found your article while searching for info about how to create a new node programmatically.
As a bonus i know now how to save to CCK fields aswell :-)

Great tutorial.

@Badger

You could also wrap the $field_name variable with {} like so:

$node->{$field_name}

Cheers!

Post new comment

The content of this field is kept private and will not be shown publicly.
Type the characters you see in this picture. (verify using audio)
Type the characters you see in the picture above; if you can't read them, submit the form and a new image will be generated. Not case sensitive.