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();'
- On Conference's Manage fields, add Conference session, label Sessions,
machine name
field_sessions, allowing unlimited values. Keep sub-field caps at 1. - 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¶

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.