Display a CCK Filefield or Imagefield Upload Widget on Your Own Custom Form

Took a fair amount of googling around to find the solution to this one. With the Node Gallery 3.x branch, we needed a way to quickly add an image to an existing gallery. We could have displayed the whole node form, but there's a lot of things on that form that we can just use the defaults for 99% of the time. We need just three fields filled in: Title, Caption, and the imagefield itself.

To use the same imagefield widget that handles all the hard work for you on the node add field on your own field, first create a handler in hook_menu such as this:

  1.   $items['node/%node_gallery_gallery/upload'] = array(
  2.     'title' => 'Upload New Image',
  3.     'page callback' => 'drupal_get_form',
  4.     'page arguments' => array('node_gallery_upload_image_form', 1),
  5.     'access callback' => 'node_gallery_user_access',
  6.     'access arguments' => array('upload', 1),
  7.     'file' => 'node_gallery.pages.inc',
  8.     'type' => MENU_LOCAL_TASK,
  9.   );

Then, in node_gallery.pages.inc, you create the form function that does the work:

  1. function node_gallery_upload_image_form($form_state, $gallery) {
  2.   $imagetype = 'node_gallery_image';
  3.   $form_id = $imagetype . '_node_form';
  4.  
  5.   module_load_include('inc', 'content', 'includes/content.node_form');
  6.  
  7.   $field = content_fields('field_node_gallery_image',$imagetype);
  8.  
  9.   $form['title'] = array(
  10.     '#title' => t('Title'),
  11.     '#type' => 'textfield',
  12.     '#required' => TRUE,
  13.     '#weight' => -10,
  14.   );
  15.   $form['body'] = array(
  16.     '#title' => t('Caption'),
  17.     '#type' => 'textarea',
  18.     '#weight' => -9,
  19.   );
  20.   $form['type'] = array(
  21.     '#type' => 'value',
  22.     '#value' => $imagetype,
  23.   );
  24.   $form['gid'] = array(
  25.     '#type' => 'value',
  26.     '#value' => $gallery->nid,
  27.   );
  28.   $form['#field_info']['field_node_gallery_image'] = $field;
  29.   $form['#field_info']['field_node_gallery_image']['#required'] = TRUE;
  30.   $form += (array) content_field_form($form, $form_state, $field);
  31.  
  32.   $form['submit'] = array('#type' => 'submit', '#weight' => 10, '#value' => 'Save');
  33.  
  34.   return $form;

This is pretty straightforward, up until lines 28 - 30. Those three lines setup the form array and then append the results from content_field_form() to our existing form. Still, very easy, but I wasn't able to find any documentation on how to do this. Just in case you're curious, here's the submit handler for that form.

  1. function node_gallery_upload_image_form_submit($form, &$form_state) {
  2.   global $user;
  3.   $image = new stdClass;
  4.   $image->uid = $user->uid;
  5.   $image->name = (isset($user->name) ? $user->name : '');
  6.   $values = $form_state['values'];
  7.   foreach ($values as $key => $value) {
  8.     $image->$key = $value;
  9.   }
  10.   node_gallery_image_save($image);
  11. }

Nothing new there. The end result is a nice looking, concise form that allows you to quickly upload an image to a gallery. Sweet!

Your rating: None Average: 4.4 (5 votes)

Comments

Extremely helpful!  I've been

Extremely helpful!  I've been searching for days looking for this!

I have a quick question though.  I've created a module that is basically a front end friendly story node edit form.  I added a image field using CCK to the story content type.

Everything works great until submit and then nothing.  Here is my submit handler.

 

function story_form_submit($form, &$form_state) {
    global $user;
    module_load_include('inc', 'node', 'node.pages');
    $node = array('type' => 'story');
    $story_form_state = array();
    $story_form_state['values']['name'] = $user->name;
    $story_form_state['values']['title'] = $form_state['values']['title'];
    $story_form_state['values']['field_story_name'][0]['value'] = $form_state['values']['name'];
    $story_form_state['values']['field_story_city'][0]['value'] = $form_state['values']['city'];
    $story_form_state['values']['body'] = $form_state['values']['body'];
    $story_form_state['values']['field_story_image'][0]['value'] = $form_state['values']['field_node_gallery_image'];
    $story_form_state['values']['op'] = t('Save');
    drupal_execute('story_node_form', $story_form_state, (object)$node);
}

Thank you for any help!

Maybe you need to add the node object to the form state?

From http://drupal.org/node/293663

Anyway, drupal_execute() called drupal_retrieve_form(), which called node_form(). It was in node_form() that I finally found the culprit. Apparently node_form() expects that the $form_state variable should contain a duplicate copy of the $node object, as an array. The first thing it does is overwrite the $node variable that's passed to it as an argument with the one that comes inside the $form_state array. I hadn't set such a thing on my $form_state variable, and so it was resetting it the way it thought the $node really OUGHT to be.

So the very simple solution was to add the following single line of code immediately before the call to drupal_execute():

<?php
    $form_state
['node'] = (array) $node;
?>

Thank you again for all your

Thank you again for all your help.  Unfortunatly that didn't fix the problem. 

It actually seems like a validation issue.  If I remove the required setting from the field and submit the form without an image it works perfectly.

Am I referencing the submitted form elements correctly for the image field?

2 things

First, unless you named your imagefield 'node_gallery_image' (which is what I named mine in the module), then you have the wrong value in there.  I'm going to assume you called it 'story_image'.

Second, your arrays are out of alignment.

Give this a try:

    $story_form_state['values']['field_story_image'] = $form_state['values']['field_story_image'];

Problem handing a CCK filefield in my form

Hi:

I need to do something very similar...add a file upload field to my form.  I don't quite understand your code...can you please post your code for your content_fields and content_field_form functions?

My current problem is that I have a file upload field in my form, defined like so:

function mmil_upload_form ( $form_state )
{
       ....    

       $form['#attributes']['enctype'] = 'multipart/form-data';
       $form['file'] = array (
        '#type' => 'file',
        '#description' => 'We accept .zip, .gzip, .tgz, tar.gz and .bz2 files up to 2 MB.',
        '#required' => TRUE,
        '#title' => t ( 'Choose your file to upload' ) );

        $form['submit'] = array ( '#type' => 'submit', '#value' => 'Submit' );

        return ( $form );

}

But when I choose a file to upload and then then click on the submit button, I get an error saying that "Choose your file to upload field is required.", so it thinks the file is missing.  I don't understand why and what I can do to fix this problem.

Your help is appreciated.

Mona

filefield problem solved

I solved my problem...it turns out that I CANNOT use '#required' => TRUE when setting up the file field in the form!  That field will be empty for both validate and submit.  Instead I had to actually save the file in the submit function with file_save_upload() to valiidate it.  Here is my submit function excerpt:

function a_upload_form_submit ( $form, &$form_state )
{
    global $user;

    $limits = _upload_file_limits ( $user );
    $validators = array (
        'file_validate_extensions' => array ( $limits['extensions'] ),
    );
    $file = file_save_upload ( 'file', $validators, null, false );
    if ( $file == 0  )
    {
        form_set_error ( '', t ( 'Error: missing required upload file.' ) );
        return;
    }
    // save data code here

}

Hope this helps someone else.

cheers,

Mona

Thanks

Thanks Justin.

FileField

 

I`m trying to create a CCK widget, based on FileField widget like that. Then I create new CCK widget for my content type. But I did not get this widget while creating a node.

 

<?php
// $Id:

/**
* Implementation of CCK's hook_widget_info().
*/
function filewidget_widget_info() {
  return array(
    
'filewidget' => array(
      
'label' => t('Filewidget'),
      
'field types' => array('filefield'),
      
'multiple values' => CONTENT_HANDLE_CORE,
      
'callbacks' => array(
        
'default value' => CONTENT_CALLBACK_DEFAULT,
      ),
    ),
  );
}

/**
* Implementation of CCK's hook_widget_settings().
*/

function filewidget_widget_settings($op$widget) {
  switch (
$op) {
    case 
'form':
      return 
filewidget_widget_settings_form($widget);
    case 
'validate':
      return 
filewidget_widget_settings_validate($widget);
    case 
'save':
      return 
filewidget_widget_settings_save($widget);
  }
}

function filewidget_widget_settings_form($widget) {
  
$form module_invoke('filefield''widget_settings''form'$widget);

  if ($form['file_extensions']['#default_value'] == 'txt') {
    
$form['file_extensions']['#default_value'] = '3gp avi flv mp4 mpg mpeg';
  }

  $form['text'] = array(
    
'#type' => 'textfield',
    
'#title' => t('Text'),
    
'#default_value' => !empty($widget['text']) ? $widget['text'] : '',
    
'#size' => 15,
    
'#maxlength' => 10,
    
'#description' => t('Lorem ipsum dolorum set amen.'),
  );

  return $form;
}

function filewidget_widget_settings_validate($widget) {
}

function filewidget_widget_settings_save($widget) {
  
$filefield_settings module_invoke('filefield''widget_settings''save'$widget);
  return 
array_merge($filefield_settings, array('text'));
}

/**
* Implementation of CCK's hook_widget().
*
* Assign default properties to item and delegate to FileField.
*/

function filewidget_widget(&$form, &$form_state$field$items$delta 0) {
  
$element filefield_widget($form$form_state$field$items$delta);
  return 
$element;
}

/**
* Element #value_callback function.
*/

function filewidget_widget_value($element$edit FALSE) {
  
$item filefield_widget_value($element$edit);

  return $item;
}

/**
* Element #process callback function.
*/

function filewidget_widget_process($element$edit, &$form_state$form) {
  
$element = array();

  return $element;
}

/**
* Implementation of CCK's hook_default_value().
*/

function filewidget_default_value(&$form, &$form_state$field$delta) {
  return 
filefield_default_value($form$form_state$field$delta);
}

?>

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <p> <span> <div> <h1> <h2> <h3> <h4> <h5> <h6> <img> <map> <area> <hr> <br> <br /> <ul> <ol> <li> <dl> <dt> <dd> <table> <tr> <td> <em> <b> <u> <i> <strong> <font> <del> <ins> <sub> <sup> <quote> <blockquote> <pre> <address> <code> <cite> <embed> <object> <param> <strike> <caption>
  • Lines and paragraphs break automatically.

More information about formatting options