Creating a Drupal Field Group Programmatically

How to create a Drupal field group programatically in Drupal 8, 9, 10, etc.

While working on adding a new module to the LocalGov Drupal distribution, I came across an interesting dilemma. I was adding a new module that creates some fields (Irish service type, Irish service id, Irish service ...)  on an existing content type (services content type). This would mean that if anyone council in Ireland installed my module, they would automatically have a listing of all services that their council provides (via the Irish LocalGov Services API).

Once I was finished creating my fields, facets, views, etc I created some field groups to group the Irish fields together on the 'Manage Form Display' page, then exported my config. Next when I tried to import the config on a new install of the site, it wouldn't import because there was already values in the database from LocalGov Drupal core for the services 'Manage Form' display. Simple fix: put my config into /config/optional instead of config/install in my module, and then rebuild the site. This time the config did import, except I couldn't see any of the fields on my /node/add/service node creation form? Reason - since there was already config for the form display in the active config, Drupal ignored my config for the same item in /config/optional. But ... the fields were there in the database - created via the field.field.field_name.yml files that were imported.

That when I realised that I was missing two things:

  1. Place the fields on the manage form display page (they were currently in the 'Disabled' region), and
  2. Place the "Irish Council Services" vertical tab on the manage form display page (I couldn't see it anywhere).

The first item wasn't too difficult since the fields already existed. But the second was very tricky to figure out (at least for my small brain), because the vertical tab hadn't been created since the config that would create it had been passed over by Drupal.

To get around this, I needed to create the vertical tab programmatically in hook_install() when the module was being installed. Turns out, it's pretty easy, but no amount of searching on Google turned up any results. Thanks to Ekes on the LocalGov Drupal Slack for some pointers. Here's the code I used (I needed this to apply to 3 content types, hence the foreach loop):

 * Implements hook_install().
function localgov_irish_service_catalogue_install() {
  // Since the core.entity_form_display.yml file already has a value in the DB for the services 
  // content types, it does not get imported a second time on install. This means our tabs for 
  // the 'Manage Form Display' page need to be created manually.
  $bundles = [

  foreach ($bundles as $bundle) {
    $group_irish_services = new stdClass;
    $group_irish_services->group_name = 'group_irish_service_catalogue';
    $group_irish_services->context = 'form';
    $group_irish_services->entity_type = 'node';
    $group_irish_services->bundle = $bundle;
    $group_irish_services->mode = 'default';
    $group_irish_services->label = 'Irish Service Catalogue';
    $group_irish_services->region = 'content';
    $group_irish_services->parent_name = 'group_tabs';
    $group_irish_services->weight = '100';
    $group_irish_services->children = [
    $group_irish_services->format_type = 'tab';
    $group_irish_services->format_settings = [
      'classes' => '',
      'show_empty_fields' => false,
      'id' => '',
      'formatter' => 'closed',
      'description' => '',
      'required_fields' => true,


Filed Under:

  1. Drupal Planet
  2. Drupal
  3. PHP