Custom entries in entity view modes? Background + question

I want to port entdispfieldui to Drupal 8. (issue)

The module allows a site builder to add new entries into an entity view mode, configure and position them among the regular fields. These entries exist per view mode / bundle / entity type.

I am wondering what would be the best way to achieve this in Drupal 8. Is one of the ideas below suitable? Why would I use one over the other?

Ideas so far

Idea 1: Extra fields + config entities

hook_entity_extra_field_info() allows to insert "pseudo" fields per entity bundle, but across view modes. The idea would be to use hook_form_alter() to remove the items from those view modes where they don't belong.

I found some documentation on extra fields here: https://www.webomelette.com/creating-pseudo-fields-drupal-8

Entries would be stored as config entities, with keys to determine to which view mode they belong.

For this, I started looking at https://www.drupal.org/docs/8/api/configuration-api/creating-a-configuration-entity-type-in-drupal-8

Idea 2: Learn from field_group and Display suite

field_group does something similar to what I am trying to do. Except that the entries are not pseudo fields, but groups. But still, these are entries or "things" that exist per view mode, and can be created and deleted.

But I found that field_group does not use a config entity type for this. Instead, in field_group.entity_display.schema.yml, I find this:

core.entity_view_display.*.*.*.third_party.field_group:
  type: sequence
  label: 'Field group settings on entity view'


Similar lines can be found in ds.entity_display.schema.yml or field_layout.schema.yml. Although these do not use type: sequence. I think this is because they store settings for the view mode itself, not for entries within the view mode.

So I wonder, what does the core.entity_view_display.*.*.*.third_party... mean, and why would I use this + type: sequence, instead of a config entity type?

And if I use this method, would it still make sense to work with hook_entity_extra_field_info() ?
I made it work!

There are many details to consider, so here is just a rough overview.

Storing the entries.

I decided to store the entries not in config entities, but as raw config entries. This seems easier, and prevents recursion with hook_entity_extra_field_info().

For each entry, we store:


Configuration that tells us how the item should be displayed when viewing the entity.
Optionally, an administrative label and/or a label for visitor consumption.


We do NOT store the weight (order / position between other fields). Thanks to hook_entity_extra_field_info(), Drupal will do this for us!

We do NOT store an id or machine name as a value within the entry. Instead, the machine name is part of the key referencing the config entry.

Each entry is identified by a key of the format "entdisp.vme.$entity_type_id.$bundle.$view_mode.$entry_machine_name". 

entdisp.view_mode_entry.schema.yml:

entdisp.vme.*.*.*.*:
  type: ignore


Obviously this could be more sophisticated, but it works for me.

Crud forms for add + delete

Similar to field_group module, create forms to add and delete view mode entries.

E.g. admin/structure/types/manage/article/display/full will have an action link "Add EntDisP entry" leading to admin/structure/types/manage/article/display/full/entdisp/add.

hook_entity_extra_field_info()

Register extra fields per bundle, with placeholders for the label and other settings.

/**
 * Implements hook_entity_extra_field_info().
 */
function entdisp_entity_extra_field_info() {

  $ids = \Drupal::configFactory()-&gt;listAll('entdisp.vme.');

  $fill = ['', '', '', '', '', ''];

  $defaults = [
    'label' =&gt; '_',
    'visible' =&gt; FALSE,
  ];

  $extra = [];
  foreach ($ids as $id) {
    $pieces = explode('.', $id) + $fill;
    if (in_array('', $pieces, TRUE)) {
      continue;
    }
    list(,,$entity_type_id, $bundle, $view_mode, $vme_name) = $pieces;
    // $view_mode is not used!
    $extra[$entity_type_id][$bundle]['display']['entdisp_' . $vme_name] = $defaults;
  }

  return $extra;
}


hook_form_entity_view_display_edit_form_alter()

Alter the entity_view_display_edit_form.

In $form['fields'] and in $form['#extra'], we already find one entry for each extra field that we previously registered.

For each of the entry in $form['#extra'] that begins with 'entdisp_', do the following:


Check if the a corresponding entry exists in the settings.
If not, remove the entry from $form['fields'] and from $form['#extra'].
If yes, modify the element in $form['fields'][$name], to give it a label and configuration controls. Have a look at field_group_field_ui_display_form_alter() and at EntityViewDisplayEditForm in core.


This is all a bit tricky and more work than can be explained here. But it is easier than in field_group, thanks to the trick with hook_entity_extra_field_info().

hook_entity_view()

In this hook, for each item in $display->getComponents(), we


look up the corresponding config entry.
add a render element to $build.


It can look somehow like this: https://www.webomelette.com/creating-pseudo-fields-drupal-8