Drupal Migrate – An Introduction

Some time ago, I volunteered to migrate a white label implementation of a Drupal 6 site that is destined to be shut down and merge its data into another Drupal 6 site that uses (mostly) the same content types and structures. I had it all mapped out. It would be easy. Just a few lines of code, some mySQL queries, and we’d be done with it.

It turns out that merging into an existing Drupal site where you want to keep the data from being overwritten is more of a big-ish deal than I thought.

Fortunately, there are great tools out there to help with this, and the one I chose to use is the Drupal Migrate module. Even though this module is designed primarily to migrate D5, D6 (and earlier) sites into D7, there is a D6 version of the module, and it doesn’t care what the source is, so you can use it to merge/migrate between two same-version Drupal sites. It’s not standard operating procedure, but it’s supported, but it’s a barely-documented scenario, hence this series of posts.

I’ll start by covering the basic setup and configuration of Drupal Migrate, and move from there to some more complicated and less obvious situations that I encountered, and how I overcame them. Hopefully this saves somebody else some time and research.

To begin, download the Drupal Migrate module. For the Drupal 6 version, you also need to install dependencies: autoload and dbtng. I highly recommend installing the migrate_ui submodule as well, which requires elements.

I recommend enabling migrate_ui because it gives a Drupal based user interface to the Migrate operations. Without migrate_ui,  you will have to manage all Migrate commands via Drush. Even with migrate_ui, Drush is be extremely helpful for debugging, and is absolutely required for large migrations. So go ahead and install Drush. You’ll need it, and love it.

Once Migrate is installed, you’ll need to create a custom module for your own migration. This sounds daunting, but there are good examples included in migrate – beer.inc and wine.inc. They are worth studying, with beer.inc documenting a basic migration, and wine.inc documenting a more complex migration. But these examples don’t cover everything.

Still unconvinced? I’d highly recommend skimming through this video to see Migrate in action.

A custom migration module has three components: an .info file, a .module file, and an .inc file. These should be created in /sites/all/modules/your_modulename, and the module needs to be enabled on destination site. The .inc file is where most of the migration definition work takes place.

The .info file

name = "My migration"
description = "Migrating the old D6 site to the current D6 site."
package = "MyMigration"
core = 6.x
dependencies[] = taxonomy
dependencies[] = node
dependencies[] = image  // Requires image module. Only needed if migrating images. Paths alone (with separate filecopy) can be migrated without this.
dependencies[] = comment
dependencies[] = migrate
dependencies[] = content
dependencies[] = date
 
files[] = my_migration.module
files[] = my_migrations.inc

Some explanations:

  • The values between the quotes of the first three lines can be pretty much whatever you want. This is informational stuff.
  • Note the 6.x in the ‘core’ definition. This should reflect the main drupal version of your site (i.e. 5, 6, 7). 
  • List the dependencies that your migration will require. You don’t have to get this exactly right, the list above will serve as a good starting point, and should cover most Drupal-sourced content and data migrations.
  • The ‘files[]’ definitions should reference the filenames of the .module file and .inc file(s).

The .module file

<?php

// define the source database
define("SOURCE_DATABASE", 'source_site_database_name');
define("DESTINATION_DATABASE", 'destination_site_database_name');

function my_migration_migrate_api() {
  $api = array(
    'api' => 2,
    'migrations' => array(
        'MyUsers' => array('class_name' => 'MyUsersMigration'),
        'MyStories' => array('class_name' => 'MyStoriesMigration'),
        'MyNomination' => array('class_name' => 'MyNominationMigration'),
        'MyNominationContent' => array('class_name' => 'MyNominationContentMigration'),
        'MyForum' => array('class_name' => 'MyForumMigration'),
        'MyComment' => array('class_name' => 'MyCommentMigration'),
        'MyReview' => array('class_name' => 'MyReviewMigration'),
        'MyUserLocation' => array('class_name' => 'MyUserLocationMigration'),
        'MyStoryLocation' => array('class_name' => 'MyStoryLocationMigration'),
        'MyFile' => array('class_name' => 'MyFileMigration'),
        'MyUpload' => array('class_name' => 'MyUploadMigration'),
        'MyReviewScore' => array('class_name' => 'MyReviewScoreMigration'),
        'MyVote'  => array('class_name' => 'MyVoteMigration'),
        ),
  );
  return $api;
}

?>

Some explanations:

  • Define your source and destination databases here. Most examples show only the source database definition, but if you’re planning on doing any additional processing which might require lookups on the destination site’s database, it’s better to avoid hardcoding database names into the migration definition. Examples of when this is required is, for example, when using the prepare() function to tie in the results of earlier migration steps.
  • This is where you register each of the individual migration steps (called classes) that you will be executing, and which are coded in your .inc file. Each time you add a new migration class to your .inc file, you must add an according line in the .module file to register it.
  • First gotcha: You MUST use the naming convention where the class name ends with ‘Migration’. So if your friendly class name is called ‘foo_bar’, the machine class name will be ‘foo_barMigration’. Maybe it’s because I learned my programming before widespread adoption of object oriented practices, but this was NOT obvious to me. If you don’t do this, your attempts to migrate end in cryptic error messages.

Stay tuned for the next installment, where I will dive into the .inc file and the actual migration.

Extra reading

Here are some resources that helped me get started:

Leave a Reply

Your email address will not be published. Required fields are marked *