Drupal 8 Content Entity Bundles – Part 2: Most Simple Entity with Bundles

Series Parts:

Quick confession: This is actually not the “most” simple version of a custom entity. You don’t necessarily need a to provide a custom permission. You could instead use an existing permission. Additionally, all of the annotations shown in the following example don’t need to be stated explicitly (especially handlers[form]), as they will automatically use the default core values when not present. I choose to specify each annotation to help me better understand what is going on.

Now, let’s create an extremely simple custom entity that is fieldable and has bundles. To do so, we’re going to need a few things:

The Plan

  • Custom permission – Alternatively, you could use an existing Drupal permission.
  • Content Entity – In this case, named “Most Simple”.
  • Config Schema – Details how the config entity is stored within the database.
  • Config Entity – In this case, named “Most Simple Type”.
  • Config Entity Form – Custom default/add/edit form for the Config Entity.

The Code


This is pretty straight forward. Just create MODULENAME.permissions.yml file in the module and provide a new permission.

Config Schema

Create the config/MODULENAME.schema.yml file within the module, and define the details for our Config Entity.

Content Entity

Besides annotations, you might be surprised how little PHP code it takes to create a very simple Content Entity. That is because of the magic that happens behind the scenes. Take a look.

The Magic of ContentEntityBase

Aside from the annotation this file only has 3 lines of PHP. A namespace for this class, the import for the extending the ContentEntityBase class, and the custom class definition itself. But due to extending the ContentEntityBase, there is much more going on in the background when this class is instantiated.

Installation – On installation of the module containing this entity, the base_table will be created and the class’s “Base Fields” will define the columns for that table. But if you read closely, you’ll notice that we didn’t define anything in the annotation called “base fields”… so where are they coming from?

Base Field Definitions – The parent class ContentEntityBase has a static method named baseFieldDefinitions that is called at various times throughout Drupal core. Inside this method, it automatically looks for specific entity_keys and added them as base fields.

Entity Keys ContentEntityBase will automatically create field definitions for:

  • id
  • uuid
  • revision
  • langcode
  • bundle

You can also override the baseFieldDefinitions method in your own class to provide additional base fields. I’ll do this in a later example.

Config Entity

Creating a very simple Config Entity also requires very little PHP. Most of the work is done by Drupal parsing the annotation.

The main differences to note between this Config Entity and the previous Content Entity are the new annotation properties (described in the examples at the top of this post), and the new form handlers. For a Config Entity, you’ll need to provide a custom class for the form handlers (explained below).

The Magic of ConfigEntityBundleBase

Unlike the ContentEntityBase, the ConfigEntityBundleBase does not have a constructor that provides a lot of behind the scenes magic. Most of the methods in this base class are related to operations that are performed on the entity, such as the preSave() and postSave() methods.

Config Entity Form

As previously mentioned, we need to create our own form class for Config Entities. The reason for this is because ConfigEntityBundleBase does not magically turn our entity_keys into fields.

If you haven’t created a custom form for the config entity and you go to create an entity through the UI, there will be no fields in which to provide values for our entity_keys and the form will not save.

In the custom Config Entity Form we define two methods; form() and save(). The form method simply provides fields for the entity_keys defined in the annotation, and the save method simply saves the entity and redirects the user with a message.


That’s it! We now have a very simple Content Entity that has Bundles! Unfortunately, the user experience for managing these entities is terrible.

? Problems:

  • No navigation. You must browse directly to the entity management URLs
  • Few messages telling us what happened. The only message we’ve created is when saving the Config Entity.
  • Few redirects dealing entities. The only redirect we’ve created is when saving the Config Entity
  • No practical information on the entity lists. If you were to navigate to the “collection” routes for these entities, all you would see is a list of operations for each entity. You can’t even tell which entity is which. We’ll fix this in the next example by adding ListBuilders to our module.

Luckily, most of these problems are pretty easy to fix…

Next – Part 3: Simple Content Entity with Bundles


1 Thoughts


May 16, 2018

This has been enormously helpful, and one of the only walkthroughs I could find about custom content entities with bundles. As of version 8.5, the drupal_set_message function has been deprecated. I’m trying my hand at dependency injection to use the Messenger service. That seems, to my very newbie and inexperienced eyes, the new way to display messages. The most_simple module works without issue in my installation. However, in my custom module, it generates a white screen with the error message that an error has been encountered – when trying to add a new content entity. (Not an entity type) I will keep plugging along to see if I can figure out what I’m doing wrong, but I wanted to let you know in case you wanted to update this code. Thank you again. I REALLY appreciate all of the work that you put into this.

Leave a Reply

Your email address will not be published. Required fields are marked *