Christopher Bloom
Frontend developer, lover of design systems, CSS architecture, and all things javascript.
Christopher Bloom (illepic)
Scenario:
Legacy Drupal 6 site needs a migration to new Drupal 8 site. We want to migrate settings, content types, fields, users, files, content. The Drupal 6 site database is accessible from the freshly installed Drupal 8 database.
Not "in-place" upgrade like Drupal 6 to 7
No UI, command line only
A single Migration YAML file might look like this:
status: true
dependencies: { }
id: upgrade_d6_node_page
migration_tags:
- 'Drupal 6'
migration_group: migrate_drupal_6
label: 'Nodes (page)'
source:
plugin: d6_node
node_type: page
process:
nid: nid
vid: vid
type:
plugin: default_value
default_value: post
langcode:
plugin: default_value
source: language
default_value: und
title: title
uid: node_uid
status: status
created: created
changed: changed
promote: promote
sticky: sticky
body/format:
plugin: default_value
default_value: basic_html
body/value:
plugin: remove_strings
source: body
field_media_primary:
-
source: nid
plugin: img_assist
type: 'mid'
-
plugin: iterator
process:
target_id: fid
field_attachments:
-
plugin: iterator
process:
target_id: fid
display:
plugin: default_value
default_value: 1
field_group:
source: nid
plugin: og_lookup
destination:
plugin: 'entity:node'
migration_dependencies:
required:
- upgrade_d6_user
- upgrade_d6_node_type
- upgrade_d6_file_media
optional: { }
In Drupal 8 settings.php, right next to your regular database configuration, add a db config FOR THE D6 SITE:
$databases['migrate']['default'] = array (
'database' => 'dbname',
'username' => 'dbuser',
'password' => 'dbpass',
'prefix' => '',
'host' => 'localhost',
'port' => '3306',
'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql',
'driver' => 'mysql',
);
You now have configuration for
$databases['my_d8_site']['default'] and $databases['migrate']['default']
This EXACT name for the D6 db config is extremely important:
$databases['migrate']['default']
Aight, D8. Generate a Migration
From the D8 site root, run:
drush migrate-upgrade --configure-only
Boom. D8 just took its best guess at figuring out all the fields, nodes, files, etc. (hopefully)
Now let's dump all this out as YAML files:
drush config-export --destination=/tmp/migrate
Many YAML files will now appear in /tmp/migrate. We're going to move all these to a custom module shortly.
Let's make a module so Drupal understands how to find this config
Use Drupal Console to generate a module for us
drupal generate:module
A series of questions will appear. We'll call the module custom_migration. Use the default options provided except:
Would you like to add module dependencies: yes
Module dependencies separated by commas:
migrate_drupal, migrate_plus
Create a folder in your new module:
custom_migration/config/install
Move our previously generated YAML to the new module:
cp /tmp/migrate/migrate_plus.migration.* \
/tmp/migrate/migrate_plus.migration_group.migrate_*.yml \
/path/to/your/module/config/install/
Just make sure you do NOT include the default config group file called migrate_plus.migration_group.default.yml
Let's run it
Running drush migrate-status shows us the individual migrations D8 knows about
$ drush migrate-status
Group: migrate_drupal_6 Status Total Imported Unprocessed Last imported
upgrade_d6_system_site Idle 1 1 0
upgrade_d6_url_alias Idle 6972 0 6972
upgrade_d6_file Idle 9914 3499 0
upgrade_d6_user_picture_file Idle 281 281 0
upgrade_user_picture_entity_display Idle 1 1 0
upgrade_d6_user Idle 1402 1133 0
upgrade_d6_file_media Idle 9914 3495 0
upgrade_d6_book_blog Idle 822 0 822
upgrade_d6_node_event Idle 1351 0 1351
upgrade_d6_node_forum Idle 2305 0 2305
upgrade_d6_node_guild_app Idle 679 677 0
upgrade_d6_node_image Idle 2243 0 2243
upgrade_d6_node_page Idle 9 0 9
Run all migrations:
drush migrate-import --all
Congrats!
source:
plugin: d6_file
process:
fid: fid
# Skip any filename in the map below
filename:
-
plugin: static_map
source: filename
bypass: true
map:
'gallery grid': ''
preview: ''
thumbnail: ''
img_assist_properties: ''
large: ''
-
plugin: skip_contains
skip:
- 'furiousraid'
-
plugin: skip_on_empty
method: row
-
plugin: callback
callable: basename
source: filepath
Next up: Write your own process plugins
(in custom_migration/src/Plugin/migrate/process/ImagePath.php)
<?php
/**
* @file
* Contains \Drupal\df_migration\Plugin\migrate\process\ImagePath.
*/
namespace Drupal\df_migration\Plugin\migrate\process;
use Drupal\migrate\Annotation\MigrateProcessPlugin;
use Drupal\migrate\ProcessPluginBase;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\Row;
/**
* This plugin fixes d6 Image file names to be the actual filename from filesystem
*
* @MigrateProcessPlugin(
* id = "image_path"
* )
*/
class ImagePath extends ProcessPluginBase {
/**
* {@inheritdoc}
*/
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row,
$destination_property) {
return basename($value);
}
}
Next up: Edit a migration YAML file, reload it in Drupal, and rerun a migration
# Rollback migration
drush mr upgrade_d6_node_page
# (Edit the migrate_plus.migration.upgrade_d6_node_page.yml file)
# Now, hard reload the file using Config Development module
drush cdi1 modules/custom/df_migration/config/install/migrate_plus.migration.upgrade_d6_node_page.yml \
&& drupal cr all
# Re-run this migration
drush mi upgrade_d6_node_guild_app
Next up: unbork a crashed migration
drush php-eval 'var_dump(Drupal::keyValue("migrate_status")->set('your_migration_name', 0))'
By Christopher Bloom
Frontend developer, lover of design systems, CSS architecture, and all things javascript.