diff --git a/includes/webform.report.inc b/includes/webform.report.inc
index 628b57d..9ba0f59 100644
--- a/includes/webform.report.inc
+++ b/includes/webform.report.inc
@@ -177,11 +177,32 @@ function webform_results_table($node, $pager_count = 0) {
   }
 
   // Get all the submissions for the node.
-  $header = theme('webform_results_table_header', array('node' => $node));
+  $options['type'] = 'results';
+  $header = webform_results_download_submission_information($node, $options);
+  foreach (theme('webform_results_table_header', array('node' => $node)) as $key => $cell) {
+    $cell['title'] = $cell['data'];
+    $header[$key] = $cell;
+  }
+  foreach ($header as &$info) {
+    $info['data'] = $info['title'];
+  }
   $submissions = webform_get_submissions($node->nid, $header, $pager_count);
   $total_count = webform_get_submission_count($node->nid);
 
-  $output = theme('webform_results_table', array('node' => $node, 'components' => $node->webform['components'], 'submissions' => $submissions, 'total_count' => $total_count, 'pager_count' => $pager_count));
+  $row_count = count($submissions);
+  foreach ($submissions as $sid => &$submission) {
+    $extra_data[$sid] = module_invoke_all('webform_results_download_submission_information_data', $submission, $options, 0, $row_count);
+  }
+
+  $output = theme('webform_results_table', array(
+    'node' => $node,
+    'components' => $node->webform['components'],
+    'submissions' => $submissions,
+    'total_count' => $total_count,
+    'pager_count' => $pager_count,
+    'header' => $header,
+    'extra_data' => $extra_data,
+  ));
   if ($pager_count) {
     $output .= theme('pager');
   }
@@ -219,24 +240,23 @@ function theme_webform_results_table($variables) {
   $submissions = $variables['submissions'];
   $total_count = $variables['total_count'];
   $pager_count = $variables['pager_count'];
+  $header = $variables['header'];
+  $extra_data = $variables['extra_data'];
 
-  $header = array();
   $rows = array();
   $cell = array();
 
   // This header has to be generated separately so we can add the SQL necessary.
   // to sort the results.
-  $header = theme('webform_results_table_header', array('node' => $node));
 
   // Generate a row for each submission.
   foreach ($submissions as $sid => $submission) {
-    $link_text = $submission->is_draft ? t('@serial (draft)', array('@serial' => $submission->serial)) : $submission->serial;
-    $cell[] = l($link_text, 'node/' . $node->nid . '/submission/' . $sid);
-    $cell[] = format_date($submission->submitted, 'short');
-    $cell[] = theme('username', array('account' => $submission));
-    $cell[] = $submission->remote_addr;
     $component_headers = array();
 
+    foreach (array_keys($header) as $key) {
+      $cell[] = isset($extra_data[$sid][$key]) ? $extra_data[$sid][$key] : '';
+    }
+
     // Generate a cell for each component.
     foreach ($node->webform['components'] as $component) {
       $data = isset($submission->data[$component['cid']]) ? $submission->data[$component['cid']] : NULL;
@@ -397,8 +417,8 @@ function webform_results_download_form($form, &$form_state, $node) {
 
   $csv_components = array('info' => t('Submission information'));
   // Prepend information fields with "-" to indent.
-  foreach (webform_results_download_submission_information($node) as $key => $title) {
-    $csv_components[$key] = '-' . $title;
+  foreach (webform_results_download_submission_information($node, array('type' => 'download')) as $key => $info) {
+    $csv_components[$key] = '-' . $info['title'];
   }
 
   $csv_components += webform_component_list($node, 'csv', TRUE);
@@ -825,8 +845,8 @@ function webform_results_download_headers($node, $options) {
       $header[1][0] = t('Submission Details');
       $submission_information_headers = array_values($submission_information);
     }
-    foreach ($submission_information_headers as $column => $label) {
-      $header[2][$column] = $label;
+    foreach ($submission_information_headers as $column => $info) {
+      $header[2][$column] = $info['title'];
     }
   }
 
@@ -892,10 +912,16 @@ function webform_results_download_rows($node, $options, $serial_start = 0) {
 
     $row = array();
     // Add submission information.
+    $data = module_invoke_all('webform_submission_information_data', $submission, $options, $serial_start, $row_count);
+    $context = array('submission' => $submission, 'options' => $options, 'serial_start' => $serial_start, 'row_count' => $row_count);
+    drupal_alter('webform_submission_information_data', $data, $context);
     foreach (array_keys($submission_information) as $token) {
-      $cell = module_invoke_all('webform_results_download_submission_information_data', $token, $submission, $options, $serial_start, $row_count);
-      $context = array('token' => $token, 'submission' => $submission, 'options' => $options, 'serial_start' => $serial_start, 'row_count' => $row_count);
-      drupal_alter('webform_results_download_submission_information_data', $cell, $context);
+      $data = array(isset($data[$token]) ? $data[$token] : '');
+      if ($cell = module_invoke_all('webform_results_download_submission_information_data', $token, $submission, $options, $serial_start, $row_count)) {
+        $data = $cell;
+      }
+      $context2 = array('token' => $token) + $context;
+      drupal_alter('webform_results_download_submission_information_data', $data, $context2);
       // implode() to ensure everything from a single value goes into one column, even if more than one module responds to this item.
       $row[] = implode(', ', $cell);
     }
@@ -938,9 +964,17 @@ function webform_results_download_rows($node, $options, $serial_start = 0) {
  *   Filter down the list of columns based on a provided column list.
  */
 function webform_results_download_submission_information($node, $options = array()) {
-  $submission_information = module_invoke_all('webform_results_download_submission_information_info');
+  $submission_information = module_invoke_all('webform_submission_information_info', $node, $options);
+  $legacy_submission_information = module_invoke_all('webform_results_download_submission_information_info');
+  $submission_information = drupal_array_merge_deep($legacy_submission_information, $submission_information);
   drupal_alter('webform_results_download_submission_information_info', $submission_information);
+  drupal_alter('webform_submission_information_info', $submission_information, $node, $options);
 
+  foreach ($submission_information as $key => &$info) {
+    if (!is_array($info)) {
+      $info = array('title' => $info);
+    }
+  }
   if (isset($options['components'])) {
     foreach ($submission_information as $key => $label) {
       if (!in_array($key, $options['components'])) {
@@ -953,45 +987,57 @@ function webform_results_download_submission_information($node, $options = array
 }
 
 /**
- * Implements hook_webform_results_download_submission_information_info().
+ * Implements hook_webform_submission_information_info().
  */
-function webform_webform_results_download_submission_information_info() {
-  return array(
-    'webform_serial' => t('Serial'),
-    'webform_sid' => t('SID'),
-    'webform_time' => t('Time'),
-    'webform_draft' => t('Draft'),
-    'webform_ip_address' => t('IP Address'),
-    'webform_uid' => t('UID'),
-    'webform_username' => t('Username'),
-  );
+function webform_webform_submission_information_info($node, $options) {
+  $info = array();
+  if ($options['type'] == 'results') {
+    $info['webform_serial'] = array('title' => t('#'), 'field' => 'sid', 'sort' => 'desc');
+    $info['webform_time'] = array('title' => t('Submitted'), 'field' => 'submitted');
+    $info['webform_user'] = array('title' => t('User'), 'field' => 'name');
+    $info['webform_ip_address'] = array('title' => t('IP Address'), 'field' => 'remote_addr');
+  }
+  else {
+    $info['webform_serial'] = t('Serial');
+    $info['webform_sid'] = array('title' => t('SID'), 'field' => 'sid', 'sort' => 'desc');
+    $info['webform_time'] = array('title' => t('Time'), 'field' => 'submitted');
+    $info['webform_draft'] = t('Draft');
+    $info['webform_ip_address'] = array('title' => t('IP Address'), 'field' => 'remote_addr');
+    $info['webform_uid'] = t('UID');
+    $info['webform_username'] = t('Username');
+  }
+  return $info;
 }
 
 /**
  * Implements hook_webform_results_download_submission_information_data().
  */
-function webform_webform_results_download_submission_information_data($token, $submission, array $options, $serial_start, $row_count) {
-  switch ($token) {
-    case 'webform_serial':
-      return $submission->serial;
-    case 'webform_sid':
-      return $submission->sid;
-    case 'webform_time':
-      if (!empty($options['iso8601_date'])) {
-        return format_date($submission->submitted, 'custom', 'Y-m-d\TH:i:s', 'UTC');
-      }
-      else {
-        return format_date($submission->submitted, 'short');
-      }
-    case 'webform_draft':
-      return $submission->is_draft;
-    case 'webform_ip_address':
-      return $submission->remote_addr;
-    case 'webform_uid':
-      return $submission->uid;
-    case 'webform_username':
-      return $submission->name;
+function webform_webform_submission_information_data($submission, array $options, $serial_start, $row_count) {
+  $data = array();
+  if ($options['type'] == 'results') {
+    $link_text = $submission->is_draft ? t('@serial (draft)', array('@serial' => $submission->serial)) : $submission->serial;
+    $data['webform_serial'] = l($link_text, 'node/' . $submission->nid . '/submission/' . $submission->sid);
   }
+  else {
+    $data['webform_serial'] = $submission->serial;
+  }
+  $data['webform_sid'] = $submission->sid;
+  if (!empty($options['iso8601_date'])) {
+    $time = format_date($submission->submitted, 'custom', 'Y-m-d\TH:i:s', 'UTC');
+  }
+  else {
+    $time = format_date($submission->submitted, 'short');
+  }
+  $data['webform_time'] = $time;
+  $data['webform_draft'] = $submission->is_draft;
+  $data['webform_ip_address'] = $submission->remote_addr;
+  $data['webform_uid'] = $submission->uid;
+  $data['webform_username'] = $submission->name;
+  $data['webform_user']['data'] = array(
+    '#theme' => 'username',
+    '#account' => $submission
+  );
+  return $data;
 }
 
 /**
@@ -1006,7 +1052,7 @@ function webform_webform_results_download_submission_information_data($token, $s
  *   through from the GUI interface.
  */
 function webform_results_download_default_options($node, $format) {
-  $submission_information = webform_results_download_submission_information($node);
+  $submission_information = webform_results_download_submission_information($node, array('type' => 'download'));
 
   $options = array(
     'delimiter' => variable_get('webform_csv_delimiter', '\t'),
diff --git a/webform.api.php b/webform.api.php
index 3e92b74..ffe6e12 100644
--- a/webform.api.php
+++ b/webform.api.php
@@ -727,6 +727,59 @@ function hook_webform_node_defaults_alter(&$defaults) {
 /**
  * Add additional fields to submission data downloads.
  *
+ * @param stdclass $node
+ *   Webform node
+ * @param array $options
+ *   Extra parameters. Contains at least the index type.
+ *
+ * @return
+ *   Keys and titles for default submission information.
+ *   Optionally the value can be an array with the following keys:
+ *     - title: the translated title (usually used as table header).
+ *     - field: the entry corresponds a specific field in the query
+ *              (used for table sorting).
+ *     - sort: asc/desc -- default sort order (if any).
+ *
+ * @see hook_webform_submission_information_data()
+ */
+function hook_webform_submission_information_info($node, array $options) {
+  return array(
+    'field_key_1' => t('Field Title 1'),
+    'field_key_2' => array(
+      'title' => t('Field Title 2'),
+      'field' => 'sid',
+      'sort' => 'desc',
+    ),
+  );
+}
+
+/**
+ * Return values for submission data download fields.
+ *
+ * @param $submission
+ *   The data for an individual submission from webform_get_submissions().
+ * @param $options
+ *   A list of options that define the output format. These are generally passed
+ *   through from the GUI interface.
+ * @param $serial_start
+ *   The starting position for the Serial column in the output.
+ * @param $row_count
+ *   The number of the row being generated.
+ *
+ * @return
+ *   Values for the information fields keyed by their keys.
+ *
+ * @see hook_webform_results_download_submission_information_info()
+ */
+function hook_webform_submission_information_data($submission, array $options, $serial_start, $row_count) {
+  $data['field_key_1'] = 'Field Value 1';
+  $data['field_key_2'] = 'Field Value 2';
+  return $data;
+}
+
+/**
+ * Add additional fields to submission data downloads.
+ *
  * @return
  *   Keys and titles for default submission information.
  *
diff --git a/webform.module b/webform.module
index cc78572..2a992e0 100644
--- a/webform.module
+++ b/webform.module
@@ -797,7 +797,7 @@ function webform_theme() {
       'file' => 'includes/webform.report.inc',
     ),
     'webform_results_table' => array(
-      'variables' => array('node' => NULL, 'components' => NULL, 'submissions' => NULL, 'node' => NULL, 'total_count' => NULL, 'pager_count' => NULL),
+      'variables' => array('node' => NULL, 'components' => NULL, 'submissions' => NULL, 'node' => NULL, 'total_count' => NULL, 'pager_count' => NULL, 'header' => array(), 'extra_data' => array()),
       'file' => 'includes/webform.report.inc',
     ),
     'webform_results_download_range' => array(
