How to do custom processing of feeds imports

Posted By Joe Haskins on Friday, January 3, 2014 - 11:33

Many Drupal developers will agree that Feeds is the go-to module for importing content into Drupal. While it works great “out of the box” for importing spreadsheets, xml files, or nearly anything else you can throw at it, sometimes you need to do more than just save values to a field. What happens if you need to do some additional processing on the values before you save them?

I encountered this problem on a project where the client supplied content in a spreadsheet with a unique “sort by” field and an “antecedents” field that could be empty or contain the sort by values for one or more other pieces of content from the spreadsheet. Within Drupal, the antecedents were implemented as an entity reference field so I faced the challenge of mapping the list of “sort by” values to nodes during the import. The solution is to define a new mapping target that will handle any custom processing that needs to be done.

The feeds module provides hook_feeds_processor_targets_alter() which can be used to add new mapping targets. Using it to add a new mapping target is simply a matter of supplying a name and callback function for the target.

  1. function MYMODULE_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name) {
  2.   if ($entity_type == 'node') {
  3.     $targets['somefield']['name'] = t('somefield custom import target');
  4.     $targets['somefield']['callback'] = 'MYMODULE_somefield_set_target';
  5.   }
  6. }

Once you’ve defined the target for feeds, you need to create the callback function that will handle whatever custom processing you need.

  1. function MYMODULE_somefield_set_target($source, $entity, $target, $value, $mapping) {
  2.   // This is where you would do whatever custom processing you need to to.
  3.   // $value contains the raw value from the source.
  4.   $processed = do_something($value);
  5.  
  6.   // Remove any existing values from the entity in case this is an update.
  7.   unset($entity->{'field_'.$target}[$entity->language]);
  8.  
  9.   $entity->{'field_'.$target}[$entity->language] = array();
  10.  
  11.   // Now assign the processed value to the entity.
  12.   // This example only shows a single value but this is easily adapted
  13.   // for multiple values.
  14.   $entity->{'field_'.$target}[$entity->language][]['target_id'] = $processed;    
  15. }

Now all that’s left is to enable your custom module and add a mapping to the new target.