Author image
Senior Developer

Creating new field formatters in Drupal 7

Creating extra field formatters in Drupal 7 is fairly simple, but it can take some poking around in the new Fields code. So here is some sample code to make it easier for you! You can add formats to your own fields -- or existing fields that are defined by other Drupal modules. This is the case for the following example - a formatter for a link field to display the URL as an absolute URL.

First, implement hook_field_formatter_info() to declare your field formatter to the fields API, and implement hook_field_formatter_view() which tells Drupal what to do when viewing the field using your formatter.

/**
* Implements hook_field_formatter_info().
*/
function MYMODULE_field_formatter_info() {
  return array(
    // the key must be unique, so it's best to prefix with your module's name.
    'MYMODULE_absolute_url' => array(
      // the label is is what is displayed in the select box in the UI.
      'label' => t('Absolute URL, as plain text'),
      // field types is the important bit!! List the field types your formatter is for.
      'field types' => array('link_field'),
      // You can usually leave 'multiple values' as follows:
      'multiple values' => FIELD_BEHAVIOR_DEFAULT,
    ),
  );
}

/**
* Implements hook_field_formatter_view(). This code just passes straight
* through to a theme function, MYMODULE_formatter_FORMATTER
* (e.g. MYMODULE_formatter_MYMODULE_absolute_url).
*/
function MYMODULE_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  $elements = array();
  foreach ($items as $delta => $item) {
    $elements[$delta] = array(
      '#markup' => theme('MYMODULE_formatter_'. $display['type'], array('element' => $item, 'field' => $instance)),
    );
  }
  return $elements;
}

So in this case, we just pass straight through to a theme function, which is probably what you'll want to do in most cases. Alternatively, you could do some processing of the field first, or even pass through to the field's default theme/formatting function after doing some processing on the element. But for this example, let's just go straight to a theme function...

/**
* Implements hook_theme().
*/
function MYMODULE_theme() {
  return array(
    // The theme function that our formatter uses:
    'MYMODULE_formatter_MYMODULE_absolute_url' => array(
      // Don't forget that all Drupal 7 theme functions have only one argument,
      // so you declare what variables get passed within that argument instead.
      // See http://drupal.org/node/224333#theme_changes
      'variables' => array('element' => NULL),
    ),
  );
}

/**
* Theme function for 'MYMODULE_absolute_url' link field formatter.
*/
function theme_MYMODULE_formatter_MYMODULE_absolute_url($element) {
  // This code is specific to the Link field. It is based on theme_link_formatter_plain().
  return empty($element['element']['url']) ? check_plain($element['element']['title']) : url($element['element']['url'], array('absolute' => TRUE, 'attributes' => $element['element']['attributes']));
}

(Replace 'MYMODULE' in the code snippets with your module's name.)

That should get you started. The new field API in Drupal 7 is brilliant, hopefully this will be useful to you if you want to use existing fields but format them differently.

For a much more detailed guide to field formatters in Drupal 7, see How to create a custom field for Drupal 7: field formatter

Comments

Thanks for this intro, James :-)

A couple remarks :
The 'multiple values' => FIELD_BEHAVIOR_DEFAULT' part CKK D6 stuff, and is not needed anymore (has no effect).
In CCK D6, there was a distinction between formatters that handle one single value and get called iteratively (most frequent case) and those that handled all multiple values in one piece of markup (e.g points on a map, advanced JS image slideshow...). This does not apply in D7 anymore. All formatters iterate on values themselves.

- Most formatters shouldn't need a theme function, especially if they only involve 'massaging the raw values into a displayable string' (with no markup). Going through a theme function makes more complex code, and adds CPU overhead (a formatter can be called 100s of times on a listing page).

If they do, though, I'd recommend using #theme rather than #markup, so that the render array stays alter-friendly, instead of a precomputed HTML string - that's the whole point of render arrays :-)

- side note : leaving string sanitization in the theme layer is not recommended practice ;-). Belongs to a preprocessor.
But that's probably more a remark for the link.module ?

Comments on this article are now closed, if you want to give us feeback you can use our contact form instead.