This guide documents the process of creating a custom entity type in Drupal 8 using the example of an Event entity type.

You can reach this guide at https://git.io/d8entity.

The starting point is a stock Drupal 8.6 core Standard installation with the contributed Entity API available at modules/entity and an empty module directory at modules/event.

Having Drush 9 available is required to follow along. When Drush commands are to be run, run them from within the Drupal installation. When PHP code is to be executed, this can be done by running drush core:cli or by creating a test script and then running drush php:script <name-of-script>.

Table of contents

  1. Using entities for data storage
    1. Create a module
    2. Create a minimal entity class
    3. Install the entity type
    4. Add field definitions
    5. Install the fields
    6. Add field methods
  2. Viewing entities on a page
    1. Install the contributed Entity API module.
    2. Add a route
    3. Configure fields for display
  3. Manipulating entities through forms
    1. Add the routes
    2. Configure fields for display
    3. Add a specialized form
  4. Listing entities
    1. Add a route
    2. Add a specialized list builder
    3. Add an administrative view
  5. Adding administrative links
    1. Add a menu link for the event listing
    2. Add a local task for the event listing
    3. Add local tasks for the edit and delete forms
  6. Adding additional fields
    1. Add the field definitions
    2. Add additional field methods
    3. Add validation constraints
    4. Implement the computed field
    5. Install the fields
  7. Tracking changes to entities
    1. Make events revisionable
  8. Storing dynamic data in configuration
    1. Create an entity class
    2. Provide a configuration schema
    3. Install the entity type
  9. Providing a user interface for configuration entities
    1. Add a list of event types
    2. Add forms for event types
  10. Categorizing different entities of the same entity type
    1. Add the bundle field
    2. Install the bundle field
  11. Configuring bundles in the user interface
    1. Enable Field UI for events
    2. Add dynamic fields to events
    3. Configure view modes
    4. Configure the form
  12. Translating content
    1. Install the Content Translation module
    2. Make events translatable
  13. Translating configuration
    1. Install the Configuration Translation module

1. Using entities for data storage

1.1. Create a module

1.2. Create a minimal entity class

Classes allow categorizing objects as being of a certain type. Event entities, that will be created below, will be instances of the entity class. In terms of code organization, classes can be used to group related functionality.

1.3. Install the entity type

Drupal can create the database schema for our entity type automatically but this needs to be done explicitly. The preferred way of doing this is with Drush.

1.4. Add field definitions

Fields are the pieces of data that make up an entity. The ID and UUID that were saved as part of the event above are examples of field values. To be able to store actual event data in our entities, we need to declare additional fields.

Just like with the ID and UUID fields above, Drupal can automatically provide Author and Published fields for us, which we will take advantage of so that we can track who created events and distinguish published and unpublished events.

1.5. Install the fields

Drupal notices changes to the entity type that affect the database schema and can update it automatically.

1.6. Add field methods

Instead of relying on the generic get() and set() methods it is recommended to add field-specific methods that wrap them. This makes interacting with events in code more convenient. Futhermore, it is recommended to add an interface

2. Viewing entities on a page

Viewing an entity on a page requires a route on which the entity's field values are output on a given path. This can be automated by amending the entity annotation.

2.1. Install the contributed Entity API module.

The contributed Entity API provides various enhancements to the core Entity API. One such enhancement is the ability to more easily provide permissions entity types which we will now use.

2.2. Add a route

2.3. Configure fields for display

Which fields to display when rendering the entity, as well as how to display them, can be configured as part of the field definitions. Fields are not displayed unless explicitly configured to.

3. Manipulating entities through forms

3.1. Add the routes

3.2. Configure fields for display

3.3. Add a specialized form

4. Listing entities

4.1. Add a route

4.2. Add a specialized list builder

4.3. Add an administrative view

While a specialized entity list builder has the benefit of being re-usable one can also take advantage of Drupal's Views module to create an administrative listing of events.

To provide a usable and integrated administration experience the different pages need to be connected and enriched with Drupal's standard administrative links.

For the event listing to show up in the toolbar menu under Content, we need to provide a menu link for it.

5.2. Add a local task for the event listing

5.3. Add local tasks for the edit and delete forms

6. Adding additional fields

Now that our basic implementation of Events is functional and usable from the user interface, we can add some more fields. This is both to recap the above chapters and to show some additional features that are often used for content entities.

6.1. Add the field definitions

6.2. Add additional field methods

6.3. Add validation constraints

6.4. Implement the computed field

6.5. Install the fields

The event entities are feature complete for our purposes as of now.

7. Tracking changes to entities

Drupal provides a mechanism to track changes of entities by storing a new revision of an entity each time it is saved.

7.1. Make events revisionable

7.2. Add a user interface for managing revisions

8. Storing dynamic data in configuration

Apart from content entities there is a second type of entities in Drupal, the configuration entities. These have a machine-readable string ID and can be deployed between different environments along with the rest of the site configuration.

8.1. Create an entity class

While there are some distinctions, creating a configuration entity type is very similar to creating a content entity type.

8.2. Provide a configuration schema

To ensure that the structure of each configuration object is correct, a schema is provided. When importing configuration from another environment, each configuration object is validated against this schema.

8.3. Install the entity type

9. Providing a user interface for configuration entities

9.1. Add a list of event types

9.2. Add forms for event types

In contrast to content entities, configuration entities do not have the ability to use widgets for their forms, so we need to provide the respective form elements ourselves.

10. Categorizing different entities of the same entity type

Drupal provides a mechanism to distinguish content entities of the same type and attach different behavior to the entities based on this distinction. In the case of event entities, for example, it allows events to have different behavior based on the type of event they are. The nomenclature is that entity types can have bundles where each entity of that entity type belongs to a certain bundle.

Generally a configuration entity type is used to provide the bundles for a content entity type. In this case each Event type entity will be a bundle for the Event entity type.

10.1. Add the bundle field

Like for the id and uuid fields, the field definition for the type field is automatically generated by ContentEntityBase::baseFieldDefinitions().

10.2. Install the bundle field

11. Configuring bundles in the user interface

11.1. Enable Field UI for events

11.2. Add dynamic fields to events

The ability to have comments is managed as a field in Drupal, so we can use Field UI to add a Comments field to an event type.

11.3. Configure view modes

11.4. Configure the form

12. Translating content

Content entities can be made translatable in the storage by amending the entity type annotation. However, this by itself does not make the content entity translatable in the user interface. It only allows site builders to make it translatable in the user interface with the Content Translation module.

12.1. Install the Content Translation module

12.2. Make events translatable

13. Translating configuration

13.1. Install the Configuration Translation module