diff --git a/feeds.api.php b/feeds.api.php
index c139da1..89188f2 100644
--- a/feeds.api.php
+++ b/feeds.api.php
@@ -283,8 +283,8 @@ function hook_feeds_processor_targets_alter(&$targets, $entity_type, $bundle) {
 
       // Specify both summary_callback and form_callback to add a per mapping
       // configuration form.
-      'summary_callback' => 'my_module_summary_callback',
-      'form_callback' => 'my_module_form_callback',
+      'summary_callback' => array('my_module_summary_callback'),
+      'form_callback' => array('my_module_form_callback'),
     );
     $targets['my_node_field2'] = array(
       'name' => t('My Second custom node field'),
diff --git a/feeds.module b/feeds.module
index 419e071..4418e9c 100644
--- a/feeds.module
+++ b/feeds.module
@@ -35,6 +35,7 @@ function feeds_hook_info() {
     'feeds_after_save',
     'feeds_after_import',
     'feeds_after_clear',
+    'feeds_processor_targets',
     'feeds_processor_targets_alter',
     'feeds_parser_sources_alter',
   );
diff --git a/feeds_ui/feeds_ui.admin.inc b/feeds_ui/feeds_ui.admin.inc
index 45b423c..1ed2de3 100644
--- a/feeds_ui/feeds_ui.admin.inc
+++ b/feeds_ui/feeds_ui.admin.inc
@@ -633,12 +633,12 @@ function feeds_ui_mapping_settings_form($form, $form_state, $i, $mapping, $targe
   }
 
   if ($form_state['mapping_settings_edit'] === $i) {
+    $settings_form = array();
     // Build the form.
-    if (isset($target['form_callback'])) {
-      $settings_form = call_user_func($target['form_callback'], $mapping, $target, $form, $form_state);
-    }
-    else {
-      $settings_form = array();
+    if (!empty($target['form_callback'])) {
+      foreach ((array) $target['form_callback'] as $callback) {
+        $settings_form += call_user_func($callback, $mapping, $target, $form, $form_state);
+      }
     }
 
     // Merge in the optional unique form.
@@ -662,12 +662,13 @@ function feeds_ui_mapping_settings_form($form, $form_state, $i, $mapping, $targe
     );
   }
   else {
+    $summary = '';
     // Build the summary.
-    if (isset($target['summary_callback'])) {
-      $summary = call_user_func($target['summary_callback'], $mapping, $target, $form, $form_state);
-    }
-    else {
-      $summary = '';
+    if (!empty($target['summary_callback'])) {
+      foreach ((array) $target['summary_callback'] as $callback) {
+        $summary[] = call_user_func($callback, $mapping, $target, $form, $form_state);
+      }
+      $summary = implode('<br />', $summary);
     }
 
     // Append the optional unique summary.
diff --git a/mappers/date.inc b/mappers/date.inc
index 061962d..abb56d3 100644
--- a/mappers/date.inc
+++ b/mappers/date.inc
@@ -6,13 +6,12 @@
  */
 
 /**
- * Implements hook_feeds_processor_targets_alter().
- *
- * @see FeedsNodeProcessor::getMappingTargets().
+ * Implements hook_feeds_processor_targets().
  *
  * @todo Only provides "end date" target if field allows it.
  */
-function date_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name) {
+function date_feeds_processor_targets($entity_type, $bundle_name) {
+  $targets = array();
   foreach (field_info_instances($entity_type, $bundle_name) as $name => $instance) {
     $info = field_info_field($name);
     if (in_array($info['type'], array('date', 'datestamp', 'datetime'))) {
@@ -30,6 +29,7 @@ function date_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_nam
       );
     }
   }
+  return $targets;
 }
 
 /**
diff --git a/mappers/file.inc b/mappers/file.inc
index e9cbc26..b21a0f7 100644
--- a/mappers/file.inc
+++ b/mappers/file.inc
@@ -7,11 +7,10 @@
  */
 
 /**
- * Implements hook_feeds_processor_targets_alter().
- *
- * @see FeedsNodeProcessor::getMappingTargets()
+ * Implements hook_feeds_processor_targets().
  */
-function file_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name) {
+function file_feeds_processor_targets($entity_type, $bundle_name) {
+  $targets = array();
   foreach (field_info_instances($entity_type, $bundle_name) as $name => $instance) {
     $info = field_info_field($name);
 
@@ -39,6 +38,7 @@ function file_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_nam
       }
     }
   }
+  return $targets;
 }
 
 /**
diff --git a/mappers/link.inc b/mappers/link.inc
index 90b5268..9b4c011 100644
--- a/mappers/link.inc
+++ b/mappers/link.inc
@@ -6,11 +6,10 @@
  */
 
 /**
- * Implements hook_feeds_processor_targets_alter().
- *
- * @see FeedsProcessor::getMappingTargets()
+ * Implements hook_feeds_processor_targets().
  */
-function link_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name) {
+function link_feeds_processor_targets($entity_type, $bundle_name) {
+  $targets = array();
   foreach (field_info_instances($entity_type, $bundle_name) as $name => $instance) {
     $info = field_info_field($name);
     if ($info['type'] == 'link_field') {
@@ -32,6 +31,7 @@ function link_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_nam
       }
     }
   }
+  return $targets;
 }
 
 /**
diff --git a/mappers/number.inc b/mappers/number.inc
index 338d569..056a285 100644
--- a/mappers/number.inc
+++ b/mappers/number.inc
@@ -6,11 +6,10 @@
  */
 
 /**
- * Implements hook_feeds_processor_targets_alter().
- *
- * @see FeedsProcessor::getMappingTargets()
+ * Implements hook_feeds_processor_targets().
  */
-function number_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name) {
+function number_feeds_processor_targets($entity_type, $bundle_name) {
+  $targets = array();
   $numeric_types = array(
     'list_integer',
     'list_float',
@@ -30,6 +29,7 @@ function number_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_n
       );
     }
   }
+  return $targets;
 }
 
 /**
diff --git a/mappers/path.inc b/mappers/path.inc
index cd39fb1..8d86391 100644
--- a/mappers/path.inc
+++ b/mappers/path.inc
@@ -6,11 +6,11 @@
  */
 
 /**
- * Implements hook_feeds_processor_targets_alter().
- *
- * @see FeedsNodeProcessor::getMappingTargets().
+ * Implements hook_feeds_processor_targets().
  */
-function path_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name) {
+function path_feeds_processor_targets($entity_type, $bundle_name) {
+  $targets = array();
+
   switch ($entity_type) {
     case 'node':
     case 'taxonomy_term':
@@ -19,11 +19,12 @@ function path_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_nam
         'name' => t('Path alias'),
         'description' => t('URL path alias of the node.'),
         'callback' => 'path_feeds_set_target',
-        'summary_callback' => 'path_feeds_summary_callback',
-        'form_callback' => 'path_feeds_form_callback',
+        'summary_callback' => array('path_feeds_summary_callback'),
+        'form_callback' => array('path_feeds_form_callback'),
       );
       break;
   }
+  return $targets;
 }
 
 /**
@@ -73,7 +74,7 @@ function path_feeds_set_target($source, $entity, $target, array $values, $mappin
  *   Associative array of the mapping settings.
  * @param $target
  *   Array of target settings, as defined by the processor or
- *   hook_feeds_processor_targets_alter().
+ *   hook_feeds_processor_targets().
  * @param $form
  *   The whole mapping form.
  * @param $form_state
diff --git a/mappers/profile.inc b/mappers/profile.inc
index 00fdf3a..20f4843 100644
--- a/mappers/profile.inc
+++ b/mappers/profile.inc
@@ -6,10 +6,10 @@
  */
 
 /**
- * Implements hook_feeds_processor_target_alter().
+ * Implements hook_feeds_processor_targets().
  */
-function profile_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name) {
-
+function profile_feeds_processor_targets($entity_type, $bundle_name) {
+  $targets = array();
   if ($entity_type != 'user') {
     return;
   }
@@ -25,6 +25,7 @@ function profile_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_
       );
     }
   }
+  return $targets;
 }
 
 /**
diff --git a/mappers/taxonomy.inc b/mappers/taxonomy.inc
index 088a558..8925ad2 100644
--- a/mappers/taxonomy.inc
+++ b/mappers/taxonomy.inc
@@ -55,9 +55,10 @@ function taxonomy_feeds_get_source(FeedsSource $source, FeedsParserResult $resul
 }
 
 /**
- * Implements hook_feeds_processor_targets_alter().
+ * Implements hook_feeds_processor_targets().
  */
-function taxonomy_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name) {
+function taxonomy_feeds_processor_targets($entity_type, $bundle_name) {
+  $targets = array();
   foreach (field_info_instances($entity_type, $bundle_name) as $name => $instance) {
     $info = field_info_field($name);
     if ($info['type'] == 'taxonomy_term_reference') {
@@ -65,8 +66,8 @@ function taxonomy_feeds_processor_targets_alter(&$targets, $entity_type, $bundle
         'name' => check_plain($instance['label']),
         'callback' => 'taxonomy_feeds_set_target',
         'description' => t('The @label field of the entity.', array('@label' => $instance['label'])),
-        'summary_callback' => 'taxonomy_feeds_summary_callback',
-        'form_callback' => 'taxonomy_feeds_form_callback',
+        'summary_callback' => array('taxonomy_feeds_summary_callback'),
+        'form_callback' => array('taxonomy_feeds_form_callback'),
       );
     }
   }
@@ -75,6 +76,7 @@ function taxonomy_feeds_processor_targets_alter(&$targets, $entity_type, $bundle
     $targets['tid']['description'] = t('The tid of the taxonomy term. NOTE: use this feature with care, node ids are usually assigned by Drupal.');
     unset($targets['vocabulary']);
   }
+  return $targets;
 }
 
 /**
@@ -244,7 +246,7 @@ function taxonomy_feeds_term_lookup_term_by_guid($guid) {
  *   Associative array of the mapping settings.
  * @param array $target
  *   Array of target settings, as defined by the processor or
- *   hook_feeds_processor_targets_alter().
+ *   hook_feeds_processor_targets().
  * @param array $form
  *   The whole mapping form.
  * @param array $form_state
diff --git a/mappers/text.inc b/mappers/text.inc
index 235aea3..5696f4d 100644
--- a/mappers/text.inc
+++ b/mappers/text.inc
@@ -6,11 +6,10 @@
  */
 
 /**
- * Implements hook_feeds_processor_targets_alter().
- *
- * @see FeedsProcessor::getMappingTargets()
+ * Implements hook_feeds_processor_targets().
  */
-function text_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name) {
+function text_feeds_processor_targets($entity_type, $bundle_name) {
+  $targets = array();
   $text_types = array(
     'list_text',
     'text',
@@ -38,10 +37,11 @@ function text_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_nam
     }
 
     if (!empty($instance['settings']['text_processing'])) {
-      $targets[$name]['summary_callback'] = 'text_feeds_summary_callback';
-      $targets[$name]['form_callback'] = 'text_feeds_form_callback';
+      $targets[$name]['summary_callback'] = array('text_feeds_summary_callback');
+      $targets[$name]['form_callback'] = array('text_feeds_form_callback');
     }
   }
+  return $targets;
 }
 
 /**
@@ -88,7 +88,7 @@ function text_feeds_set_target(FeedsSource $source, $entity, $target, array $val
  *
  * Displays which text format will be used for the text field target.
  *
- * @see text_feeds_processor_targets_alter()
+ * @see text_feeds_processor_targets()
  * @see text_feeds_form_callback()
  */
 function text_feeds_summary_callback(array $mapping, $target, array $form, array $form_state) {
@@ -110,7 +110,7 @@ function text_feeds_summary_callback(array $mapping, $target, array $form, array
  *
  * Allows to select a text format for the text field target.
  *
- * @see text_feeds_processor_targets_alter()
+ * @see text_feeds_processor_targets()
  * @see text_feeds_summary_callback()
  */
 function text_feeds_form_callback(array $mapping, $target, array $form, array $form_state) {
diff --git a/plugins/FeedsEntityProcessor.inc b/plugins/FeedsEntityProcessor.inc
index 5125c94..4e48fe9 100644
--- a/plugins/FeedsEntityProcessor.inc
+++ b/plugins/FeedsEntityProcessor.inc
@@ -260,10 +260,7 @@ class FeedsEntityProcessor extends FeedsProcessor {
       unset($targets[$entity_info['bundle keys']['bundle']]);
     }
 
-    // Let other modules expose mapping targets.
-    self::loadMappers();
-    $type = $this->entityType();
-    drupal_alter('feeds_processor_targets', $targets, $type, $info['bundle']);
+    $this->getHookTargets($targets);
 
     return $targets;
   }
diff --git a/plugins/FeedsNodeProcessor.inc b/plugins/FeedsNodeProcessor.inc
index d3d3bb4..1f8e584 100644
--- a/plugins/FeedsNodeProcessor.inc
+++ b/plugins/FeedsNodeProcessor.inc
@@ -339,11 +339,7 @@ class FeedsNodeProcessor extends FeedsProcessor {
       );
     }
 
-    // Let other modules expose mapping targets.
-    self::loadMappers();
-    $entity_type = $this->entityType();
-    $bundle = $this->bundle();
-    drupal_alter('feeds_processor_targets', $targets, $entity_type, $bundle);
+    $this->getHookTargets($targets);
 
     return $targets;
   }
diff --git a/plugins/FeedsProcessor.inc b/plugins/FeedsProcessor.inc
index 1c56f62..5b1bcbe 100755
--- a/plugins/FeedsProcessor.inc
+++ b/plugins/FeedsProcessor.inc
@@ -820,6 +820,20 @@ abstract class FeedsProcessor extends FeedsPlugin {
   }
 
   /**
+   * Allows other modules to expose targets.
+   *
+   * @param array &$targets
+   *   The existing target array.
+   */
+  protected function getHookTargets(array &$targets) {
+    self::loadMappers();
+    $type = $this->entityType();
+    $bundle = $this->bundle();
+    $targets += module_invoke_all('feeds_processor_targets', $type, $bundle);
+    drupal_alter('feeds_processor_targets', $targets, $type, $bundle);
+  }
+
+  /**
    * Set a concrete target element. Invoked from FeedsProcessor::map().
    *
    * @ingroup mappingapi
diff --git a/plugins/FeedsTermProcessor.inc b/plugins/FeedsTermProcessor.inc
index 9b0024e..d4670d4 100644
--- a/plugins/FeedsTermProcessor.inc
+++ b/plugins/FeedsTermProcessor.inc
@@ -177,21 +177,13 @@ class FeedsTermProcessor extends FeedsProcessor {
       'description' => array(
         'name' => t('Term description'),
         'description' => t('Description of the taxonomy term.'),
-        'summary_callback' => 'text_feeds_summary_callback',
-        'form_callback' => 'text_feeds_form_callback',
+        'summary_callback' => array('text_feeds_summary_callback'),
+        'form_callback' => array('text_feeds_form_callback'),
       ),
     );
 
-    // Let implementers of hook_feeds_term_processor_targets() add their targets.
-    try {
-      self::loadMappers();
-      $entity_type = $this->entityType();
-      $bundle = $this->bundle();
-      drupal_alter('feeds_processor_targets', $targets, $entity_type, $bundle);
-    }
-    catch (Exception $e) {
-      // Do nothing.
-    }
+    $this->getHookTargets($targets);
+
     return $targets;
   }
 
diff --git a/plugins/FeedsUserProcessor.inc b/plugins/FeedsUserProcessor.inc
index d01db43..02607f2 100644
--- a/plugins/FeedsUserProcessor.inc
+++ b/plugins/FeedsUserProcessor.inc
@@ -193,11 +193,7 @@ class FeedsUserProcessor extends FeedsProcessor {
        );
     }
 
-    // Let other modules expose mapping targets.
-    self::loadMappers();
-    $entity_type = $this->entityType();
-    $bundle = $this->bundle();
-    drupal_alter('feeds_processor_targets', $targets, $entity_type, $bundle);
+    $this->getHookTargets($targets);
 
     return $targets;
   }
diff --git a/tests/feeds_tests.module b/tests/feeds_tests.module
index fe25704..5ce8961 100644
--- a/tests/feeds_tests.module
+++ b/tests/feeds_tests.module
@@ -102,17 +102,17 @@ function feeds_tests_files_remote() {
 }
 
 /**
- * Implements hook_feeds_processor_targets_alter().
+ * Implements hook_feeds_processor_targets().
  */
-function feeds_tests_feeds_processor_targets_alter(&$targets, $entity_type, $bundle) {
+function feeds_tests_feeds_processor_targets($entity_type, $bundle) {
+  $targets = array();
   $targets['test_target'] = array(
     'name' => t('Test Target'),
     'description' => t('This is a test target.'),
     'callback' => 'feeds_tests_mapper_set_target',
-    'summary_callback' => 'feeds_tests_mapper_summary',
-    'form_callback' => 'feeds_tests_mapper_form',
+    'summary_callback' => array('feeds_tests_mapper_summary'),
+    'form_callback' => array('feeds_tests_mapper_form'),
   );
-
   $targets['test_unique_target'] = array(
     'name' => t('Test unique target'),
     'description' => t('This is a unique test target.'),
@@ -120,6 +120,7 @@ function feeds_tests_feeds_processor_targets_alter(&$targets, $entity_type, $bun
     'optional_unique' => TRUE,
     'unique_callbacks' => array('feeds_tests_mapper_unique'),
   );
+  return $targets;
 }
 
 /**
@@ -217,7 +218,7 @@ function feeds_tests_mapper_form($mapping, $target, $form, $form_state) {
 /**
  * Callback for unique_callbacks for test_target mapper.
  *
- * @see feeds_tests_feeds_processor_targets_alter()
+ * @see feeds_tests_feeds_processor_targets()
  */
 function feeds_tests_mapper_unique(FeedsSource $source, $entity_type, $bundle, $target, array $values) {
   $query = new EntityFieldQuery();
