An example defining custom field type, field widget and field formatter in Drupal 8.
An example defining custom field type, field widget and field formatter in Drupal 8.
Nothing fancy about the module definition as such, except for the fact that it would define a field. A standard info file with inc files for utility functions. Unlike Drupal 7, field types, field widgets and field formatters are defined and detected using Plugin definitions with annotations like @FieldType, @FieldWidget and @FieldFormatter respectively. Hence, we have noo hook_field_xxx() implementations in the .module file.
The first thing to do is create a FieldType plugin implementation. This class would represent a single item of the Burrito field type and hence, by convention, it has been named the BurritoItem. Notice the @FieldType part of the class documentation - that is where we have all the data which previously used to be provided by a hook_field_info() implementation.
Here is some quick info on some important methods of the class (which previously used to be hook_field_* functions):
After you define the field type, you can enable the module and attach an instance of the burrito_maker_burrito field type to any fieldable entity. We are now 33.33333% close to our objective of having our custom burrito data!
NOTE: At times, it may seem tempting to name your field only burrito instead of burrito_maker_burrito. However, it is good practice to define stuff in the namespace of your own module.
So, the database tables are ready and your field type appears in the UI. But how would the user enter data for their custom burritos? Drupal doesn't know anything about them burritos! So, we need to implement a FieldWidget plugin to let tell Drupal exactly how it should build the forms for accepting burrito data.
A default widget type for our custom burrito field has already been specified in the @FieldType declaration - the machine name being burrito_default. To define the structure of the widget, we implement BurritoDefaultWidget with the following important method:
The BurritoDefaultWidget::processToppingsFieldset() method solely exists as a helper. Its only purpose is to help flatten the user input array in such a way that the field names map to various database columns, instead of being nested under meat and toppings indexes in the POST array.
NOTE: One might think that adding the #tree attribute to these fieldsets can help flatten the fieldset's sub-fields, but it does't work that way. If you set #tree as FALSE on the fieldset, though we might expect only the fieldset to be be flattened, what actually happens is every child of the fieldset is submitted as a root element in the main form. Hence, we use the BurritoDefaultWidget::processToppingsFieldset() to do the trick.
Input checked. Storage checked. Now for presentation of data, we define the BurritoDefaultFormatter. It's main purpose is to take a list BurritoItem objects and display them (as per the field's display settings). This is done by the BurritoFormatter::viewElements() method. Rest of the methods in the Formatter are optional but quite useful for implementing certain commonly needed features. A default formatter for our custom burrito field has already been specified in the @FieldType declaration - the machine name being burrito_default.
NOTE: Documentation on other methods of the BurritoDefaultFormatter will be added soon.