Post-migration steps: what to do after a Drupal to WordPress migration project

From time-to-time I get clients who ask me to only export the content to a WordPress database, after which they’ll complete the remaining setup themselves. If this applies to your project, you can use these migration notes to help get your new WordPress site running properly.

Import the database dump file

Please see these notes for importing the WordPress dump file.

Administrator credentials and email address

I will have changed your content management system (CMS) administrator password and email address to help with debugging. It’s important that you change these to your own as soon as possible.

Drupal and WordPress user passwords are encrypted so I won’t be able to view them. However, for your peace of mind, I recommend that you ask all your users to reset their passwords after your new WordPress site is live.

Server credentials

Please remember to change any database, (S)FTP, SSH server and control panel credentials you may have given me.

Migrating to a live server

I perform most Drupal to WordPress migrations on a development server. For help on how to move WordPress to your live server, please see: WordPress Codex: Moving WordPress.

Common errors after moving to a live server

Please see below for some common errors you may experience after migrating your new WordPress site to a new server.

Incorrect domain in URLs

WordPress stores domains in the database. If you performed the migration on a local or development server, there’s a good chance that the links will be incorrect after migrating to your live server. Use the Interconnect IT utility to run a search and replace on your database. This will also correct changed database prefixes.

More information can be found on the interconnect/it Search Replace DB page.

“You do not have sufficient permissions to access this page”

If you receive this error after logging in to your new WordPress installation, it’s possible that the database prefix on your new WordPress site is not set correctly. This may happen if you move your WordPress installation to a host that uses a different database prefix.

Try running one of the queries below. Replace wp_new_usermeta, oldprefix_ and newprefix_ as appropriate.

Option 1:

UPDATE wp_new_usermeta SET meta_key = REPLACE(meta_key,’oldprefix_’,’newprefix_’);

UPDATE wp_new_options SET option_name = REPLACE(option_name,’oldprefix_’,’newprefix_’);

Option 2:

update wp_new_usermeta set meta_key = ‘newprefix_usermeta’ where meta_key = ‘wp_capabilities’;

update wp_new_usermeta set meta_key = ‘newprefix_user_level’ where meta_key = ‘wp_user_level’;

update wp_new_usermeta set meta_key = ‘newprefix_autosave_draft_ids’ where meta_key = ‘wp_autosave_draft_ids’;

update wp_new_options set option_name = ‘newprefix_user_roles’ where option_name = ‘wp_user_roles’;

Please note that these queries may not work for you. Success depends on your specific setup.

For more information, please see the following pages:

Further help

I’ll be very happy to provide support you if have difficulties after migration. For a quotation, please contact me. I also offer customised hosting and maintenance packages. Please ask for details.

Importing your WordPress dump file after a Drupal to WordPress migration

If you hired me to run a content export only, you’ll be responsible for setting up WordPress on your own server. Here are some notes to help you with importing the migrated WordPress database.

Import the database dump file

I will deliver either a MySQL database dump file or login credentials to the phpMyAdmin control panel for your project. The first thing you’ll need to do is import the WordPress database into your hosting environment.

Update the database for your domain

WordPress stores domain settings in the database. Since we run the migration and testing on a development server with a temporary sub-domain, you’ll need to update the settings to match your live domain. The easiest way to do this is to use a search and replace utility by Interconnect IT.

It’s pretty straight forward and only takes a few minutes. In the search and replace section:

  • Search for: the domain for your test server
  • Replace with: the domain for your live server

Change the login credentials

I use my own admin email address and password during the migration. For security, please change the administrator user details for your live site. After updating the domains, go directly to the login page to make additional adjustments.

  • http://YOUR-DOMAIN/wp-login.php
  • username: [Your username]
  • password: [Your password]

Your temporary administrator username and password will be sent separately.

Set your WordPress theme

Set the WordPress theme to one that you have installed. I use one of the standard WordPress themes for the migration. However, if the new WordPress site isn’t set to use to a theme you have installed and configured, you may get a blank screen while browsing the site.

  1. After logging in as admin, go to Dashboard > Appearance > Themes.
  2. Select the theme you want to use.

Handling Drupal terms during a Drupal to WordPress migration

When migrating Drupal terms into WordPress, it’s important to understand exactly what terms are and how the two systems handle categorising information.

A primer on Drupal taxonomies

One of Drupal’s most powerful features is its ability to organise content with taxonomies. Unfortunately, the taxonomy system is also notorious as one of the trickiest things about Drupal for beginners to understand. You can find a more detailed explanation here but essentially, a taxonomy is the practice and science of classifying things. In content management terms, you would mostly use taxonomies to organise and categorise articles or posts.

Taxonomies in Drupal uses the concept of vocabularies and terms. Terms are just a list of words that describe a particular type of content. They’re grouped together into vocabularies, which can be thought of as ‘containers’ for a set of terms. Vocabularies may be assigned to any content type. Drupal allows you to arrange the terms within a vocabulary using a parent-and-child hierarchical structure or they can be a flat list, with each term being on the same level as the others.

You can have many vocabularies in Drupal, each containing any number of terms. Vocabulary names must be unique and you cannot have duplicate term names within a vocabulary. It’s possible, however, to have the same term name appear in different vocabularies. Fig. 1 shows an example Drupal taxonomy with three vocabularies, Music, Movies and Books. The Movies and Books vocabularies both have the term Sci-Fi.

An example of Drupal vocabularies and terms
Fig 1: Drupal vocabularies and terms

For more information about the Drupal taxonomy system, please see Organizing content with taxonomies.

WordPress categories and tags

WordPress’ system for organising content is simpler. You have the option of categories–which can be hierarchical–and tags which are flat, or non-hierarchical. In general, categories in WordPress are used as a way of broadly organising posts and tags are used for more detailed descriptions.

Unlike Drupal, where you can have many containers in the form of vocabularies, a standard WordPress installation offers one container for categories and one for tags. Also as standard, categories and tags can only be assigned to the WordPress post content type. A WordPress developer can extend this by creating custom content types with their own categories and tags.

Fig. 2 shows show you’d organise the Music, Movies and Books categorisation in WordPress.

WordPress categories and tags
Fig. 2: WordPress categories and tags

Migrating Drupal terms as WordPress categories and tags

When running a Drupal to WordPress migration, we need to map Drupal’s more complex multi-vocabulary taxonomy system into the simpler WordPress model of categories and tags. How we do this depends on how you want to organise your new WordPress site. For example, we can:

  • convert Drupal vocabulary names into WordPress categories and Drupal term names into WordPress tags;
  • convert Drupal terms into WordPress categories and sub-categories;
  • vocabularies and their associated terms.

It’s all up to you and we figure this out during the requirements gathering stage of the project. For many sites, converting Drupal vocabulary names into WordPress categories and Drupal term names into WordPress tags, as shown in Fig. 3, seems to be the most sensible option. The important thing to know is that the migration may require us to ‘collapse’ or combine your taxonomies.

Merging Drupal and WordPress taxonomies
Fig 3: Merging Drupal taxonomies into WordPress

Since WordPress doesn’t support duplicate category or tag names, another thing to consider is how to handle any duplicate Drupal terms. Normally, the easiest solution is to append a unique number so that you can filter them out post-migration. We can do some clever merging and re-assigning of terms to posts but frankly, it’s probably not worth incurring the extra fees. Unless you have a great number of duplicates, you can probably do the job yourself quite easily via the WordPress Dashboard controls.

Organising your categories and tags in WordPress

Now that we know what’s involved in converting Drupal’s taxonomy over to WordPress, the next obvious question would be, “What’s the best way to structure categories and tags in WordPress?” While I cannot prescribe exactly how you should organise your site, I can point you to this excellent article so you can decide for yourself: Categories vs Tags – SEO Best Practices for Sorting your Content. Generally you should only have a few categories, maybe five or ten in total. Any more and they can become unwieldy and difficult to manage. These categories will reflect the main themes of your site. Tags can then further describe the details of each post and link specific topics together. You can have any number of tags.

The chances are that you probably want to avoid any drastic changes to the site structure when migrating from Drupal to WordPress. A simple mapping of vocabularies to categories and terms to tags is usually the closest equivalent in WordPress.

Drupal to WordPress migration activity diagram

This UML activity diagram accompanies my post, Drupal to WordPress migration explained.

Drupal to WordPress migration process activity diagram

Diagram created with draw.io.

Migration steps listing

  1. Prepare tables: This is where we reset the development database tables to a known state, ready for another migration pass.
  2. Delete unwanted vocabularies
  3. Delete unwanted terms
  4. Merge terms? Yes: go to step a; No: go to step 5
    1. Create tables for each vocabulary to merge
    2. Create duplicate table for each vocabulary
    3. Make duplicate terms unique
    4. Merge terms
  5. Create tags
  6. Create categories and sub-categories
  7. Set uncategorized term
  8. Create posts from nodes
  9. Set posts and page types
  10. Associate posts with terms
  11. Update tag counts
  12. Set default category
  13. Migrate comments
  14. Migrate authors
  15. Site-specific settings and customisation: this would include WordPress site information settings and URL redirects

FeenBan: A shadowban plugin for WordPress

Michael W. Dean of the Freedom Feens Talk Radio Show was having a problem with concern trolls. He wanted a way to shadowban commenters so I made him a plugin.

Here’s what he had to say about it:

“Gets rid of trolls without them knowing they’ve been banned. They keep posting, but no one other than them can see their posts.

Deliciously devilish! Trolling the trolls!

FeenBan! I’m not just the namesake, I’m also a client!”

For more information, visit the plugin page or download it from the WordPress Plugin Directory.

Drupal to WordPress migration: user table mapping

This is part four of a series of posts documenting the table mappings for a site migration from Drupal 6 to WordPress 3. For more information, please see the first article in the series.

Table mapping for WordPress users

This maps Drupal user export to WordPress.

Drupal 6.x

WordPress 3.x

Notes

users

wp_posts

uid

ID

name

user_login

Format to lowercase, replace spaces with underscores

pass

user_pass

name

user_nicename

mail

user_email

created

user_registered

Formatted from UNIX time

name

display_name

user_status

Whitespace string

user_activation_key

Set to 0

Table mapping for WordPress user meta values

User information like capabilities and roles in the wp_usermeta table.

users

wp_usermeta

uid

user_id

meta_key

Set to string e.g. ‘wp_capabilities’

meta_value

Set to string e.g. ‘a:1:{s:6:”author”;s:1:”1″;}’

More information about the settings for appropriate meta_key and meta_value can be found in the WordPress Codex:

Node authors and comment authors

Drupal stores both node authors and comment authors in the users table. WordPress handles things differently. Page and post authors are stored in the wp_users table but comment authors are stored in wp_comments together with the comment data.

Drupal to WordPress migration: comments table mapping

This is part three of a series of posts documenting the table mappings for a site migration from Drupal 6 to WordPress 3. For more information, please see the first article in the series.

Table mapping for WordPress comments

Drupal 6.x

WordPress 3.x

Notes

comments

wp_posts

cid

comment_ID

nid

comment_post_ID

timestamp

comment_date

Converted from UNIX timestamp

comment

comment_content

pid

comment_parent

name

comment_author

mail

comment_author_email

homepage

comment_author_url

Truncated to WordPress limit of 200 chars

status

comment_approved

Comment authors

A note about the different ways Drupal and WordPress store comment author information: Drupal stores comment authors in its users table alongside site users like node authors. In WordPress, comment authors are stored in its wp_comments together with the comment data. WordPress comment authors are not entered into the wp_users table.

Drupal to WordPress migration: terms table mapping

This is part two of a series of posts documenting the table mappings for a site migration from Drupal 6 to WordPress 3. For more information, please see the first article in the series.

Table mapping for WordPress terms

This table mapping exports the Drupal terms into WordPress.

Drupal 6.x

WordPress 3.x

Notes

term_data

wp_terms

tid

term_id

name

name

name

slug

Make lower case and convert spaces to underscores

vid

term_group

Not used in a default WordPress installation

term_data

wp_term_taxonomy

tid

term_taxonomy_id

tid

term_id

taxonomy

String: ‘post_tag’ or ‘category’

description

description

parent

0 (No parent)

In the WordPress Taxonomy documentation, “term_group is a means of grouping together similar terms.” During a standard migration, the WordPress term_group is set to the Drupal vocabulary ID, which seems to make sense. Nevertheless, a default WordPress installation does not actually use the value for anything. It may have been included by the developers for future expandability or use by plugins.

term_group=0 is the default value when creating a term using the Drupal user interface.

Below, we associate posts with the newly migrated terms.

Drupal 6.x

WordPress 3.x

term_node

wp_term_relationships

nid

object_id

tid

term_taxonomy_id

Drupal to WordPress migration: posts table mapping

Following on from Drupal to WordPress migration explained, I will create a series of posts documenting the table mappings for a site migration from Drupal 6.x to WordPress 3.x.

To read the mapping, you look up the Drupal table on the left listing the fields we use for a migration. Directly to its right is the WordPress table with the corresponding field in the same row. So for example, the nid in Drupal’s node table is exported to the id field in the WordPress wp_posts table.

I have listed all the fields used in the query. If a Drupal field shows no mapping in the WordPress table, it is being used to match entries in another table for a join. Here we use the vid field in node and node_revisions for an INNER JOIN.

Table mapping for WordPress wp_posts

Drupal 6.x

WordPress 3.x

Notes

node

wp_posts

nid

id

id

post_author

created

post_date

Create date from UNIX timestamp

title

post_title

changed

post_modified

Create date from UNIX timestamp

type

post_type

status

post_status

vid

node_revisions

body

post_content

teaser

post_excerpt

vid

node

url_alias

nid

dst

post_name

If dst field is NULL, use nid

src

to_ping

Whitespace string

pinged

Whitespace string

post_content_filtered

Whitespace string

Query

REPLACE INTO wordpress.wp_posts (
id,
post_author,
post_date,
post_content,
post_title,
post_excerpt,
post_name,
post_modified,
post_type,
post_status,
to_ping,
pinged,
post_content_filtered)
SELECT DISTINCT
n.nid ‘id’,
n.uid ‘post_author’,
DATE_ADD(FROM_UNIXTIME(0), interval n.created second) ‘post_date’,
r.body ‘post_content’,
n.title ‘post_title’,
r.teaser ‘post_excerpt’,
IF(a.dst IS NULL,n.nid, SUBSTRING_INDEX(a.dst, ‘/’, -1)) ‘post_name’,
DATE_ADD(FROM_UNIXTIME(0), interval n.changed second) ‘post_modified’,
n.type ‘post_type’,
IF(n.status = 1, ‘publish’, ‘private’) ‘post_status’,
‘ ‘,
‘ ‘,
‘ ‘
FROM drupal.node n
INNER JOIN drupal.node_revisions r USING(vid)
LEFT OUTER JOIN drupal.url_alias a
ON a.src = CONCAT(‘node/’, n.nid)
WHERE n.type IN (
/* List the content types you want to migrate */
‘page’,
‘story’,
‘blog’,
‘video’,
‘forum’,
‘comment’);