Migrating data from Drupal 6 to Drupal 7

Massaging Drupal 6 data into Drupal 7

One of our clients is redeveloping the front-end of their site and wanted to take the opportunity to upgrade from Drupal 6 in the process. As the basic data structure was to remain the same, it made sense to go for a straight upgrade, following the instructions in the UPGRADE.txt file from Drupal 7.

After checking that all the modules on the original site were up to date, I did a quick site audit. All of the Drupal 6 modules used had a Drupal 7 version except for the attribute module. The attribute module lets you create a CCK field that contains an attribute:value pair, such as color:blue or size:large. This kind of functionality can be created in Drupal 7 using the field collection module, but would require a bit of work to migrate the data over.

The original site used features extensively. The built in Drupal upgrade path is designed around migrating data contained in the database, not in code. A quick look through the features issue queue provided this patch which adds an extra drush command to features – drush features-import-all.  Running this moved all of the features into the database.  I could then disable each of the custom features without losing any configuration data.

Continuing with the instructions in UPGRADE.txt, I quickly had Drupal core updated to version 7 together with all the contributed modules that had a Drupal 7 release.  All the content types were still there, but missing lots of fields, which brings us to the next step – moving Drupal 6 CCK data to Drupal 7 fields.  This is well covered in the Drupal handbook page, Migrating D6 Content Construction Kit (CCK) to D7 Fields.

By this point, all the old content was showing up in Drupal 7 apart from the attribute fields. The old CCK attribute field was called field_item_for_sale_glance and all the data was in the content_field_item_for_sale_glance table in the database.

I created a new field_collection, which I also called field_item_for_sale_glance, containing two text fields; field_sale_attribute_key and field_sale_attribute_value.  After that, a quick bit of custom code was required to copy the data across.

function sale_attribute_to_field_collection() {
  // Get all item_for_sale nodes.
  $result = db_select('node', 'n')
    ->condition('n.type', 'item_for_sale')

  foreach ($result as $node_data) {
    // Check to see if the old CCK attribute field has any data for this node.
    $old_field = db_select('content_field_item_for_sale_glance', 'old')
      ->condition('old.nid', $node_data->nid)
      ->condition('old.vid', $node_data->vid)
      ->orderBy('', 'ASC')

    foreach ($old_field as $old_data) {
      if ($node = node_load($node_data->nid)) {
        // Create a new field collection item.
        $field_collection_item = entity_create('field_collection_item', array('field_name' => 'field_item_for_sale_glance'));
        // Attach it to the node.
        $field_collection_item->setHostEntity('node', $node);
        // Insert the attribute field values.
        $field_collection_item->field_sale_attribute_key[LANGUAGE_NONE][0]['value'] = $old_data->field_item_for_sale_glance_attribute;
        $field_collection_item->field_sale_attribute_value[LANGUAGE_NONE][0]['value'] = $old_data->field_item_for_sale_glance_value;
        // Save the field collection.

That successfully moved the last of the data over, ready for the front-end work to begin.

Once Drupal 8 is released, I imagine we'll see a flurry of Drupal 6 sites wanting to move to Drupal 7.  It's good to see that the upgrade process is relatively painless.

Add comment

Log in to post comments


You might be interested in checking out the Multifield module ( as a D7 replacement for Attributes, and an alternative to Field collection.

Thanks Dave - I hadn't seen that module. Love the Fifth Element reference! :-)

"It's good to see that the upgrade process is relatively painless."

Consider yourself lucky!. For anything but the most basic of sites, the d6 to d7 upgrade process is a veritable nightmare best avoided if at all possible (think feeds or migrate modules). Especially for those brave souls who did it are the beginning of the d7 release cycle-- I don't even remember how long it took to repair the process after release so that it didn't mangle sites.

No one should need a cheat sheet like to upgrade a site-- what normal user would even think to look for one (they expect everything they need to know to be in UPGRADE.txt, and why wouldn't they?).

Seriously, the issue queues and forums are littered with horror stories. I did it once and I'll never do it again. Migrate is the way to go if you can handle the added complexity.

Yes, this was a pretty basic site with a handful of content types, although it did have mapping and Brightcove video integration. For anything more complex, we do go with the Migrate approach.

There are lots of D6 sites out there though which are pretty basic. For those, it doesn't take long to do a site audit of contrib modules and a test upgrade to see if it's viable.

You're lucky, I've hated the D6 to D7 upgrade process primarily because upgrading modules has become such a pain. Wish someone would have written a module that would take all D6 modules and auto-download D7 equivalents,

It's certainly a process that's crying out to be automated. I wouldn't like to attempt it without drush! I got into a rhythm and whizzed through the bulk of the modules like so:

git rm -r module_name
drush dl module_name
drush en module_name -y
drush cc all
drush updb
Check for errors.
git add module_name
git commit -m "Upgraded module_name to D7."

Thanks for the insight on your progress through the project. I had a few issues with features import, although the patch may not have been available to me at the time. But the content_migrate module is and was so useful, as you found.

How long would you say it took you to go through this whole process? Hours? Days? Thanks!

The actual work was spread out over a few days, but I think I spent about a day on it in total.

Drush certainly helps to speed things up though. For example, getting a list of all non-core, enabled modules can be done with

drush pml --no-core --status=enabled --type=module

and if you want the actual project name, so that you can go to, just run the output through awk. 

drush pml --no-core --status=enabled --type=module | awk -F "[()]" '{ for (i=2; i<NF; i+=2) print $i }'