Loading ...

How to write a custom field formatter for Drupal 8

Submitted by Tim on July 31, 2016

I was recently working on a Drupal 8 website and needed to rewrite the output of a date field for better displaying and theming purpose.

In Drupal 7, I would have done this with the Display Suite module. But in Drupal 8, I will be using the Drupal console to generate the scaffolding for me and a Twig template to control output bit of custom code to connect the dots.

Output will look like:

<div class="article-date">
  <span>{{ source.day }}</span>
  <span>{{ source.month }}</span>
</div>

Step 1

I make a module (or implement this in a custom module) that allows me to easily enable and disable my functionality.

$ drupal generate:module

Drupal console will prompt for some details. After entering them, I have my custom module.

Step 2

Creating the custom field formatter.

$ drupal generate:plugin:fieldformatter

Drupal console will prompt for some details. After entering them, I have my custom field formatter inside my custom module.

Step 3

Creating a the Twig template file (/templates/article-date.html.twig) in the custom module to control the output.

<div class="article-date">
  <span>{{ source.day }}</span>
  <span>{{ source.month }}</span>
</div>

 Step 4

Implement hook_theme() in the .module file

/**
 * Implements hook_theme().
 */
function mymodule_theme() {
  $theme = [];

  $theme['article-date'] = [
    'variables' => array(
      'source' => NULL
    ),
  ];

  return $theme;
}

Step 5

To connect the dots I add code to the viewElements() method of the formatter class.

/**
   * {@inheritdoc}
   */
  public function viewElements(FieldItemListInterface $items, $langcode) {
    $elements = [];

    $source = array();
    foreach ($items as $delta => $item) {
      // Get the date value
      $date = $item->getValue();
      // Split the date in pieces for theming.
      $date_pieces = explode('-', $date['value']);
      // Transform the numeric representation of a month into the three letters
      //representation of a month.
      switch ($date_pieces[1]) {
        case '01':
          $date_pieces[1] = 'jan';
          break;
        case '02':
          $date_pieces[1] = 'feb';
          break;
        case '03':
          $date_pieces[1] = 'mar';
          break;
        case '04':
          $date_pieces[1] = 'apr';
          break;
        case '05':
          $date_pieces[1] = 'may';
          break;
        case '06':
          $date_pieces[1] = 'jun';
          break;
        case '07':
          $date_pieces[1] = 'jul';
          break;
        case '08':
          $date_pieces[1] = 'aug';
          break;
        case '09':
          $date_pieces[1] = 'sep';
          break;
        case '10':
          $date_pieces[1] = 'oct';
          break;
        case '11':
          $date_pieces[1] = 'nov';
          break;
        case '12':
          $date_pieces[1] = 'dec';
          break;
      }

      // Prepare the variables.
      $source = array(
        'day' => $date_pieces[2],
        'month' => $date_pieces[1],
        'year' => $date_pieces[0]
      );
    }

    // Put everything in an array for theming.
    $elements[] = array(
      '#theme' => 'article-date',
      '#source' => $source,
    );

    return $elements;
  }

Step 6

Clear the caches.