Transforming Data in a Drupal 8 Migration, Step-by-Step

We’re wrapping up our first Drupal 8 project here at Advomatic, and Jim and I have been tasked with implementing a content migration from the client’s existing Drupal 6 site.

My first migration job was to write a plugin which rewrites image assist tags in node body fields as regular HTML image tags. Fortunately, lots of smart people had already solved this problem for Drupal 6 to Drupal 7 migrations (I adapted my plugin from Olle Jonsson’s script on Github), so the biggest hurdle was learning how to implement this thing in Drupal 8.

This is the true story of how we made it work.

Note: You’ll need to use Drush 8 for working with Drupal 8. I’d recommend following Karen Stevenson’s great tutorial from the Lullabot blog to help set up multiple versions of Drush on your system.

Initial setup

When we first ran our migrations, a few months ago, we needed specific checkouts from dev branches of core and migrate modules. However, as of our final migration run yesterday (10/6/15), we were able to use:

Enable those modules and their dependencies, then set up your own custom module for your plugin code. The very cool Drupal Console module is a quick way to generate the boilerplate files you’ll need.

Write some code

Migration template

Your migration is likely going to need to provide migration templates for various node types, as well as one that handles all nodes. This plugin for handling image assist tags needs to run on all imported nodes, so we start by copying /core/modules/node/migration_templates/d6_node.yml over to our module and adjusting it a little to instruct it to run the ImgAssist plugin (see line 36 here).

Migrate plugin

There are example process plugins in “process” folders around the installation, and looking at those was a great way to figure out how to write ours. Jim made note of these commands to use for finding example code:

find ./ -type d -name 'migration_templates'
find ./ -type d -name 'process'

Our ImgAssist migrate process plugin starts with the Drupal 6 node body and teaser values, and then it runs through a few steps to create their Drupal 8 counterparts:

  • 1. Read through the body value and pick out [img_assist] tags.
  • 2. Split those tags into usable pieces.
  • 3. Build the HTML image tag.
  • 4. Replace the original content containing img_assist tags with the rewritten version, using the built-in transform function.

Running a node migration, step-by-step

  • 1. Get the D6 site and your D8 site running locally.
  • 3. Enable migrate_plus, migrate_upgrade and your custom module.
  • 4. Add your D6 database connection information to settings.php (you can follow the Drupal 7 directions here).
  • 5. Run these Drush commands:
    • drush8 migrate-upgrade --legacy-db-url=mysql://dbusername:dbpassword@dbhost/D6databasename --legacy-root=http://d6site.local --configure-only
    • drush8 migrate-status (just to make sure your custom migration template is registering)
    • drush8 migrate-import yourmodule_d6_node

You’ll get a notice the first time running migrate-import since the node migration depends on a few others to run first, such as d6_user. Run the dependency migrations as needed, then try the custom node import again.

If you have a lot of nodes, the import process will take a few minutes. I actually wrote this entire blog post while waiting for imports to run. Go do something fun for a minute, you’ve earned it.

Eventually, migrate-import will finish running, and you’ll be all set! You can compare the node on your D8 site against the node on the D6 site and see that the tag has been replaced. Hooray!

If it didn’t work: read on. It’s totally fine, you’ve got this.

So what if you have to roll it back?

drush migrate-rollback hasn’t been implemented in D8 just yet (but it is getting close). A workaround is to use drush scr to run a script which deletes your newly-imported nodes. We’ve been using this:

Then, you’ll need to uninstall your custom module, remove all of its config entities from the database, and drop its database tables. You can do that with queries like these:

DELETE from config where name=“migrate.migration.yourmodule_d6_node”;
DROP table migrate_map_yourmodule_d6_node;
DROP table migrate_message_yourmodule_d6_node;

To make this a little easier, you could add these queries to a hook_uninstall function in your module. I’m not one for making things easy (I’m working on this migration before there’s even a Drupal 8 release candidate, after all), so I’ve just been using drush sql-cli.

Now you can adjust your code as needed, re-enable your module and give it another shot (you can just skip ahead to the “drush8 migrate-import yourmodule_d6_node” step at this point).

Further reading

It took a lot of research to figure out how to get migrate working in Drupal 8 this early in the game. These articles were immensely helpful (thanks bloggers and documenters!).

You should also check out