Sometimes it is necessary to add extra information in our entities to migrate the content to Drupal 8.
Let’s say that I want to migrate the articles content type from Drupal 7 to Drupal 8 and as part of that I want to migrate the tags with my articles.
There are two options:
- Create a new migration for the taxonomy terms and later link them using the
migration_lookup
plugin. - Make the article migration check to see if the terms exist already and if not then create them.
I will go with option two in this example. To do that I’m going to use the Migrate Plus module, which provides some handy plugins such as entity_generate.
The entity_generate process plugin
receives a value and checks if there is an entity with that name. If the term exists then it uses it and if it does not then creates it (which is precisely what I need).
So, here is a snippet of the article migration YAML file using the entity_generate
plugin:
id: blog
migration_group: Drupal
label: Blog
source:
plugin: d7_node
node_type: blog
destination:
plugin: entity:node
process:
status: status
created: created
field_tags:
plugin: sub_process
source: field_tags
process:
target_id:
- plugin: entity_generate
source: name
value_key: name
bundle_key: vid
bundle: tags
entity_type: taxonomy_term
ignore_case: true
…
In our field_tags
field we are using the Drupal 7 field_tags
Values We are going to read the entities and pass that value into the entity_generate
plugin to create the entities. In this example, there is a problem, the d7_node
migrate plugin (included in the migrate module) provides the taxonomy terms IDs and this will make the entity_generate plugin to create some taxonomy terms using the IDs as the term names, and this is not what we want.
So what I need to do is to get from somewhere the terms names, not their ids, to do that I need to add an extra source property
.
First, we need to create a new custom module and in there create a source plugin which extends the Node
process plugin, something like this (let's say that our custom module’s name is my_migration):
Create the file:
my_migration/src/Plugin/migrate/source/MyNode.php
And the file should contain this code:
namespace Drupal\my_migration\Plugin\migrate\source;
use Drupal\migrate\Row;
use Drupal\node\Plugin\migrate\source\d7\Node;
/**
* Adds a source property with the taxonomy term names.
*
* @MigrateSource(
* id = “my_node",
* source_module = "node"
* )
*/
class MyNode extends Node {
public function prepareRow(Row $row) {
$nid = $row->getSourceProperty('nid');
// Get the taxonomy tags names.
$tags = $this->getFieldValues('node', 'field_tags', $nid);
$names = [];
foreach ($tags as $tag) {
$tids[] = $tag['tid'];
}
if (!$tids) {
$names = [];
}
else {
$query = $this->select('taxonomy_term_data', 't');
$query->condition('tid', $tids, 'IN');
$query->addField('t', 'name');
$result = $query->execute()->fetchCol();
$names[] = ['name' => $result['name']];
foreach ($result as $term_name) {
$names[] = ['name' => $term_name];
}
}
$row->setSourceProperty('field_tags_names', $names);
return parent::prepareRow($row);
}
}
It does the following things:
- It reads the nid of the article
- Gets all the terms IDs of the field_tags field
- For each ID, it gets the name of the term and put it in the `names` array
- Finally, it sets this value inside the $row using the `setsourceProperty` method.
Now our rows will have a property called fields_tags_names with the terms names, and we can pass this data to the entity_generate
plugin.
We need to make a few adjustments in our initial migration file, first and most important update the source plugin to use our new source plugin:
source:
plugin: my_node
…
And update the source in the field_tags
field to use the new field_tags_names
source property.
…
field_tags:
plugin: sub_process
source: field_tags_names
….
The final migration file looks like this:
id: blog
migration_group: Drupal
label: Blog
source:
plugin: my_node
node_type: blog
destination:
plugin: entity:node
process:
status: status
created: created
field_tags:
plugin: sub_process
source: field_tags_names
process:
target_id:
- plugin: entity_generate
source: name
value_key: name
bundle_key: vid
bundle: tags
entity_type: taxonomy_term
ignore_case: true
…
And that’s it; if we run the migration, it will create on the fly the terms if they do not exist and use them if they do exist.
Comments
2019 November 16
Sia
Thank you very much for this…
Thank you very much for this! Great walkthrough.
I had to remove
above the foreach, it was adding an empty first value to the names array causing failure due to an empty name.
Add new comment