How to extend an existing content feature

There will often be use cases where a developer wants to extend an existing content type by adding additional fields without requiring that those fields be added to every site. For example, the Drutopia Event module provides an event content type. Say we want to provide an optional location field for every event. How to do this?

Drutopia features have been intentionally created in a modular way trying to limit the number of dependencies between features. This means that when we want to add fields that would otherwise create dependencies, we do so in what might be called a “bridging” module—a module that bridges by adding a new field to an existing content type provided by another Drutopia module. We do this using the Config Actions module.

The Drutopia Storyline feature provides a working example that can be used as a model to follow when using this pattern. You will be creating two new modules. They can, however, be bundled into one project.

Here’s an outline of the steps to follow:

  • Start by creating and configuring the field as well as its form and view displays. In the example, our new field is field_storyline and is added to the page content type.
  • Create a new base feature (in our example drutopia_storyline).
    • This will provide the field storage for the new field.
    • Add a dependency on config_actions manually by editing the feature’s .info.yml file .
    • Edit the exported .yml file for the field storage, setting persist_with_no_fields to true.
  • Create the bridging module (in our example drutopia_page_storyline). You can add it directly to the directory of the base feature, so that they are both in the same project.
    • The field will be placed in the config/install folder.
    • Edit the .info.yml file of the exported feature to add dependencies on both the base feature (in our case, drutopia_storyline as well as the module that provides the content type you’re adding the field to (in our case, drutopia_page).
    • Manually write config actions files to add your new field to relevant configuration. Save these files to an actions folder inside the config folder. The actions will include the changes impacted by adding the new field such as the form mode and any display mode used.
    • To determine what code needs to go into the new config actions files, use Drupal core’s built-in functionality to export a single configuration item. For example, in our case, assume one of the configuration changes was to add field_storyline to the full view mode the page content type.
      • Navigate to Configuration > Development > Synchronize Configuration > Export > Single. For “Configuration type” select “Entity view display” and for “Configuration name” select “node.page.full”.
      • In the YAML markup that’s displayed, look for occurrences of the name of the field you added. In our case, this is field_storyline and they occur in two places: under dependencies.config and under content. Both of these changes need to be registered in a config actions file.
      • Create a new file, naming it for the config item you’re altering. The file name is given on the export form, below the YAML text area. In our case, the file will be named core.entity_view_display.node.page.full.yml. Rather than working up a new file from scratch, look for one you can model yours on. See the examples in Drutopia Page Storyline. From the exported YAML code, you can copy and paste in the entire section giving the configuration for your field. See the below example for drutopia_page_storyline, which includes comments.
plugin: 'add'
actions:
  # Add config dependency.
  config_dependencies:
    path: ["dependencies", "config"]
    # Edit the next line to use the name of your field.
    value: "field.field.node.page.field_storyline"
  # Add the entity form display settings.
  content:
    path: ["content"]
    value:
      # This is the portion to replace with what you copy from exported YAML.
      field_storyline:
        type: entity_reference_paragraphs
        weight: 3
        settings:
          title: Paragraph
          title_plural: Paragraphs
          edit_mode: open
          add_mode: button
          form_display_mode: default
          default_paragraph_type: storyline_header
        third_party_settings: {  }
        region: content