diff --git a/imagefield_zip.ahah.inc b/imagefield_zip.ahah.inc
index 7c52533..f66148b 100644
--- a/imagefield_zip.ahah.inc
+++ b/imagefield_zip.ahah.inc
@@ -38,7 +38,7 @@ function imagefield_zip_js($type_name, $field_name) {
 
   // Destory the orginal zip upload form and replace it with the clean clone.
   $id = 'edit-' . str_replace('_', '-', $field_name) . '-upload';
-  $extra_js .= '<script type="text/javascript">
+  $extra_js = '<script type="text/javascript">
   _imagefield_zip_' . $field_name . '_cloned.insertAfter(_imagefield_zip_' . $field_name . '_real);
   _imagefield_zip_' . $field_name . '_real.remove();
   _imagefield_zip_' . $field_name . '_real = $("#' . $id . '");
@@ -220,3 +220,233 @@ function imagefield_zip_add_files_to_form($type_name, $field_name, $files) {
   $GLOBALS['devel_shutdown'] =  FALSE;
   return $output . $output_js;
 }
+
+/**
+ * AHAH menu callback.
+ */
+function imagefield_zip_multigroup_js($type_name, $group_name) {
+  $result = false;
+  $images = array();
+
+  // File validation array for file_save_upload()
+  //  Has a .zip file extension.
+  //  Is valid zip.
+  $validators = array(
+    'file_validate_extensions' => array('zip'),
+    'imagefield_zip_is_valid_zip' => array(),
+  );
+
+  if ($file = file_save_upload($group_name . '_zip', $validators)) {
+    // Extract all files.
+    $extracted = imagefield_zip_extract($file->filepath);
+    if (!empty($extracted)) {
+      // Only select valid image files
+      $images = array_filter($extracted, '_imagefield_zip_is_archived_image');
+    }
+    else {
+      watchdog('imagefield_zip', t('Unpacked archive appears to be empty.'), array(), 'warning');
+    }
+
+    // Delete the zip file as we extracted and used everything we wanted from it.
+    imagefield_zip_delete_file($file);
+  }
+  else {
+    watchdog('imagefield_zip', t('Failed to save uploaded file'), array(), 'error');
+  }
+
+  // Generate HTML for the images that where uploaded
+  $result = imagefield_zip_add_files_to_multigroup_form($type_name, $group_name, $images);
+
+  // Destory the orginal zip upload form and replace it with the clean clone.
+  $id = 'edit-' . str_replace('_', '-', $group_name) . '-upload';
+  $extra_js = '<script type="text/javascript">
+  _imagefield_zip_' . $group_name . '_cloned.insertAfter(_imagefield_zip_' . $group_name . '_real);
+  _imagefield_zip_' . $group_name . '_real.remove();
+  _imagefield_zip_' . $group_name . '_real = $("#' . $id . '");
+  _imagefield_zip_' . $group_name . '_cloned = _imagefield_zip_' . $group_name . '_real.clone(true);
+  </script>';
+
+  // Theme HTML
+  $data = theme('status_messages') . $result . $extra_js;
+  if ($result !== FALSE) {
+    $return = array('data' => $data, 'status' => TRUE);
+  }
+  else {
+    $return = array('data' => $data);
+  }
+
+  // For some reason, file uploads don't like drupal_json() with its manual
+  // setting of the text/javascript HTTP header. So use this one instead.
+  print drupal_to_js($return);
+  exit;
+}
+
+/**
+ * Menu callback for AHAH addition of new empty widgets.
+ *
+ * Adapted from content_add_more_js to work with groups instead of fields.
+ */
+function imagefield_zip_add_files_to_multigroup_form($type_name_url, $group_name, $files) {
+  $content_type = content_types($type_name_url);
+  $type_name = $content_type['type'];
+  $groups = fieldgroup_groups($type_name);
+  $group = $groups[$group_name];
+
+  // Immediately disable devel shutdown functions so that it doesn't botch our
+  // JSON output.
+  $GLOBALS['devel_shutdown'] = FALSE;
+
+  if (($group['settings']['multigroup']['multiple'] != 1) || empty($_POST['form_build_id'])) {
+    // Invalid request.
+    drupal_set_message(t('An unrecoverable error occurred. The uploaded file likely exceeded the maximum file size (@size) that this server supports.', array('@size' => format_size(file_upload_max_size()))), 'error');
+    return FALSE;
+  }
+
+  // Retrieve the cached form.
+  $form_state = array('submitted' => FALSE);
+  $form_build_id = $_POST['form_build_id'];
+  $form = form_get_cache($form_build_id, $form_state);
+  if (!$form) {
+    // Invalid form_build_id.
+    drupal_set_message(t('An unrecoverable error occurred. This form was missing from the server cache. Try reloading the page and submitting again.'), 'error');
+    return FALSE;
+  }
+
+  $type = content_types($form['#node']->type);
+  $fields = _imagefield_zip_fields($type);
+
+  // We don't simply return a new empty widget to append to existing ones, because
+  // - ahah.js won't simply let us add a new row to a table
+  // - attaching the 'draggable' behavior won't be easy
+  // So we resort to rebuilding the whole table of widgets including the existing ones,
+  // which makes us jump through a few hoops.
+
+  // The form that we get from the cache is unbuilt. We need to build it so that
+  // _value callbacks can be executed and $form_state['values'] populated.
+  // We only want to affect $form_state['values'], not the $form itself
+  // (built forms aren't supposed to enter the cache) nor the rest of $form_data,
+  // so we use copies of $form and $form_data.
+  $form_copy = $form;
+  $form_state_copy = $form_state;
+  $form_copy['#post'] = array();
+  form_builder($_POST['form_id'], $form_copy, $form_state_copy);
+  // Just grab the data we need.
+  $form_state['values'] = $form_state_copy['values'];
+  // Reset cached ids, so that they don't affect the actual form we output.
+  form_clean_id(NULL, TRUE);
+
+  // Sort the $form_state['values'] we just built *and* the incoming $_POST data
+  // according to d-n-d reordering.
+  unset($form_state['values'][$group_name][$group['group_name'] .'_add_more']);
+  foreach ($_POST[$group_name] as $delta => $item) {
+    $form_state['values'][$group_name][$delta]['_weight'] = $item['_weight'];
+    $form_state['values'][$group_name][$delta]['_remove'] = isset($item['_remove']) ? $item['_remove'] : 0;
+  }
+  $group['multiple'] = $group['settings']['multigroup']['multiple'];
+  $form_state['values'][$group_name] = _content_sort_items($group, $form_state['values'][$group_name]);
+  $_POST[$group_name] = _content_sort_items($group, $_POST[$group_name]);
+
+
+  // Find the correct field to add the images to.
+  foreach ($fields as $field_name => $field) {
+    if (isset($form[$group_name][0][$field_name])) {
+      $target_field = $field_name;
+      $dest = filefield_widget_file_path($field);
+      break;
+    }
+  }
+
+  // Build our new form element for the whole group, asking for one more element.
+  $delta = max(array_keys($_POST[$group_name]));
+  $item_count = count($_POST[$group_name]);
+  $delta_used = array();
+
+  // Set previous fids.
+  foreach ($_POST[$group_name] as $delta => $post_values) {
+    if (empty($form[$group_name][$delta][$target_field]['#default_value']['fid']) && !empty($post_values[$target_field]['fid'])) {
+      $temp['#default_value'] = $post_values[$target_field];
+      $form[$group_name][$delta][$target_field]['#default_value'] = filefield_widget_value($temp);
+    }
+  }
+
+  // Add files to empty slots or create a new one.
+  foreach ($files as $file) {
+    // Get an empty delta.
+    while (!empty($form[$group_name][$delta][$target_field]['#default_value']['fid'])) {
+      $delta++;
+    }
+
+    // The delta element does not exist; we need to create it.
+    if (!isset($form[$group_name][$delta][$target_field])) {
+      $item_count++;
+      $form_state['item_count'] = array($group_name => $item_count);
+      $form_element = content_multigroup_group_form($form, $form_state, $group, $delta);
+      // Rebuild weight deltas to make sure they all are equally dimensioned.
+      foreach ($form_element[$group_name] as $key => $item) {
+        if (is_numeric($key) && isset($item['_weight']) && is_array($item['_weight'])) {
+          $form_element[$group_name][$key]['_weight']['#delta'] = $delta;
+        }
+      }
+      // Add the new element at the right place in the (original, unbuilt) form.
+      $success = content_set_nested_elements($form, $group_name, $form_element[$group_name]);
+    }
+
+    // Add photo info to new group.
+    $delta_element = &$form[$group_name][$delta][$target_field];
+    // Put the file in the new element.
+    if ($file = field_file_save_file($file->filepath, $delta_element['#upload_validators'], $dest)) {
+      // Set array perents to prevent php notices.
+      $delta_element['#array_parents'][] = $target_field;
+      // Set the default value of the widget to the extracted file.
+      $delta_element['#default_value'] = filefield_widget_value($delta_element, (array) $file);
+    }
+    // Record new deltas.
+    $delta_used[] = $delta;
+  }
+
+  // Save the new definition of the form.
+  $form_state['values'] = array();
+  form_set_cache($form_build_id, $form, $form_state);
+
+  // Build the new form against the incoming $_POST values so that we can
+  // render the new element.
+  foreach ($delta_used as $delta) {
+    $_POST[$group_name][$delta]['_weight'] = $delta;
+  }
+  $form_state = array('submitted' => FALSE);
+  $form += array(
+    '#post' => $_POST,
+    '#programmed' => FALSE,
+  );
+  $form['#post'] = array();
+  $form = form_builder($_POST['form_id'], $form, $form_state);
+  // Render the new output.
+  $group_form = array_shift(content_get_nested_elements($form, $group_name));
+
+  // We add a div around the new content to receive the ahah effect.
+  foreach ($delta_used as $delta) {
+    $group_form[$delta]['#prefix'] = '<div class="ahah-new-content">'. (isset($group_form[$delta]['#prefix']) ? $group_form[$delta]['#prefix'] : '');
+    $group_form[$delta]['#suffix'] = (isset($group_form[$delta]['#suffix']) ? $group_form[$delta]['#suffix'] : '') .'</div>';
+  }
+  // Prevent duplicate wrapper.
+  unset($group_form['#prefix'], $group_form['#suffix']);
+  // We're in the AHAH handler, so the fieldset was expanded.
+  $group_form['#collapsed'] = FALSE;
+
+  // Generate the new html.
+  $output = drupal_render($group_form);
+
+  // If a newly inserted widget contains AHAH behaviors, they normally won't
+  // work because AHAH doesn't know about those - it just attaches to the exact
+  // form elements that were initially specified in the Drupal.settings object.
+  // The new ones didn't exist then, so we need to update Drupal.settings
+  // by ourselves in order to let AHAH know about those new form elements.
+  $javascript = drupal_add_js(NULL, NULL);
+  $output_js = isset($javascript['setting']) ? '<script type="text/javascript">jQuery.extend(Drupal.settings, '. drupal_to_js(call_user_func_array('array_merge_recursive', $javascript['setting'])) .');</script>' : '';
+
+  // Using drupal_json() breaks filefield's file upload, because the jQuery
+  // Form plugin handles file uploads in a way that is not compatible with
+  // 'text/javascript' response type.
+  $GLOBALS['devel_shutdown'] =  FALSE;
+  return $output . $output_js;
+}
diff --git a/imagefield_zip.info b/imagefield_zip.info
index 3ec509d..d7d1499 100644
--- a/imagefield_zip.info
+++ b/imagefield_zip.info
@@ -3,4 +3,4 @@ description = "Upload a zip file containing images that will automatically be po
 package = CCK
 dependencies[] = imagefield
 core = 6.x
-version = 6.x-6-dev
\ No newline at end of file
+version = 6.x-1.x-dev
diff --git a/imagefield_zip.module b/imagefield_zip.module
index 61fb7ff..7699875 100644
--- a/imagefield_zip.module
+++ b/imagefield_zip.module
@@ -3,6 +3,9 @@
  * Implementation of hook_menu().
  */
 function imagefield_zip_menu() {
+  $items = array();
+
+  // Callback for AHAH zip upload buttons.
   $items['imagefield_zip/ahah/%/%'] = array(
     'page callback' => 'imagefield_zip_js',
     'page arguments' => array(2,3),
@@ -11,6 +14,14 @@ function imagefield_zip_menu() {
     'type' => MENU_CALLBACK,
     'file' => 'imagefield_zip.ahah.inc',
   );
+  $items['imagefield_zip/ahah-multigroup/%/%'] = array(
+    'page callback' => 'imagefield_zip_multigroup_js',
+    'page arguments' => array(2,3),
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+    'file' => 'imagefield_zip.ahah.inc',
+  );
+
   return $items;
 }
 
@@ -62,17 +73,48 @@ function imagefield_zip_extract($filepath) {
   return $extracted;
 }
 
+function imagefield_zip_get_groups(&$form) {
+  // Get groups if available.
+  $groups = array();
+  if (module_exists('fieldgroup')) {
+    // code from fieldgroup_form_alter().
+    $group_rows = array();
+    $field_rows = array();
+
+    //prepare data that will make this easier
+    $groups = fieldgroup_groups($form['type']['#value']);
+    if (!empty($groups)) {
+      foreach ($groups as $name => $more) {
+        $group_rows[] = $name;
+      }
+    }
+
+    if (!empty($form['#field_info'])) {
+      $fields = $form['#field_info'];
+      foreach ($fields as $name => $more) {
+        $field_rows[] = $name;
+      }
+    }
+    fieldgroup_order_fields_groups($group_rows, $groups, $field_rows);
+  }
+  return $groups;
+}
+
 /**
  * Implementation of hook_form_alter().
  */
 function imagefield_zip_form_alter(&$form, $form_state, $form_id) {
-
-
-  if (isset($form['type']) && isset($form['#node']) && $form['type']['#value'] .'_node_form' == $form_id && ($type = content_types($form['#node']->type))) {
+  if (   isset($form['type'])
+      && isset($form['#node'])
+      && $form['type']['#value'] .'_node_form' == $form_id
+      && ($type = content_types($form['#node']->type))
+        ) {
     $form['#after_build'][] = '_imagefield_zip_form_after_build';
 
+    $groups = imagefield_zip_get_groups($form);
+
     foreach (_imagefield_zip_fields($type) as $field) {
-      _imagefield_zip_form($form, $field['field_name'], $form['#node']);
+      _imagefield_zip_form($form, $field['field_name'], $form['#node'], $groups);
     }
   }
 }
@@ -88,30 +130,61 @@ function _imagefield_zip_element_validate($element, &$form_state) {
 * #after_build function to modify CCK fields
 */
 function _imagefield_zip_form_after_build($form, &$form_state) {
+  global $_imagefield_zip;
+
   $type = content_types($form['#node']->type);
   foreach (_imagefield_zip_fields($type) as $field) {
     $field_name = $field['field_name'];
+    $in_a_group = FALSE;
 
     // Move zip upload into fieldset if imagefield is in fieldset.
-    if (!isset($form[$field_name])) {
-      _imagefield_zip_cck_walker($form, $field_name, $form[$field_name .'_zip']);
+    if (!isset($form[$field_name]) && isset($form[$field_name . '_zip'])) {
+      _imagefield_zip_cck_walker($form, $field_name, $form[$field_name . '_zip']);
       unset($form[$field_name .'_zip']);
     }
+    // Set the weight if in a group.
+    if (!isset($form[$field_name]) && !empty($_imagefield_zip['groups'])) {
+      foreach ($_imagefield_zip['groups'] as $group_name) {
+        if (empty($form[$group_name]) || empty($form[$group_name]['#group_fields'][$field_name]) || !isset($form[$group_name]['#weight']) || empty($form[$group_name . '_zip'])) {
+          continue;
+        }
 
-    // Code below creates a clone of the upload field in javascript.
-    $id = 'edit-' . str_replace('_', '-', $field_name) . '-upload';
-    $v = '
-    <script type="text/javascript">
-    <!--//--><![CDATA[//><!--
-    _imagefield_zip_' . $field_name . '_real = $("#' . $id . '");
-    _imagefield_zip_' . $field_name . '_cloned = _imagefield_zip_' . $field_name . '_real.clone(true);
-    //--><!]]>
-    </script>
-    ';
-    $form['_markup_' . $field_name] = array(
-      '#type' => 'markup',
-      '#value' => $v,
-    );
+        $form[$group_name . '_zip']['#weight'] = $form[$group_name]['#weight'] + 0.01;
+        $in_a_group = TRUE;
+
+        // Code below creates a clone of the upload field in javascript.
+        $id = 'edit-' . str_replace('_', '-', $group_name) . '-upload';
+        $v = '
+        <script type="text/javascript">
+        <!--//--><![CDATA[//><!--
+        _imagefield_zip_' . $group_name . '_real = $("#' . $id . '");
+        _imagefield_zip_' . $group_name . '_cloned = _imagefield_zip_' . $group_name . '_real.clone(true);
+        //--><!]]>
+        </script>
+        ';
+        $form['_markup_' . $group_name] = array(
+          '#type' => 'markup',
+          '#value' => $v,
+        );
+      }
+    }
+
+    if (!$in_a_group) {
+      // Code below creates a clone of the upload field in javascript.
+      $id = 'edit-' . str_replace('_', '-', $field_name) . '-upload';
+      $v = '
+      <script type="text/javascript">
+      <!--//--><![CDATA[//><!--
+      _imagefield_zip_' . $field_name . '_real = $("#' . $id . '");
+      _imagefield_zip_' . $field_name . '_cloned = _imagefield_zip_' . $field_name . '_real.clone(true);
+      //--><!]]>
+      </script>
+      ';
+      $form['_markup_' . $field_name] = array(
+        '#type' => 'markup',
+        '#value' => $v,
+      );
+    }
   }
 
   return $form;
@@ -145,64 +218,116 @@ function _imagefield_zip_cck_walker(&$array, $cck_field, $zip_field) {
 /**
  * Implementation of hook_form().
  */
-function _imagefield_zip_form(&$form, $field_name, $node) {
-  if (isset($form[$field_name])) {
-    $max_filesize = format_size(parse_size(file_upload_max_size()));
-
-    $form[$field_name .'_zip'] = array(
-      '#weight' => intval($form[$field_name]['#weight']) + 0.01,
-    );
-    $form[$field_name .'_zip'][$field_name . '_upload'] = array(
-      '#type' => 'file',
-      '#title' => t('Zip Upload'),
-      '#name' => "files[{$field_name}_zip]",
-      '#description' => t('Maximum Filesize: @max_filesize<br />Must be a ZIP file', array('@max_filesize' => $max_filesize)),
-      '#attributes' => array(
-        'accept' => 'zip'
-      ),
-      '#element_validate' => array('_imagefield_zip_element_validate'),
-      //'#imagefield' => &$form[$field_name],
-    );
-
-    // Code adapted from content_multiple_value_form().
-    // Make sure the form is cached so ahah can work.
-    $form['#cache'] = TRUE;
-    $field_name_css = str_replace('_', '-', $form[$field_name]['#field_name']);
-
-    $form[$field_name .'_zip'][$field_name . '_button'] = array(
-      '#type' => 'submit',
-      '#value' => t('Upload'),
-      // Submit callback for disabled JavaScript. drupal_get_form() might get
-      // the form from the cache, so we can't rely on content_form_alter()
-      // including this file. Therefore, call a proxy function to do this.
-      '#submit' => array('content_add_more_submit_proxy'),
-      '#ahah' => array(
-        'path' => 'imagefield_zip/ahah/'. $node->type .'/'. $field_name,
-        'wrapper' => $field_name_css .'-items',
-        'method' => 'replace',
-        'effect' => 'fade',
-      ),
-      // When JS is disabled, the content_add_more_submit handler will find
-      // the relevant field using these entries.
-      '#field_name' => $field_name,
-      '#type_name' => $form['type']['#value'],
-      '#prefix' => '<div class="clear-block">',
-      '#suffix' => '</div>',
-    );
-
-    $form[$field_name]['#prefix'] .= '<div id="'. $field_name_css .'-items">';
-    $form[$field_name]['#suffix'] .= '</div>';
-
-    return TRUE;
+function _imagefield_zip_form(&$form, $field_name, $node, $groups) {
+  if (empty($form[$field_name])) {
+    return FALSE;
   }
+  $max_filesize = format_size(parse_size(file_upload_max_size()));
+  global $_imagefield_zip;
 
-  foreach (element_children($form) as $key) {
-    if (_imagefield_zip_form($form[$key], $field_name, $node)) {
-      return TRUE;
+  if (!empty($groups)) {
+    foreach ($groups as $group_name => $group) {
+      if (!empty($group['fields'][$field_name])) {
+
+        // Code adapted from content_multigroup_add_more().
+        $group_multiple = $group['settings']['multigroup']['multiple'];
+        if ($group_multiple != 1) {
+          continue;
+        }
+
+        // Make sure the form is cached so ahah can work.
+        $form['#cache'] = TRUE;
+        $content_type = content_types($group['type_name']);
+        $group_name = $group['group_name'];
+        $group_name_css = str_replace('_', '-', $group_name);
+        $_imagefield_zip['groups'][] = $group_name;
+
+        $form[$group_name .'_zip'] = array(
+          '#weight' => 0,
+        );
+        $form[$group_name .'_zip'][$group_name . '_upload'] = array(
+          '#type' => 'file',
+          '#title' => t('Zip Upload'),
+          '#name' => "files[{$group_name}_zip]",
+          '#description' => t('Maximum Filesize: @max_filesize<br />Must be a ZIP file', array('@max_filesize' => $max_filesize)),
+          '#attributes' => array(
+            'accept' => 'zip'
+          ),
+          '#element_validate' => array('_imagefield_zip_element_validate'),
+        );
+        $form[$group_name .'_zip'][$group_name . '_button'] = array(
+          '#type' => 'submit',
+          '#value' => t('Upload'),
+          // Submit callback for disabled JavaScript. drupal_get_form() might get
+          // the form from the cache, so we can't rely on content_form_alter()
+          // including this file. Therefore, call a proxy function to do this.
+          '#submit' => array('content_multigroup_add_more_submit'),
+          '#ahah' => array(
+            'path' => 'imagefield_zip/ahah-multigroup/' . $content_type['url_str'] . '/' . $group_name,
+            'wrapper' => $group_name_css .'-items',
+            'method' => 'replace',
+            'effect' => 'fade',
+          ),
+          // When JS is disabled, the content_add_more_submit handler will find
+          // the relevant field using these entries.
+          '#group_name' => $group_name,
+          '#type_name' => $group['type_name'],
+          '#prefix' => '<div class="clear-block">',
+          '#suffix' => '</div>',
+        );
+
+
+        return TRUE;
+      }
     }
   }
 
-  return FALSE;
+
+
+  $form[$field_name .'_zip'] = array(
+    '#weight' => intval($form[$field_name]['#weight']) + 0.01,
+  );
+  $form[$field_name .'_zip'][$field_name . '_upload'] = array(
+    '#type' => 'file',
+    '#title' => t('Zip Upload'),
+    '#name' => "files[{$field_name}_zip]",
+    '#description' => t('Maximum Filesize: @max_filesize<br />Must be a ZIP file', array('@max_filesize' => $max_filesize)),
+    '#attributes' => array(
+      'accept' => 'zip'
+    ),
+    '#element_validate' => array('_imagefield_zip_element_validate'),
+  );
+
+  // Code adapted from content_multiple_value_form().
+  // Make sure the form is cached so ahah can work.
+  $form['#cache'] = TRUE;
+  $field_name_css = str_replace('_', '-', $form[$field_name]['#field_name']);
+
+  $form[$field_name .'_zip'][$field_name . '_button'] = array(
+    '#type' => 'submit',
+    '#value' => t('Upload'),
+    // Submit callback for disabled JavaScript. drupal_get_form() might get
+    // the form from the cache, so we can't rely on content_form_alter()
+    // including this file. Therefore, call a proxy function to do this.
+    '#submit' => array('content_add_more_submit_proxy'),
+    '#ahah' => array(
+      'path' => 'imagefield_zip/ahah/'. $node->type .'/'. $field_name,
+      'wrapper' => $field_name_css .'-items',
+      'method' => 'replace',
+      'effect' => 'fade',
+    ),
+    // When JS is disabled, the content_add_more_submit handler will find
+    // the relevant field using these entries.
+    '#field_name' => $field_name,
+    '#type_name' => $form['type']['#value'],
+    '#prefix' => '<div class="clear-block">',
+    '#suffix' => '</div>',
+  );
+
+  $form[$field_name]['#prefix'] .= '<div id="'. $field_name_css .'-items">';
+  $form[$field_name]['#suffix'] .= '</div>';
+
+  return TRUE;
 }
 
 function _imagefield_zip_fields($type) {
