Direct Drupal 5 to Drupal 7 Migration in 24hrs

With Drupal 7 around the corner, a lot of Drupal developers and users are surely looking at their lingering still-on-Drupal-5 sites and thinking, "surely I might be able to skip Drupal 6 and upgrade directly to Drupal 7?"

Most all experienced Drupal developers would say (to end-users), "not possible". This is because modules only provide upgrade paths from one major version to the next, and just about all Drupal modules received large rewrites between Drupal 5 and Drupal 6. Without help from module developers, it's not extraordinarily difficult to do a direct Drupal 5 to Drupal 7 migration, but you are going to be building out a lot more things manually.

Of all the projects I'm working on, only my personal blog was still on Drupal 5. As this is rather embarrassing, I figured at least it would be a good experience with direct migration from D5 to D7. Here are my experiences and the approach I used in this upgrade.

  1. Don't bother with upgrading to D6 at all.
    With a jump this big, it seemed like a huge headache to download all of my Drupal 5 modules in their Drupal 6 versions. Especially because some modules have actually released a later D5 version than I was running, I'd actually need to upgrade my D5 modules first, then upgrade to D6, then upgrade to D7. No thanks.
  2. Install a clean Drupal 7 site, clean database.
    You have to start somewhere, so I downloaded Drupal 7 RC2 along with essential modules for my site: Views (and CTools), Webform, WYSIWYG, Mollom, and Devel.
  3. Rebuild the basics.
    This includes building out Taxonomy vocabularies, Content types, and all the fields on those types. Fortunately with modules like Select options, ImageField, and FileField built into core, this goes much quicker than you might expect.
  4. Scale back unneeded modules.
    I couldn't believe some of the modules I'd installed for tiny bits of functionality on my site. I had Date module installed for a single date which is never used for sorting or in Views. I had Link module for entering URLs but no title. I converted both of these to simple text fields using the now-provided core Text module. Other things that made sense for me included converting Upload module to D7's File into a "field_files" field. More on that in step 6.
  5. Throw away your theme.
    My Drupal 5 site was a sub-theme of Zen. Not only is a D7 version of Zen not even out, but API differences in the theme layer make existing tpl.php files pretty much worthless. I started over with everything, including my CSS files but still copy/pasted as needed from my old theme.
  6. Write a custom upgrade module.
    The biggest step in moving from D5 to D7 like this is getting everything that can't be rebuilt manually (like content, files, and comments) over to the new site. For this I wrote a Drupal 7 module that uses Batch API to migrate all my existing nodes and comments to the new site. The basic idea is that my Drupal 7 site would be set up with access to two databases in settings.php, "default" and "legacy". This module would manually select data from the D5 site, construct nodes, files, comments, etc. into objects and call node_save() on the Drupal 7 database. This lets Drupal worry about putting all the information into separate DB tables that the new Field module is prone to use (two database tables per field). I've attached the module I used to migrate my content to this article.
  7. Rebuild your Views.
    If you've upgraded from Drupal 5 to 6 before, you're probably aware that the upgrade path from Views 1 (D5) to Views 2 (D6) was a crazy one. Essentially every view has to be rebuilt into Views 2, but Views provided a tool to help reconstuct these views. If you go straight from Views 1 to Views 3 (D7), don't expect this upgrade tool to work at all.
  8. Work through the bugs.
    At this point, trying to use Drupal 7 for a project is still a dicey bet. The first problems I ran into was a conflict between Drupal core (RC2) and Views (dev branch). Apparently Drupal core changed an API post RC2 (surprise!) that caused Views arguments to break. The solution for me was to upgrade to both dev branches of Drupal 7 and Views 3. If you get stuck, search the issue queues of the module that is giving you trouble. Drupal 7 has a lot more early-adopters than previous versions of Drupal.

So there you go. I started upgrading last night and now I'm composing my first D7 entry on the live site. Obviously this approach requires a signficant amount of technical knowledge. Even for experienced Drupal developers, writing a Drupal 7 module that migrates all content can be an intimidating learning experience due to the extensive API changes from Drupal 6. Nonetheless I hope that my own experience in upgrading my relatively simple blog might help others in facing the challenging task of bridging 3+ years of Drupal advancement in a single sweep.

Attached is my module that provides the following:

  • A form at admin/content/custom-import for performing the import.
  • Migration of D5 Upload module files to a File module field named "field_files".
  • Migration from file paths to D7 stream wrapper paths (URIs).
  • Migration of D5 Nodes including converting "Stories" to "Articles", Upload to File fields, Link module to Text module, and Taxonomy terms into Term Reference Fields (note that I manually migrated Vocabularies and terms prior to creating the upgrade module).
  • Migration of D5 Comments to D7 Comments with the comment field as a D7 Field.
  • While all content is recreated on a clean Drupal site all nodes, files, and comments maintain their same identifiers.

Happy upgrading!


Nice work. And thanks for the writeup. I agree that skipping a major version of Drupal is a reasonable way to proceed. Folks should look at migrate.module to help them do that. It is a bit more structured than a one off import thats custom built. Migrate is what Economist, Examiner, etc. use. So it can handle big and little projects.

I've used Migrate a few different times and found that for the most part it's more learning than it's worth. Either approach (entirely custom or migrate) still requires coding. In D7 the new consistency in save functions (like comment_save()) make custom scripts even easier than before. Unless I'm doing a lot of migrations (or continuous pulling from another system), the custom approaches take me significantly less time. Not to mention I'm not dependent on the stability of other modules for my migration.

Very glad I found this - web surfing always gets me at least one good wave. :) Thanks, Nate.

Thanks for the module and this page, but I have not been able to make it work. I get the following error message: An AJAX HTTP error occurred. HTTP Result Code: 500 Debugging information follows. Path: /?q=batch&id=5&op=do StatusText: Service unavailable (with message) ResponseText: PDOException: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'cando_default.files' doesn't exist: SELECT COUNT(fid) AS count FROM {files} files; Array ( ) in custom_import_batch_files() (line 86 of /var/www/candobetter.local/sites/all/modules/custom_import/custom_import.module). (ends) My best understanding is the databases are supposed to be configured in ./site/default/settings.php Could someone please tell me if I am wrong? Assuming I am right, here is my database configuration: $databases['default']['legacy'] = array( 'driver' => 'mysql', 'database' => 'cando_legacy', 'username' => 'candolocal', 'password' => '#4^7dsa%8-', 'host' => 'localhost', 'prefix' => '', ); $databases['default']['default'] = array( 'driver' => 'mysql', 'database' => 'cando_default', 'username' => 'candolocal', 'password' => '#4^7dsa%8-', 'host' => 'localhost', 'prefix' => '', ); 'default' is the largely empty mysql database into which I intend to import 'legacy'. Could someone tell me if they can spot an error above, or, if not, what the cause of the problem might be?

Is there a way to import drupal 5 user information (username, password, email and profile details) and then exporting to drupal 7?

This helped me a lot. I've never used the batch API before and this code was great for me. Looking at the example code, I think each batch method (i.e. custom_import_batch_comments) is only called once. When I'd expect it to be called multiple times. The $limit value is set, but never actually used in sql, so it runs over the full set.

hi i'm New to drupal.can you provide me the step by step process to migrate this

I got the same question how did you set up so Drupal can access the legacy database, I'm kind of confuse how to implement that.

From what I've read, the Migrate module makes it pretty easy to do imports with node / user references...since there's a bit of a chicken and egg problem with old nids / new nids. Is it worth it to adjust your code to implement something like this? Or do you think migrate is the way to go?

I'm hoping to use the Drupal-to-Drupal Data Migration module soon!

Add new comment

Commenting on this Article is closed.