This is a 4.7 friendly version of the image upload method here: http://drupal.org/node/30944. 4.7 enables much simpler code, making image.module do most of the work.

My task was to add an image upload field to a custom 'news' node - a variation on the standard story node. The function names here use those from my module (news), but these will of course need to be changed to your module references (i.e. mymodule_insert() or whatever).

STEP 1: Add the file upload field to the node's form
Insert the following line into hook_form()

$form['image'] = array('#type' => 'file', '#title' => t('Image'), '#description' => t('Click "Browse..." to select an image to upload.'));

STEP 2: Handle the submitted form's new image field using the image.module.
Create or edit hook_update() and hook_insert(). These use functions from image.module to upload the image and create the 'preview' and 'thumbnail' versions, then associate the image files with this node.

function news_update(&$node) {
  if(function_exists('image_prepare') && function_exists('image_update')){
    image_prepare($node, 'image');
    image_update($node);
  }
}
function news_insert(&$node) {
  if(function_exists('image_prepare') && function_exists('image_insert')){
    image_prepare($node, 'image');
    image_insert($node);
  }
}

STEP 3: Load the node's associated image data into $node

function news_load(&$node) {
  image_load($node);
}

You now have all the functionality you need to upload, store, edit and retrieve an image associated with your node. The call to image_load() in the hook_load() function adds the image path details to the $node array and can be accessed with

$node->images['thumbnail']
$node->images['preview']
$node->images['original']

Using the image field
In my news module I wanted to associate an image with a news article and automatically display that image as a thumbnail in the article teaser and a preview (the version resized appropriately for my theme) in the full article display, both without adding image tags to the stored node content.

Dynamically add preview and thumbnail images to the beginning of the node's content and teaser.
Add to news_view():

  // only add this next line if it does not already exist
  $node = node_prepare($node, $teaser);
  if($node->images['preview']) {
    $node->body = '<img src="/files/'.$node->images['preview'].'"/>'.$node->body;
    $node->teaser = '<img src="/files/'.$node->images['thumbnail'].'" class="teaserThumb" />'.$node->teaser;
  }

Comments

timetrial’s picture

Thanks for posting this. It's really helping me to understand about modules.

I have this nearly working. The module loads fine, but when I add content using my new module drupal tosses an error:

Invalid argument supplied for foreach() in [path to] image.module on line 363.

From there I see the content but no image, and no further errors.

This is an alpha development installl of 4.7b6 on wamp with image module from cvs. Any ideas for what I might still have wrong?

TT

nsyll’s picture

when i submit the node i get
warning: Invalid argument supplied for foreach() in [..]\modules\image\image.module on line 315

image.module on line 315

function image_update($node) {
#line315  foreach ($node->images as $label => $image) {
    $old_path = db_result(db_query("SELECT filepath FROM {files} WHERE filename='%s' AND nid=%d", $label, $node->nid));
    // This is a new image.
    if ($old_path != $image) {
      file_delete(file_create_path($old_path));
      db_query("DELETE FROM {files} WHERE filename='%s' AND nid=%d", $label, $node->nid);
      _image_insert($node, $label, file_create_path($image));
    }
  }
}

Drupal 4.7.3

seanbfuller’s picture

Looks great. The only thing I wonder about is that you are not checking for _original in the insert and edit functions. I've been working on a nodeapi module that adds images to nodes and found that I needed to check for _original to keep drupal from yelling at me when I didn't select an image.

Along these lines, your insert code would be:

      if(function_exists('image_prepare') && function_exists('image_insert')){
          image_prepare($node, 'image');
          if($node->images['_original'] != ''){
            image_insert($node);
          }
      }

And your update code would be:

      if(function_exists('image_prepare') && function_exists('image_update')){
        image_prepare($node, 'image');
        if($node->images[_original] != ''){
          image_update($node);
        }
      }

This works because image_prepare seems to send back a NULL value for $node->images['_original'] when nothing was supplied in the file input form element. Otherwise I was getting "could not copy file" errors when creating nodes without images and editing nodes without changing the image. Note that this is based on 4.7 (beta 5) and image HEAD (v1.184 signed on 2006/02/23). I have not had a chance to test out your code, but it seems like it would have the same issue that I ran into with my code. I'd be interested to hear if you find that you need this check in your code.

--------------------
Sean B. Fuller
www.seanbfuller.com

--------------------
Sean B. Fuller
www.seanbfuller.com

seanbfuller’s picture

For reference, here is the link to the nodeapi code that I wrote:

http://drupal.org/node/56761

--------------------
Sean B. Fuller
www.seanbfuller.com

--------------------
Sean B. Fuller
www.seanbfuller.com

nellus’s picture

Cheers Sean, you just saved me a potential headache. I've been away form my project for a few weeks and coming back to it I had exactly this problem.

vadbars’s picture

Thanks!! Tell me please, what i can insert 2, 3, 4...n images in one node?

delmi76’s picture

I found this post extremely useful!
How can I use image_exact module in order to have exact size thumbs?

Many thanks,

A

crinch’s picture

I have implemented your instruction in my form's submission function to upload the image. My form doesn't redirect to any URL instead on the default page. The image is uploaded but I am facing this error.....
*

* The selected file E:\work\31mayclientdrupal5_newsite\files could not be copied.
* Uploaded file is not a valid image. Only JPG, PNG and GIF files are allowed.

*
Important thing is that My form is collapsible form and submit the values without any redirection mean on its default form page.

I want help to solve this issue........what can be the reason for this...

Thanks in advance.
CRINCH

der_stue’s picture

you have to add:

$form['#attributes'] = array("enctype" => "multipart/form-data");

ekitel’s picture

you mean like this:
$form['attributes'] = array("#enctype" => "multipart/form-data");

dchan’s picture

$form['#attributes'] = array("enctype" => "multipart/form-data");
works for me...

oscnet’s picture

add to track

stephthegeek’s picture

I'm new to Drupal, so this may be out of my league... but could this be used to enable adding an additional image field (beyond the avatar) to user profiles?

rudolphp’s picture

Hi All

Can the same be done for a product module for example the tangible product module??
If yes then can you please explain how.
Thanks a lot

Regards
Rudy

slayerment’s picture

I don't know what I'm doing wrong. Here is the code im using right now:

function surgeon_form(&$node) {

  $form['title'] = array('#type' => 'textfield', '#title' => t('Title'), '#required' => TRUE, '#default_value' => $node->title, '#weight' => -5);

  $form['body_filter']['body'] = array('#type' => 'textarea', '#title' => t('Body'), '#default_value' => $node->body, '#rows' => 20, '#required' => TRUE);
  $form['body_filter']['format'] = filter_form($node->format);

  $form['image'] = array('#type' => 'file', '#title' => t('Photo'), '#description' => t('Click "Browse..." to select an image to upload.'));

  return $form;
}


function surgeon_insert(&$node) {
  db_query("INSERT INTO {surgeons} (nid, firstname, lastname, phone) VALUES (%d, '%s', '%s', '%s')", $node->nid, $node->firstname, $node->lastname, $node->phone);
  if(function_exists('image_prepare') && function_exists('image_insert')){
    image_prepare($node, 'image');
    if($node->images['_original'] != ''){
      image_insert($node);
    }
  }
}

function surgeon_update(&$node) {
  db_query("UPDATE {surgeons} SET firstname = '%s', lastname = '%s', phone = '%s' WHERE nid = %d", $node->firstname, $node->lastname, $node->phone, $node->nid);
  if(function_exists('image_prepare') && function_exists('image_update')){
    image_prepare($node, 'image');
    if($node->images['_original'] != ''){
      image_update($node);
    }
  }
}

function surgeon_load(&$node) {
  $surgeon = db_fetch_object(db_query("SELECT * FROM {surgeons} WHERE nid = '$node->nid'"));
  image_load($node);

  return $surgeon;
}

If I try uploading an image from the image.module it works fine. So I must be doing something wrong here. Any help would be appreciated.

Thanks!

erwanpia’s picture

Hi, my new module works fine with the image_module except for the image_exact function, I get the following error :

warning: Division by zero in mage_exact.module on line 89

due to the fact that the image_exact_nodeapi doesn't have the
$node->images['_original'] variable

even though it has the $node->type variable

any idea guys ?

thanks

erwanpia’s picture

Hi guys, about the image resize problem, I found the answer myself. Is this not a popular issue ?

anyway, the only thing is to add the [images][_original], [images][thumbnail] and edit[images][preview] hidden fields in your custom module form function

more info here

ymcp’s picture

Can you post the exact code you used? Following this thread, I now have a partially working test module which allows an image to be attached to a custom "news" node, but the image_exact resize does not seem to be working.

I added the hidden fields to the form, but still no joy. :-(

seanbfuller’s picture

For other people finding this thread, I think a lot of this code has culminated in walkah's image_attach module, which part of image module. it recently got tagged for 4.7, but I myself have not tested it yet. You may still have custom needs that require you to use some of the options above, but until the next generation of node relationship APIs and file APIs comes out, his contrib module might be the proper place to deal with some of these issues and feature requests. After all, it's part of an actual project, which means patches can be submitted against it. Just a heads up.

--------------------
Sean B. Fuller
www.seanbfuller.com
www.tractiv.com

--------------------
Sean B. Fuller
www.seanbfuller.com

patrickespake’s picture

The only solution is interesting, if I can put more than one image.
Insert one image is only very basic, how do I put 2, 3, 4, 5 or N images?

I am trying to do that here, but I am not getting success.

Patrick Espake
e-mail: patrickespake@gmail.com
site: www.patrickespake.com

Woody’s picture

I'm now trying to make a component for the Webform-module.
The first step is implemented in _webform_edit_choice and that works (an input-field on my edit-page).
But i don't know if the _webform_insert_choice and the _webform_update_choice can communicate with the image-module.

Can someone help me with this issue?

dev18.addweb’s picture

Yes you can place image field option in edit Tab of your about us page.and can show this image in view Tab. Please follow the code to it.

Place this code in custom_form function

step 1.

...
 $form['image_field_name'] = array(
    '#type' => 'managed_file',
    '#name' => 'name_of_image',
    '#title' => t('Title of Image'),
    '#upload_location' => 'public://', //as you want in file directory
  );

step 2.

place this code in custom submit function

variable_set ('image_variable_name' , $form_state['complete form']['image_field_name']['#file']->filename);

step 3.

Now You can use image variable 'image_variable_name' in variable_get() function

...
print('<img src="'.$base_url.'/sites/default/files/'.variable_get('image_variable_name').'">'); 
...

Thanks