formatters

Drupal 8 Field API series part 1: field formatters

The Drupal 8 cycle has entered the API freeze since the 1st of July, which means it's time to start porting modules or simply play around with the API. While there are exceptions to change the API, you can safely assume that 95% (or even more) will remain as it is today.

This is the first article which will be part of a series of changes in Field API for Drupal 8: field formatters. In case there are updates to the API, we will update the articles, but also the change records on drupal.org. Watch out for the next couple of weeks and months and hopefully you're prepared for Drupal 8 and Field API.

Plugins

Creating field formatters in Drupal 7 was done by implementing four hooks. In Drupal 8, formatters are now plugins using the new Plugin API. Hooks are replaced by methods in classes, which means that your module file will be empty if you only provide a formatter (unless you also implement one of the field formatter alter hooks). Being classes, this means that field formatters can now extend on each other. A good example in core is the image field formatter extending the file field formatter class. Discovery and class instantiation is managed by the new formatter plugin manager.

Create a file like '{your_module}/lib/Drupal/{your_module}/Plugin/field/FieldFormatter/{NameOfYourFormatter}.php. That's a lot of directories right ? Welcome to the world of PSR-0, namespaces and plugins in D8. This is most likely going to change, feel free to read, or even help along in https://drupal.org/node/1971198. Also, plugin managers can now control where plugins reside, see https://drupal.org/node/2043379, so we'll probably change this at some point.

In most cases, you will want to extend the FormatterBase class which does most of the heavy lifting for you. Following classes will usually be imported at the top of your file:

<?php
// FormatterBase class.
Drupal\Core\Field\FormatterBase;
// FieldItemInterface
use Drupal\Core\Field\FieldItemListInterface;
?>

1. hook_field_formatter_info() are now annotations

hook_field_formatter_info() is replaced by annotation-based plugin discovery, using the \Drupal\field\Annotation\FieldFormatter annotation class. As for other plugin types, the accepted properties are documented in the annotation class. Other modules can extend this by implementing hook_field_formatter_info_alter(). In core, the edit module adds the edit property so it knows which in-place editor it has to use. Note that some property names have changed since Drupal 7 (spaces replaces by underscores). This is how an annotation looks like, which is placed right above the class keyword.

<?php
/**
* Plugin implementation of the 'foo_formatter' formatter
*
* @FieldFormatter(
*   id = "foo_formatter",
*   label = @Translation("Foo formatter"),
*   field_types = {
*     "text",
*     "text_long"
*   },
*   settings = {
*     "trim_length" = "600",
*   },
*    edit = {
*      "editor" = "form"
*    }
* )
*/
class FooFormatter extends FormatterBase { }
?>

2. hook_field_formatter_settings_form() becomes FormatterInterface::settingsForm()

Next up is to create a settingsForm() method. If you have an old settings form, you can simply move the code to this method. Settings are automatically saved and can be accessed by calling $this->getSetting('settings_key');. Remember to always start with an empty $elements array and not with the $form argument from the function arguments.

<?php
 
/**
   * {@inheritdoc}
   */
 
public function settingsForm(array $form, array &$form_state) {
   
$element = array();

   
$element['trim_length'] = array(
     
'#title' => t('Trim length'),
     
'#type' => 'number',
     
'#default_value' => $this->getSetting('trim_length'),
     
'#min' => 1,
     
'#required' => TRUE,
    );

    return
$element;
  }
?>

3. hook_field_formatter_settings_summary() becomes FormatterInterface::settingsSummary()

Settings are accessed by calling $this->getSetting('settings_key');. Another change is that the summary now needs to return an array instead of a string.

<?php
 
/**
   * {@inheritdoc}
   */
 
public function settingsSummary() {
   
$summary = array();
   
$summary[] = t('Trim length: @trim_length', array('@trim_length' => $this->getSetting('trim_length')));
    return
$summary;
  }
?>

4. hook_field_formatter_prepare_view becomes FormatterInterface::prepareView() and hook_field_formatter_view() becomes FormatterInterface::viewElements()

The first method allows you to add additional information on the items, the second is where the actual formatting happens. Settings are accessed by calling $this->getSetting('settings_key');. Also, the methods now receive the field values as a \Drupal\Core\Field\FieldItemListInterface object, rather than an $items array in Drupal 7. More information can be found about Drupal 8 Entity API and the syntax around field values in the handbook. Simply put, FieldItemListInterface objects can be accessed and iterated on like an array of items keyed by delta, and properties in each item can be accessed by simple object syntax.

<?php
 
/**
   * {@inheritdoc}
   */
 
public function viewElements(FieldItemListInterface $items) {
   
$elements = array();

   
$text_processing = $this->getSetting('text_processing');
    foreach (
$items as $delta => $item) {
      if (
$this->getPluginId() == 'text_summary_or_trimmed' && !empty($item->summary)) {
       
$output = $item->summary_processed;
      }
      else {
       
$output = $item->processed;
       
$output = text_summary($output, $text_processing ? $item->format : NULL, $this->getSetting('trim_length'));
      }
     
$elements[$delta] = array('#markup' => $output);
    }

    return
$elements;
  }
?>

Alter hooks

The alter hooks are still the same for Drupal 8, with one small API change in hook_field_formatter_settings_summary_alter() which is invoked by the Field UI module. The summary is now an array of strings instead of a single string. <br/> will be automatically inserted between the strings when the summary is displayed.

<?php
/**
* Implements hook_field_formatter_settings_summary_alter().
*/
function my_module_field_formatter_settings_summary_alter(&$summary, $context) {
 
// Append a message to the summary when an instance of foo_formatter has
  // mysetting set to TRUE for the current view mode.
 
if ($context['formatter']->getPluginId() == 'foo_formatter') {
    if (
$context['formatter']->getSetting('mysetting')) {
     
$summary[] = t('My setting enabled.');
    }
  }
}
?>

The other two hooks are hook_field_formatter_info_alter() allowing you to make changes to the formatter definitions and hook_field_formatter_settings_form_alter() which is invoked from by the Field UI module when displaying the summary of the formatter settings for a field.

Resources

Conclusion

Writing and maintaining field formatters for Drupal 8 is not hard. In most cases, when porting, it's simply moving the contents of your old hooks to the methods in a class. In the next part, we will see how you write widget plugins in Drupal 8.

Introducing Field formatter conditions for Drupal

The Field formatter conditions module for Drupal allows you to add conditions and actions per field on the manage display screens of entities (nodes, users etc). For example: you can hide a field on path x. Or hide it when the current user has role 'Administrator'. The module ships with several built-in conditions and actions for common use cases we encountered during projects at work. And thanks to jpstrikesback a couple of more will be added before we hit a 1.0 release.

It's easy to write your own specific use cases for a project, consult the API or look into the code how to built a form, condition and callback yourself in a few minutes. Field API and Display Suite fields are supported, Field API's extra fields are not, and most likely neither in the future.

Rules support

It gets better though. The API is limited to the fact that a callback is both the condition and the action. But what in case you want more conditions ? That's where Rules comes into play. You can build unlimited rules with fancy conditions and then fire off actions on a specific field. Currently, the module ships with two rules actions which can hide a field or change the image style of an image formatter. The event for these rules always needs to be 'A field is rendered'. Depending on the use cases, more will be added later, but it's easy for developers to write their own actions targeted for a specific project.

See it in action

See how it works in a short screencast. Happy conditioning and a very good new year!

Limit the number of fields to display on Field UI with Display Suite

This is probably the number one feature request during the D6 cycle of Display suite: limit the number of items on a multiple value field, usually on images. This involves custom coding in the form of creating new formatters over and over again in code or using the Custom formatters module. The upcoming release of Display Suite for Drupal 7 now puts an end to this annoying limitation. All Field API fields with a cardinality set to unlimited or more than one get an extra textfield on the manage display screens to limit the output per field. I've recorded a short screencast to demonstrate that exciting new suble feature. A new release is scheduled this wednesday, so test and report any errors when found!

There are also 2 issues on d.o to get this feature into other modules:

Subscribe to RSS - formatters

You are here