Got a new web project? Request a quote

How to use the Feeds api

Feeds (http://drupal.org/project/feeds) is a very popular module. From the project page, we get a nice description of the module:

Import or aggregate data as nodes, users, taxonomy terms or simple database records.

The basic idea is that you throw a csv file to it and it creates drupal content. As simple as that. The input format can be more than just a csv, check the project page for more details.

We can use the feeds api http://drupalcode.org/project/feeds.git/blob/HEAD:/feeds.api.php if we want more functionality than the standard.
I am going to describe 3 different uses of the the feeds api:

  1. Perform an operation after a feed source has been parsed, before it will be processed
  2. Perform pre-save operations
  3. Add additional target options to the mapping form

1. Perform an operation after a feed source has been parsed, before it will be processed

Use this hook:

<?php
 hook_feeds_after_parse
()
?>

A common use case is to alter the data from the csv. For example, lets say that the terms we want to import are described different in the csv than in drupal:
In the csv we may have words like "n. america", "s. america", "w. europe", "e. europe" while the terms in drupal are: "north america", "south america", "western europe", "eastern europe". We need to map the csv values to their drupal equivalent data before import:

<?php
/**
 * Implements hook_feeds_after_parse().
 */
function mymodule_feeds_after_parse(FeedsSource $source, FeedsParserResult $result) {
 
$map = array(
   
'e. europe' => 'eastern europe',
   
'w. europe' => 'western europe',
  );
  foreach(
$result->items as $key=>$item){
   
$result->items[$key]['region'] = $map[$result->items[$key]['region']];
  }
}
?>

2. Perform pre-save operations

This allows us to act on the entity that is going to be created. This is similar to the hook_entity_presave().
Here we import only users with their surname equal to 'Smith':

<?php
/**
 * Implements hook_feeds_presave().
 */
function mymodule_feeds_presave(FeedsSource $source, $entity, $item) {

 
// check that this is fired only for the indented importer
 
if($source->importer->id=='my_user_importer'){
   
// check that we like this name
   
if($item['surname'] != 'Smith'){
     
$entity->feeds_item->skip = TRUE;
     
drupal_set_message(t('Only Smith\'s allowed. Skipping...', 'warning');
    }
  }
}
?>

3. Add additional target options to the mapping form

This is the most advanced case described here. The hook

<?php
 hook_feeds_processor_targets_alter
()
?>

allows us to do more complex stuff. For example, lets assume that in our site we are using different newsletter lists, and we want to register the user to the proper list. The newsletter lists are not a field in the user form, so we don't get the option in the feeds ui to control this. This hook allows us to add a field in the feeds ui mapping form and define a callback for its function.

<?php
/**
 * Implements hook_feeds_processor_targets_alter().
 *
 */
function mymodule_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name) {
 
$targets['newsletter_list'] = array(
   
'name' => t('Newsletter list'),
   
'description' => t('This field sets the user to the proper newsletter list.'),
   
'callback' => 'mymodule_newsletter_list',
  );
}
?>

The code above will show a new option "Newsletter list" in the fields mapping page of the feeds ui module for our importer. Now, we need to define a callback, for this option.

<?php
/**
 * Callback for hook_feeds_processor_targets_alter.
 * Subscribes the user to the proper newsletter list.
 *
 * @param $source
 * @param $entity
 * @param $target
 * @param $value
 * @param $mapping
 */
function mymodule_newsletter_list ($source, $entity, $target, $value, $mapping) {
 
//$value contains the subscription list from the csv
 
subscribe_user(($entity->uid, $value);
}
?>

Did you like this post? Drop me a line in the comments below