Skip to main content

Drupal 8: Creating a custom field - Part 1: Field type

28th Jan 2014

Jo Fitzgerald


I have been experimenting with the Alpha release of Drupal 8 and so I'm sharing some of my experiences so that you can avoid the pitfalls I have encountered.

First I would like to give credit to the two articles I used during the exercise:

Hopefully this article will provide a third point-of-view to make your task easier.

a) Create the file

In D8 the location of files is very important. The field type must be located as follows:
N.B. The field type name should be in CamelCase.

b) Add Contains, namespace and use

In the newly created field type file add a brief comment to explain what it consists of:

/** * @file * Contains \Drupal\<module_name>\Plugin\field\field_type\<field_type_name>. */

N.B. The "Contains..." line should match the location and name of this file.

Then add the namespace as follows:

namespace Drupal\<module_name>\Plugin\field\field_type;

N.B. It is vital that the namespace matches the location of the file otherwise it will not work.

Then add the following uses:

use Drupal\field\Plugin\Type\FieldType\ConfigFieldItemBase;

This provides the class that the field item will extend.

use Drupal\field\FieldInterface;

This provides a variable type required within the field item class.

c) Add field details annotation

Annotations are an important part of Drupal 8 and must not be treated as simple comments! :o) The annotation should appear as follows:

/** * Plugin implementation of the '<field_type_name>' field type. * * @FieldType( * id = "<field_type_id>", * label = @Translation("<field_type_label>"), * description = @Translation("<field_type_description>"), * default_widget = "<field_type_default_widget>", * default_formatter = "<field_type_default_formatter>" * ) */

N.B. All text represented by a <placeholder> should be appropriately replaced according to requirements. The default_widget and default_formatter must match the ids of a widget and a formatter (see Part 2 and Part 3 of this article).

d) Add field item class

Create the field item class as follows:

class <field_type_name> extends ConfigFieldItemBase { }

N.B. The <field_type_name> must match the name of this file (case-sensitive).

The class should contain the following:

i. schema()

The schema() function defines the sub-field(s) that make up the field item. Here is an example:

/** * {@inheritdoc} */ public static function schema(FieldInterface $field) { return array( 'columns' => array( 'forename' => array( 'type' => 'varchar', 'length' => 256, 'not null' => TRUE, ), 'surname' => array( 'type' => 'varchar', 'length' => 256, 'not null' => TRUE, ), 'age' => array( 'type' => 'int', 'not null' => TRUE, ), ), ); }

ii. isEmpty()

The isEmpty() function defines what constitutes an empty field item, e.g.

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

iii. getPropertyDefinitions()

The getPropertyDefinitions() function defines the data types of the fields, e.g.

/** * {@inheritdoc} */ static $propertyDefinitions; /** * {@inheritdoc} */ public function getPropertyDefinitions() { if (!isset(static::$propertyDefinitions)) { static::$propertyDefinitions['forename'] = array( 'type' => 'string', 'label' => t('Forename'), ); static::$propertyDefinitions['surname'] = array( 'type' => 'string', 'label' => t('Surname'), ); static::$propertyDefinitions['age'] = array( 'type' => 'integer', 'label' => t('Age'), ); } return static::$propertyDefinitions; }

Here is a simple example, similar to that described above.

Click Part 2: Field widget to continue creating a custom field.