I manage several sites that have been running on Drupal 7. For a variety of reasons, I finally decided that it was time to upgrade them to Drupal 9. I wanted to bypass Drupal 8 altogether, since its end-of-life is coming up in November 2021. Previously, the upgrade path required a detour through D8, but now it’s possible (theoretically) to go straight to D9, so that’s what I planned to do.
My first migration adventure was with https://digitallatin.org/, the main informational site for the Digital Latin Library. I selected that one because it’s a pretty simple site: a couple of custom content types and fields, no custom modules, very few users, and hardly any bells or whistles. I figured that migrating a simple site would prepare me for dealing with the more complex https://catalog.digitallatin.org/ later.
I’m going to include some command line stuff here, along with more general observations and notes, in the hope that this information will help someone else.
Just for context, I am working on a droplet at Digital Ocean running CentOS 7. That means it has MariaDB instead of MySQL, but otherwise everything is pretty standard. I am also using Composer (version 2.1.3) for managing the Drupal codebase.
Edit the settings.php file
Make these changes to settings.php.
- Navigate to
settings.phpusing your favorite text editor.
- Search for ‘trusted_host’ and insert the following after the end of the commented section for that setting:
$settings['trusted_host_patterns'] = [ INSERT_YOUR_HOST_PATTERN_HERE ];
- Search ‘file_private’ and insert the following after the end of the commented section for that setting:
$settings['file_private_path'] = $app_root . '/../private';
- Search ‘config_sync_directory’ and insert the following after the end of the commented section for that setting:
$settings['config_sync_directory'] = $app_root . '/../DIRECTORYFROMSTEP8/sync';
- At end of file add connection to migration database. NOTE It’s important to name the key ‘migrate’.
$databases['migrate']['default'] = array ( 'database' => 'DBNAME', 'username' => 'DBUSER', 'password' => 'DBPASSWORD', 'prefix' => '', 'host' => 'localhost', 'port' => '3306', 'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql', 'driver' => 'mysql', );
After these steps, navigate in the browser to
admin/config/media/file-system and click ‘Save configuation’ to generate the .htaccess file.
Set up Git
Now is a good time to set up Git so that you can track your work.
- Add a
.gitignorefile to the root directory. Go to https://sjhuskey.info/drupal/gitignore-for-drupal/ for a good one. 🤓
- Initiate a git repository:
- Add files to repository:
git add .
git commit -m "First commit."
Install and Enable Migrate Tools
I have encountered difficulties with installing the essential migration tools, since there are multiple conflicts between the Drupal core version, Drush version, and the various migrate modules. I have found it best to install the the migrate modules with Composer first (i.e., before installing Drush) and enable them with the UI (obviously, since Drush isn’t installed yet). Note that
--with-all-dependencies will install the right version of Drush, since Drush is a dependency of the migrate modules.
cdto the root site directory.
- Install and enable migrate tools:
composer require drupal/migrate_tools drupal/migrate_upgrade drupal/migrate_plus drupal/migrate_file --with-all-dependencies.
Evaluate Modules Installed on Original Site
- Run the command
sudo drush pm-list --type=Module --no-core --status=enabled > ~/SITENAME-modules.txtto save a list of all of the enabled contributed and custom modules to a text file in the user’s home directory.
- Download that file:
scp USERNAME@SERVERNAME:~/SITENAME-modules.txt Directory-of-your-choice
- Review the list to see if there are Drupal 9 equivalents.
- Install equivalents using Composer.
- Enable the modules with Drush.
It’s important to do these steps so that the modules are taken into account when you generate the migration files.
Commit everything to the Git repository
At this point, it’s a good idea to commit your changes to the Git repository.
git add .
git commit -m "Added modules before starting to build the migration."
git push(if you have a remote repository)
Generate the Migration YAML files
In this step, you’ll generate YAML migration files without actually running the migration (that’s what
From the root of the site, run
drush migrate-upgrade --configure-only --legacy-db-key=migrate --legacy-root=[INSERT THE ROOT DOMAIN OF YOUR SITE HERE]/
Now, so that you’ll have a copy of all of the files to review offline with a good text editor, do the following:
- Copy the config files to a directory called
drush config:export --destination=/tmp/migrate
- Copy only the files having to do with migration to a directory called
migrate_fileswithin your user’s home directory:
mkdir ~/migrate_files && cp /tmp/migrate/migrate_plus.migration.* /tmp/migrate/migrate_plus.migration_group.migrate_*.yml ~/migrate_files
- Download that directory to your computer:
scp -r USERNAME@SERVERNAME:~/SITENAME_migrate_files DIRECTORY_ON_YOUR_COMPUTER
Run the Migrations
Back in the root directory of the Drupal codebase, do the following:
drush migrate:import --tag=Configuration --execute-dependencies
drush migrate:import --tag=Content --execute-dependencies
It is very likely that there will be errors with one or both of these steps. At this point, debugging is the name of the game.
Errors and Solutions
Inline Entity Form
I ran into the error
The "inline_entity_form_field_instance_settings" plugin does not exist. I honestly didn’t think that the site I was working on used the Inline Entity Form module, so I hadn’t installed it. Installing it did not resolve the issue, so I dove into the issue queue for that project and found a workaround at https://www.drupal.org/project/inline_entity_form/issues/3208995. That did the trick for me, but it looks like https://www.drupal.org/project/inline_entity_form/issues/3221074 might also be a good solution.
The migrations related to the Google Analytics module failed, so I searched its issue queue, too. The solution was to uninstall and remove the module, then install the dev version and apply the patch at https://www.drupal.org/project/google_analytics/issues/3170816.
The D7 version of the site has a content type with a field type of "Youtube," which was supplied by the YouTube Field module. I wasn’t planning to use the YouTube Field module on the D9 version of the site, since D9 has a native Media field type that includes an option for embedding remote video files. But, since the module is supported for D8 and D9, I installed and enabled it. After that, the migration occurred without issue.