Paragraphs is a powerful Drupal module that makes gives editors more flexibility in how they design and layout the content of their pages. However, they are special in that they make no sense without a host entity. If we talk about Paragraphs, it goes without saying that they are to be attached to other entities.
In Drupal 8, individual migrations are built around an entity type. That means we implement a single migration for each entity type. Sometimes we draw relationships between the element being imported and an already imported one of a different type, but we never handle the migration of both simultaneously.
Migrating Paragraphs needs to be done in at least two steps: 1) migrating entities of type Paragraph, and 2) migrating entities referencing imported Paragraph entities.
Migration of Paragraph entities
You can migrate Paragraph entities in a way very similar to the way of migrating every other entity type into Drupal 8. However, a very important caveat is making sure to use the right destination plugin, provided by the Entity Reference Revisions module:
destination: plugin: ‘entity_reference_revisions:paragraph’ default_bundle: paragraph_type
This is critical because you can be tempted to use something more common like entity:paragraph
which would make sense given that Paragraphs are entities. However, you didn’t configure your Paragraph reference field as a conventional Entity Reference one, but as an Entity reference revisions field, so you need to use an appropriate plugin.
An example of the core of a migration of Paragraph entities:
source: plugin: url data_fetcher_plugin: http data_parser_plugin: json urls: 'feed.url/endpoint' ids: id: type: integer item_selector: '/elements' fields: - name: id label: Id selector: /element_id - name: content label: Content selector: /element_content process: field_paragraph_type_content/value: content destination: plugin: 'entity_reference_revisions:paragraph' default_bundle: paragraph_type migration_dependencies: { }
To give some context, this assumes the feed being consumed has a root level with an elements array
filled with content arrays with properties like element_id
and element_content
, and we want to convert those content arrays into Paragraphs of type paragraph_type
in Drupal, with the field_paragraph_type_content
field storing the text that came from the element_content
property.
Migration of the host entity type
Having imported the Paragraph entities already, we then need to import the host entities, attaching the appropriate Paragraphs to each one’s field_paragraph_type_content
field. Typically this is accomplished by using the migration_lookup
process plugin (formerly migration
).
Every time an entity is imported, a row is created in the mapping table for that migration, with both the ID the entity has in the external source and the internal one it got after being imported. This way the migration keeps a correlation between both states of the data, for updating and other purposes.
The migration_lookup
plugin takes an ID from an external source and tries to find an internal entity whose ID is linked to the external one in the mapping table, returning its ID in that case. After that, the entity reference field will be populated with that ID, effectively establishing a link between the entities in the Drupal side.
In the example below, the migration_lookup
returns entity IDs and creates references to other Drupal entities through the field_event_schools
field:
field_event_schools: plugin: iterator source: event_school process: target_id: plugin: migration_lookup migration: schools source: school_id
However, while references to nodes or terms basically consist of the ID of the referenced entity, when using the entity_reference_revisions
destination plugin (as we did to import the Paragraph entities), two IDs are stored per entity. One is the entity ID and the other is the entity revision ID. That means the return of the migration_lookup
processor is not an integer, but an array of them.
process: field_paragraph_type_content: plugin: iterator source: elements process: temporary_ids: plugin: migration_lookup migration: paragraphs_migration source: element_id target_id: plugin: extract source: '@temporary_ids' index: - 0 target_revision_id: plugin: extract source: '@temporary_ids' index: - 1
What we do then is, instead of just returning an array (it wouldn’t work obviously), use the extract
process plugin with it to get the integer IDs needed to create an effective reference.
Summary
In summary, it’s important to remember that migrating Paragraphs is a two-step process at minimum. First, you must migrate entities of type Paragraph. Then you must migrate entities referencing those imported Paragraph entities.
More on Drupal 8
Making the web a better place to teach, learn, and advocate starts here...
When you subscribe to our newsletter!