Skip to content

Add related content to existing session titles

Copy plain session titles into a replacement compound field with an optional content reference. Each title keeps its outer delta; references start empty.

Check the scope

The recipe supports current default revisions of untranslated, unmoderated nodes. It refuses translations, moderation and newer non-default revisions. It creates a revision per copied node; historical revisions retain only source values. Other cases need an explicit language and revision migration.

Back up and rehearse on a copy. Stop content writers through verification. Normal entity saves run site hooks. Failure may leave earlier nodes copied; reruns skip identical copies and refuse changes to replacement values.

Create the replacement

Enable Compound Field and Field UI. This example uses Conference, machine name conference, and unlimited string field field_session_titles of maximum length 255. Match the source's length and cardinality in the replacement.

Create this compound once. The recipe needs the exact sub-field names; Field UI would add field_ prefixes.

drush php:eval '\Drupal\compound_field\Entity\CompoundField::create([
  "id" => "conference_session",
  "label" => "Conference session",
  "fields" => [
    "title" => [
      "label" => "Title",
      "field_type" => "string",
      "storage_settings" => ["max_length" => 255],
    ],
    "related" => [
      "label" => "Related content",
      "field_type" => "entity_reference",
      "required" => FALSE,
      "storage_settings" => ["target_type" => "node"],
      "settings" => ["handler" => "default:node", "handler_settings" => []],
    ],
  ],
])->save();'
  1. On Conference's Manage fields, add Conference session, label Sessions, machine name field_sessions, allowing unlimited values. Keep sub-field caps at 1.
  2. Add Sessions to Manage form display with the Compound field widget. Keep Session titles for verification.

Run the copy

From the Drupal project, run the PHP recipe. Change the three arguments for other bundle or field names. It checks all nodes before writing and verifies saved values through the field API.

drush php:eval '$copy = require DRUPAL_ROOT . "/" . \Drupal::service("extension.list.module")->getPath("compound_field") . "/docs/recipes/migrate-string.php"; printf("Copied %d nodes.\n", $copy("conference", "field_session_titles", "field_sessions"));'

Keep the source field's storage type unchanged.

Verify before switching

Each copied title has an empty reference input.

Check title count, order and empty references, including a node without titles. Select a related page, save and reopen. Configure Manage display and update Views, templates, exports and API consumers before hiding the source on forms.

Keep source storage while historical values are needed. Deleting it removes access to those values in historical revisions and eventually purges their rows.