How to create a custom feeds tamper plugin

18. November 2011 - Mikael Kundert

It is very common that sometimes when you import content from a file (eg. CSV or XML file) which is provided by someone else, you are not pleased with the format. You might see many inconsistency values which obviously would need some improvements in order to have a clean import.

That is when Feeds Tamper module comes to save your task. It comes with multiple plugins which manipulates values before mapping them. That gives great power for site builders to have clean feeds imports with consistent values.

However, sometimes you will not find your plugin to do something you want and that is why I write you how to write your custom plugin for feeds tamper.

Lets use products as a real-life example. I have an CSV file which contains product's EAN code, product ID, title and color. I find out that CSV file has inconsistency on product ID's where some of them are prefixed with zeros and some of them are not.

products.csv

product id;product ean;product title;product color
001;123456;Black mug;Black
002;123457;Grey mug;grey
3;123458;Green mug;Green
04;123459;Drupal T-shirt;White, Blue
05;;Mystery product;
10;1234510;iPad;
999;1234511;Audi TT Coupé;

Product ID's appear to be three digit numbers prefixed by zeros. We would like to have products imported with consistent ID's so we want to make sure that they have ID's like '001', '003', '003', '010' and '999', etc.

When I wrote this custom plugin first time (before 7.x-1.0-beta3) there were no plugin for pad strings so I wrote my own plugin. That's the one I'm going to use now in this example.

Feeds Tamper uses ctools plugin system to let other modules determine their tamper plugins. To let Feeds Tamper module know about our new plugin we need to implement hook_ctools_plugin_directory() to tell ctools that our tamper plugins are found in a specified path. In this case that would be 'custom_plugins/'.

example_tamper_plugin/example_tamper_plugin.module
<?php
function example_tamper_plugin_ctools_plugin_directory($owner, $plugin_type) {
  if ($owner == 'feeds_tamper' && $plugin_type == 'plugins') {
    return 'custom_plugins/';
  }
}
?>

Next step is to describe our plugin so Feeds Tamper knows what to call in certain events. You do that by creating a PHP file into the plugins directory and determining $plugin variable as follow:

example_tamper_plugin/custom_plugins/example_str_pad.inc
<?php
$plugin = array(
  'form' => 'example_tamper_plugin_str_pad_form',
  'callback' => 'example_tamper_plugin_str_pad_callback',
  'name' => 'Custom pad',
);
?>

form - is the function name which gets called when feeds tamper look for plugin settings
callback - is the function name where the actual magic happens
name - obviously, the name of the plugin

Now lets implement settings form for our plugin. The whole magic will happen using str_pad() function so we will take look for all available parameters and figure out settings from those. Length will be required setting and optional settings could be string and type. Length tells how long the string should be at least. String is the character which will be used to complete the string length when string length condition is not met. Type tells which side it will fill the string.

example_tamper_plugin/custom_plugins/example_str_pad.inc
<?php
function example_tamper_plugin_str_pad_form($importer, $element_key, $settings) {
  $form = array();
  $form['length'] = array(
    '#type' => 'textfield',
    '#title' => t('Length'),
    '#description' => t('If the value of length is negative, less than, or equal to the length of the input string, no padding takes place.'),
    '#default_value' => isset($settings['length']) ? $settings['length'] : '',
    '#size' => 4,
    '#required' => TRUE,
  );
  $form['string'] = array(
    '#type' => 'textfield',
    '#title' => t('String'),
    '#size' => 10,
    '#description' => t('The string may be truncated if the required number of padding characters can\'t be evenly divided by the string\'s length.'),
    '#default_value' => isset($settings['string']) ? $settings['string'] : ' ',
  );
  $form['type'] = array(
    '#type' => 'radios',
    '#title' => t('Type'),
    '#options' => array(STR_PAD_RIGHT => t('Right'), STR_PAD_LEFT => t('Left'), STR_PAD_BOTH => t('Both')),
    '#default_value' => isset($settings['type']) ? $settings['type'] : STR_PAD_RIGHT,
  );
  return $form;
}
?>

If you would now clear your caches you should already have your plugin listed in the dropdown list of available plugins.

View of custom pad plugin settings form.

Next step is to implement the actual callback function which gets called when feeds tamper deals with the import. Feeds Tamper will take action when hook_feeds_after_parse() is invoked. It looks for enabled plugins for each element and then call the callback functions. We have determined the callback function to be example_tamper_plugin_str_pad_callback so lets implement that.

example_tamper_plugin/custom_plugins/example_str_pad.inc
<?php
function example_tamper_plugin_str_pad_callback($result, $item_key, $element_key, &$field, $settings) {
  $type = isset($settings['type']) && in_array($settings['type'], array(STR_PAD_RIGHT, STR_PAD_LEFT, STR_PAD_BOTH)) ? $settings['type'] : STR_PAD_RIGHT;
  $field = str_pad($field, intval($settings['length']), $type);
}
?>
Not that bad, huh? $field is the value which was parsed by feeds and since it's passed as reference, you just edit the value and that's all. You'll get $settings to use your settings you earlier implemented.

Next post

Taking care of Latvian Drupal community

Read More »

Comments

Mikael Kundert's picture

30. December 2011 - 12:35 - Mikael Kundert

Hi Martijn!
Sorry for late answer.

I see you're trying to generate tiny URLs on import. You also could maybe try to generate the URLs when displaying the items instead on import. I haven't tried Shorten URLs module but it may suit your needs.

However, if I would try to do it by feeds tamper plugin, I would try to find an API module which shortens URLs or try to code one myself. Short URL module would be great option, but sadly it's not ported to Drupal 7.

Together with API module you could write your callback function which shortens the URLs for you.

Add new comment