logo

Extra Block Types (EBT) - Nieuwe Layout Builder ervaring❗

Extra Block Types (EBT) - gestileerde, aanpasbare bloktypes: Slideshows, Tabs, Cards, Accordions en vele andere. Ingebouwde instellingen voor achtergrond, DOM Box, javascript-plugins. Ervaar vandaag al de toekomst van layout building.

Demo EBT-modules Download EBT-modules

❗Extra Paragraph Types (EPT) - Nieuwe Paragraphs ervaring

Extra Paragraph Types (EPT) - analoge op paragrafen gebaseerde set modules.

Demo EPT-modules Download EPT-modules

Scroll
04/10/2025, by Ivan

Menu

Deze tutorial werd oorspronkelijk gepubliceerd op Web Wash. Maar Berdir vroeg of ik de tutorial hier kon plaatsen, dus hier is hij.

De module in Drupal 7 liet toe om codevoorbeelden/snippets op te slaan in een veld. Hij kwam met een aangepast veld genaamd “Snippets field” en toonde drie formulierelementen: beschrijving, broncode en syntax highlighting-modus (welke programmeertaal).

Maar nu is het tijd om de module te upgraden naar Drupal 8.

In deze les laat ik je zien hoe ik een “basis” custom veld in Drupal 8 heb aangemaakt. Ik zal niet te diep ingaan op PSR-4, annotaties of plugins, anders wordt deze les enorm lang.

In plaats daarvan voeg ik links toe naar andere sites die dit concept verder uitleggen.

Als je op zoek bent naar gedetailleerde documentatie over de Field API in Drupal 8, bekijk dan deze reeksen:

 

In Drupal 8 worden velden niet geïmplementeerd met hooks zoals in Drupal 7. In plaats daarvan worden ze gemaakt met behulp van de nieuwe Drupal 8 Plugin API. Dit betekent dat we in plaats van hooks te implementeren klassen definiëren voor de widget, formatter en field item. De meeste Drupal 7-hooks zoals hook_field_schema, hook_field_is_empty en anderen; zijn nu methodes in klassen.

Stap 1: Implementatie van het field item

Het eerste wat we moeten doen, is een field item-klasse definiëren genaamd SnippetsItem, die de klasse FieldItemBase uitbreidt.

1. In Drupal 8 worden klassen geladen met PSR-4.

Om dus de SnippetsItem-klasse te definiëren, moeten we een bestand SnippetsItem.php maken en het plaatsen in “module” /src/Plugin/Field/FieldType/SnippetsItem.php

/**
 * @file
 * Contains \Drupal\snippets\Plugin\Field\FieldType\SnippetsItem.
 */

namespace Drupal\snippets\Plugin\Field\FieldType;

use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\TypedData\DataDefinition;

Daarna voegen we de namespace Drupal\snippets\Plugin\Field\FieldType toe en drie use-statements:

  • Drupal\Core\Field\FieldItemBase,
  • Drupal\Core\Field\FieldStorageDefinitionInterface
  • Drupal\Core\TypedData\DataDefinition.

2. Nu moeten we de details van het veld definiëren zoals veld-ID, label, standaard widget, formatter enzovoort. Dit is het equivalent van hook_field_info in Drupal 7.

In Drupal 8 zijn veel, zo niet alle, informatiehooks vervangen door annotaties.

/**
 * Plugin implementation of the 'snippets' field type.
 *
 * @FieldType(
 *   id = "snippets_code",
 *   label = @Translation("Snippets field"),
 *   description = @Translation("This field stores code snippets in the database."),
 *   default_widget = "snippets_default",
 *   default_formatter = "snippets_default"
 * )
 */
class SnippetsItem extends FieldItemBase { }

Dus in plaats van hook_field_info te implementeren, definiëren we het veld als een annotatie in de docblock boven de klasse.

De attributen in de annotatie spreken voor zich. Zorg er alleen voor dat default_widget en default_formatter verwijzen naar het ID van de widget- en formatter-annotatie, niet naar de klasse.

Als je meer wilt weten over annotaties, bekijk dan de documentatiepagina over annotation-based plugins op drupal.org.

3. Nu de field item-klasse er is, moeten we enkele methodes definiëren. De eerste is schema().

In Drupal 7 definieerde je de schema met hook_field_schema. In Drupal 8 doen we dit door de methode schema() toe te voegen in de SnippetsItem-klasse.

Schema API-documentatie bevat een overzicht van de structuur van het schema-array en mogelijke waarden.

/**
 * {@inheritdoc}
 */
public static function schema(FieldStorageDefinitionInterface $field) {
  return array(
    'columns' => array(
      'source_description' => array(
        'type' => 'varchar',
        'length' => 256,
        'not null' => FALSE,
      ),
      'source_code' => array(
        'type' => 'text',
        'size' => 'big',
        'not null' => FALSE,
      ),
      'source_lang' => array(
        'type' => 'varchar',
        'length' => 256,
        'not null' => FALSE,
      ),
    ),
  );
}

4. Vervolgens moeten we de methode isEmpty() toevoegen en bepalen wat een leeg field item is. Dit komt overeen met hook_field_is_empty in Drupal 7.

/**
 * {@inheritdoc}
 */
public function isEmpty() {
  $value = $this->get('source_code')->getValue();
  return $value === NULL || $value === '';
}

5. De laatste methode die we toevoegen is propertyDefinitions().

/**
 * {@inheritdoc}
 */
static $propertyDefinitions;

/**
 * {@inheritdoc}
 */
public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
    $properties['source_description'] = DataDefinition::create('string')
      ->setLabel(t('Snippet description'));

    $properties['source_code'] = DataDefinition::create('string')
      ->setLabel(t('Snippet code'));

    $properties['source_lang'] = DataDefinition::create('string')
      ->setLabel(t('Programming Language'))
      ->setDescription(t('Snippet code language'));

    return $properties;
  }

Deze methode definieert de datatypes die bestaan in de field values. Het “Snippets field” heeft drie waarden: beschrijving, code en taal. Daarom heb ik deze drie waarden toegevoegd als strings.

Voor meer info, bekijk hoe de Entity API de Typed Data API implementeert op drupal.org.

Klik hier om het volledige bestand te zien. Let op: het moet nog geüpdatet worden naar de PSR-4-specificatie, zie https://www.drupal.org/node/2128865 voor meer info.

Stap 2: Implementatie van de field widget

Nu we het field item hebben, maken we de field widget. Hiervoor maken we een klasse SnippetsDefaultWidget die de WidgetBase uitbreidt.

1. Maak het bestand SnippetsDefaultWidget.php en plaats het in “module” /src/Plugin/Field/FieldWidget/SnippetsDefaultWidget.php.

/**
 * @file
 * Contains \Drupal\snippets\Plugin\Field\FieldWidget\SnippetsDefaultWidget.
 */

namespace Drupal\snippets\Plugin\Field\FieldWidget;

use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Form\FormStateInterface;

De namespace moet zijn Drupal\snippets\Plugin\Field\FieldWidget en voeg de volgende use-statements toe:

  • Drupal\Core\Field\FieldItemListInterface
  • Drupal\Core\Field\WidgetBase
  • Drupal\Core\Form\FormStateInterface

2. Definieer de widget met een annotatie. Dit is gelijk aan hook_field_widget_info in Drupal 7.

/**
 * Plugin implementation of the 'snippets_default' widget.
 *
 * @FieldWidget(
 *   id = "snippets_default",
 *   label = @Translation("Snippets default"),
 *   field_types = {
 *     "snippets_code"
 *   }
 * )
 */
class SnippetsDefaultWidget extends WidgetBase { }

Let erop dat het attribuut field_types verwijst naar de veldtypes via hun ID. Voor dit veld is dat snippets_code, omdat we id = "snippets_code" hebben toegevoegd in de @FieldType-annotatie.

3. Tot slot definiëren we de formElement()-methode. Dit komt overeen met hook_field_widget_form in Drupal 7.

/**
 * {@inheritdoc}
 */
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {

  $element['source_description'] = array(
        '#title' => $this->t('Description'),
        '#type' => 'textfield',
        '#default_value' => isset($items[$delta]->source_description) ? $items[$delta]->source_description : NULL,
      );
  $element['source_code'] = array(
        '#title' => $this->t('Code'),
        '#type' => 'textarea',
        '#default_value' => isset($items[$delta]->source_code) ? $items[$delta]->source_code : NULL,
      );
  $element['source_lang'] = array(
        '#title' => $this->t('Source language'),
        '#type' => 'textfield',
        '#default_value' => isset($items[$delta]->source_lang) ? $items[$delta]->source_lang : NULL,
      );
  return $element;
}

Klik hier om het volledige bestand te bekijken. Let op: moet nog worden geüpdatet naar PSR-4, zie https://www.drupal.org/node/2128865.

Stap 3: Implementatie van de field formatter

Het laatste onderdeel is de field formatter. We maken een klasse SnippetsDefaultFormatter die FormatterBase uitbreidt.

1. Maak het bestand SnippetsDefaultFormatter.php en plaats het in “module” /src/Plugin/Field/FieldFormatter/SnippetsDefaultFormatter.php.

/**
 * @file
 * Contains \Drupal\snippets\Plugin\field\formatter\SnippetsDefaultFormatter.
 */

namespace Drupal\snippets\Plugin\Field\FieldFormatter;

use Drupal\Core\Field\FormatterBase;
use Drupal\Core\Field\FieldItemListInterface;

Namespace: Drupal\snippets\Plugin\Field\FieldFormatter en voeg de volgende use-statements toe: Drupal\Core\Field\FieldItemListInterface en Drupal\Core\Field\FormatterBase.

2. Definieer de formatter als annotatie. Dit is gelijk aan hook_field_formatter_info in Drupal 7.

/**
 * Plugin implementation of the 'snippets_default' formatter.
 *
 * @FieldFormatter(
 *   id = "snippets_default",
 *   label = @Translation("Snippets default"),
 *   field_types = {
 *     "snippets_code"
 *   }
 * )
 */
class SnippetsDefaultFormatter extends FormatterBase { }

3. Voeg de viewElements()-methode toe en definieer hoe de field values gerenderd worden. Dit is gelijk aan hook_field_formatter_view in Drupal 7.

/**
 * {@inheritdoc}
 */
public function viewElements(FieldItemListInterface $items, $langcode) {
  $elements = array();
  foreach ($items as $delta => $item) {
    // Render output using snippets_default theme.
    $source = array(
      '#theme' => 'snippets_default',
      '#source_description' => $item->source_description,
      '#source_code' => $item->source_code,
    );
    
    $elements[$delta] = array('#markup' => drupal_render($source));
  }

  return $elements;
}

Merk op dat ik een custom thema snippets_default gebruik om de snippet weer te geven vóór de formattering.

De reden hiervoor is dat ik niet te veel logica of HTML in de methode viewElements() wilde stoppen.

Klik hier om het volledige bestand te zien. Let op: moet nog geüpdatet worden naar PSR-4, zie https://www.drupal.org/node/2128865.

Conclusie

Zoals eerder gezegd, de grootste verandering in Drupal 8 is dat velden worden gemaakt met de Plugin API in plaats van hooks. Zodra je dat begrijpt, lijkt het concept van veldcreatie erg op Drupal 7. Veel methodes in Drupal 8 komen overeen met hooks in Drupal 7.

Als je de snippets module wilt testen, download dan de 8.x-dev release en probeer hem uit.