Drupal 8/9 Migration: Migrating Media Items and Their Relationships
Since Drupal 8.5, the Media module in core has been a reality and the recommended way to handle media content in Drupal.
If you're migrating from Drupal 7 to Drupal 8 or Drupal 9, this is something you need to take into consideration.
👩💻 Get up to speed on the latest version of Drupal! Join us on September 24 for a free webinar on Drupal 9.
In this blog post, we'll go through a migration example where you'll learn how to migrate media items and their relationships in Drupal.
The Drupal 8/9 Migration Tutorial Series
- Part 1: Migrating Basic Data
- Part 2: Migrating Taxonomy Terms and Term References
- Part 3: Migrating Files and Images
- NEW: Migrating Hierarchical Taxonomy Terms
- NEW: Migrating Media Items and Their Relationships (you are here!)
Before We Start
- If you are new to migrations in Drupal 8, you may want to read about migrating basic data to Drupal 8 first.
- You can follow the sample code for this tutorial: Migrate example: Media module on GitHub.
- You need to have migrate_tools and migrate_plus modules to follow this tutorial.
- You need to have Drush installed to run migrations as described in this article.
- This tutorial is also valid for Drupal 9 migrations.
The Problem
We have received a database dump and files backup from our imaginary client.
We need to:
- Migrate files from articles into Drupal 8 files
- Create media items for each migrated file
- Migrate articles to Drupal 8 and add the related media items.
Setting up the Migration
Create the migration module
We first need to create a module for our migrations. In this example, we're naming it migrate_example_media
.
We then need to add the following modules as dependencies in the module declaration:
Create a migration group
To group the migrations, we also need to create a migration group. To do so, we’ll create a fairly simple configuration file so that the group gets created when the module is installed. The file’s contents should be as follows:
id: medialabel: Media Groupsource_type: Drupal 7shared_configuration: source: key: migrate_d7
Define a new database connection
Next, you need to load the Drupal 7 database into your Drupal 8 installation. To do so, you need to define a new database connection in your settings.php file like this:
$databases['migrate_d7']['default'] = array( 'driver' => 'mysql', 'database' => 'migrate_d7', 'username' => 'user', 'password' => 'password', 'host' => 'db', 'prefix' => '',);
And then you can import the database dump into this new database connection using your preferred method.
Writing the Migrations
Next thing to do is to write the actual migrations. Per our requirements, we need to write three different migrations: one for files, one for media and one for articles.
Since Drupal 8.1.x, migrations are plugins that should be stored in a migrations folder inside any module. You can still make them configuration entities as part of the migrate_plus module, but I personally prefer to follow the core recommendation because it's easier to develop (you can make an edit and just rebuild cache to update it).
Write the file migration
The first migration to write is the file migration. To speed things up, we're placing the files backup into a migratefiles folder in sites/default/files and we'll copy the files from there to the right folder during the migration.
The source section of the migrate plugin looks like this:
source: plugin: d7_file scheme: public constants: migrate_files_path: 'sites/default/files/migratefiles'
We're setting migrate_files_path
to be the base path where we put the backup files. This will be used later to copy the files to the right location.
The process section of the migrate file looks like this:
process: filename: filename replaced_filepath: - plugin: str_replace source: filepath search: "sites/default/files/" replace: "" source_full_path: - plugin: concat delimiter: / source: - constants/migrate_files_path - '@replaced_filepath' - plugin: urlencode uri: plugin: file_copy source: - '@source_full_path' - uri filemime: filemime status: status created: timestamp changed: timestamp uid: uid
First, we create a temporary replaced_filepath
to remove the path prefix. Then, we'll use the concat plugin to create the source_full_path
based on the migrate_files_path
constant and the replaced_filepath
. Then, for the uri
, we use file_copy to copy from this source_full_path
to the destination URI. The remaining fields are directly mapped from Drupal 7 values.
You can look at the full migration file in the code samples repo.
Write the media migration
The media migration also uses d7_file
as the source. We use the skip_on_value
plugin in a temporary temp1
field to skip files that are not images:
temp1: - plugin: skip_on_value method: row not_equals: true value: - image/png - image/jpg - image/jpeg source: filemime
We use migration_lookup plugin to add the actual image files like this:
field_media_image/target_id: - plugin: migration_lookup migration: file source: fid
You can look at the full migration file in the code samples repo.
Write the article migration
The article migration is pretty similar to any other entity migrations. To set the image, we're using the sub_process and migration_lookup plugins like this:
field_image: plugin: sub_process source: field_image process: target_id: plugin: migration_lookup source: fid migration: media_image
So that it looks for the right items in the media_image
migration. You can look at the full migration file in the code samples repo.
Running the Migrations
Since we have set dependencies, we can instruct Drupal to run the migration group and it will run the migrations in the right order.
To do so, execute drush mim --group=media
and the output will look like this:
[notice] Processed 3 items (3 created, 0 updated, 0 failed, 0 ignored) - done with 'file' [notice] Processed 3 items (3 created, 0 updated, 0 failed, 0 ignored) - done with 'media_image' [notice] Processed 3 items (3 created, 0 updated, 0 failed, 0 ignored) - done with 'article'
You can also run drush ms
to see current migration status:
--------------------- ----------------------------------- -------- ------- ---------- ------------- --------------------- Group Migration ID Status Total Imported Unprocessed Last Imported --------------------- ----------------------------------- -------- ------- ---------- ------------- --------------------- Media Group (media) file Idle 3 3 0 2020-08-24 16:06:10 Media Group (media) media_image Idle 3 3 0 2020-08-24 16:06:10 Media Group (media) article Idle 3 3 0 2020-08-24 16:06:10
Next Steps
- Check out the code for the migrate_example_media module on GitHub.
- Read about migrating basic data to Drupal 8.
- Learn more about migrations on our blog.
- Sign up for one of our advanced Drupal training courses to step up your Drupal development skills.