In this post I will show you how to migrate thumbnail content from Wordpress to Drupal 8. My goals are to help you better understand the content migration process, give you starting point for future migrations, and teach you how to write process plugins and migration sources. Taxonomy terms and users migration is more straightforward so I won't cover it here.
This migration example contains templates to migrate thumbnails content. For this post, I assume the image/thumbnail field is using the Media module field. I will be using the Migrate drush module to run migrations.
First, make sure to configure your connection in your settings.php file. Add the following with proper credentials:
$databases['migrate']['default'] = [
'driver' => 'mysql',
'database' => 'wordpress_dbname',
'username' => 'wordpress_dbuser',
'password' => 'wordpress_dbpassowrd',
'host' => '127.0.0.1',
];
Here is the module structure I will be using:
wp_migration/
- wp_migration.info.yml
- wp_migration.module
- migration_templates/
- wp_content.yml
- wp_thumbnail.yml
- wp_media.yml
- src/
- Plugin/
- migrate/
- process/
- AddUrlAliasPrefix.php
- DateToTimestamp.php
- source/
- SqlBase.php
- Content.php
- Thumbnail.php
Contents of the wp_wordpress.info.yml file:
name: Wordpress Migration
type: module
description: Migrate Wordpress content into Drupal 8.
core: 8.x
dependencies:
- migrate
- migrate_drupal
- migrate_drush
Contents of the migration_templates/wp_thumbnail.yml file:
id: wp_thumbnail
label: 'Thumbnails'
migration_tags:
- Wordpress
source:
plugin: wordpress_thumbnail
# This is WP table prefix (custom variable)
# DB table example: [prefix]_posts
table_prefix: wp
constants:
# This path should point ot WP uploads directory.
source_base_path: '/path/to/source/wp/uploads'
# This is directory name in Drupal where to store migrated files
uri_file: 'public://wp-thumbnails'
process:
filename: filename
source_full_path:
-
plugin: concat
delimiter: /
source:
- constants/source_base_path
- filepath
-
plugin: urlencode
uri_file:
-
plugin: concat
delimiter: /
source:
- constants/uri_file
- filename
-
plugin: urlencode
uri:
plugin: file_copy
source:
- '@source_full_path'
- '@uri_file'
status:
plugin: default_value
default_value: 1
changed:
plugin: date_to_timestamp
source: post_date
created:
plugin: date_to_timestamp
source: post_date
uid:
plugin: default_value
default_value: 1
destination:
plugin: 'entity:file'
migration_dependencies:
required: {}
optional: {}
Contents of the migration_templates/wp_media.yml file:
id: wp_media
label: 'Media'
migration_tags:
- Wordpress
source:
plugin: wordpress_thumbnail
# This is WP table prefix (custom variable)
# DB table example: [prefix]_posts
table_prefix: wp
constants:
bundle: image
process:
bundle: 'constants/bundle'
langcode:
plugin: default_value
default_value: en
'field_image/target_id':
-
plugin: migration
migration: wp_thumbnail
source: post_id
-
plugin: skip_on_empty
method: row
destination:
plugin: 'entity:media'
migration_dependencies:
required: {}
optional: {}
Contents of the migration_templates/wp_content.yml file:
id: wp_content
label: 'Content'
migration_tags:
- Wordpress
source:
plugin: wordpress_content
# Wordpress post type (custom variable)
post_type: post
# This is WP table prefix (custom variable)
# DB table example: [prefix]_posts
table_prefix: wp
process:
type:
plugin: default_value
default_value: article
'path/pathauto':
plugin: default_value
default_value: 0
'path/alias':
# This will add the following to URL aliases in Drupal
plugin: add_url_alias_prefix
# url/alias/prefix/2017/07/21/[post-title]
prefix: url/alias/prefix
source: path_alias
promote:
plugin: default_value
default_value: 0
sticky:
plugin: default_value
default_value: 0
langcode:
plugin: default_value
default_value: en
status:
plugin: default_value
default_value: 1
title: post_title
created:
plugin: date_to_timestamp
source: post_date
changed:
plugin: date_to_timestamp
source: post_modified
field_image:
-
plugin: migration
migration: wp_media
source: thumbnail
-
plugin: skip_on_empty
method: row
'body/summary': post_excerpt
'body/format':
plugin: default_value
default_value: full_html
'body/value': post_content
destination:
plugin: 'entity:node'
migration_dependencies:
required: {}
optional: {}
Contents of the src/Plugin/migrate/process/AddUrlAliasPrefix.php file:
<?php
namespace Drupal\wp_migration\Plugin\migrate\process;
use Drupal\migrate\ProcessPluginBase;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\Row;
/**
* Add prefix to URL aliases.
*
* @MigrateProcessPlugin(
* id = "add_url_alias_prefix"
* )
*/
class AddUrlAliasPrefix extends ProcessPluginBase {
/**
* {@inheritdoc}
*/
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
$prefix = !empty($this->configuration['prefix']) ? '/' . $this->configuration['prefix'] : '';
return $prefix . $value;
}
}
Contents of the src/Plugin/migrate/process/DateToTimestamp.php file:
<?php
namespace Drupal\wp_migration\Plugin\migrate\process;
use Drupal\migrate\ProcessPluginBase;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\Row;
/**
* Date to Timetamp conversion.
*
* @MigrateProcessPlugin(
* id = "date_to_timestamp"
* )
*/
class DateToTimestamp extends ProcessPluginBase {
/**
* {@inheritdoc}
*/
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
return strtotime($value . ' UTC');
}
}
I like to keep my module code clean and organized so I use base classes that I later extend in individual migration source files.
Here is contents of the src/Plugin/migrate/source/SqlBase.php file:
<?php
namespace Drupal\wp_migration\Plugin\migrate\source;
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
use Drupal\migrate\Row;
class SqlBase extends DrupalSqlBase {
/**
* Get database table prefix from the migration template.
*/
protected function getPrefix() {
return !empty($this->configuration['table_prefix']) ? $this->configuration['table_prefix'] : 'wp';
}
/**
* Get Wordpress post type from the migration template.
*/
protected function getPostType() {
return !empty($this->configuration['post_type']) ? $this->configuration['post_type'] : 'post';
}
/**
* Generate path alias via pattern specified in `permalink_structure`.
*/
protected function generatePathAlias(Row $row) {
$prefix = $this->getPrefix();
$permalink_structure = $this->select($prefix . '_options', 'o', ['target' => 'migrate'])
->fields('o', ['option_value'])
->condition('o.option_name', 'permalink_structure')
->execute()
->fetchField();
$date = new \DateTime($row->getSourceProperty('post_date'));
$parameters = [
'%year%' => $date->format('Y'),
'%monthnum%' => $date->format('m'),
'%day%' => $date->format('d'),
'%postname%' => $row->getSourceProperty('post_name'),
];
$url = str_replace(array_keys($parameters), array_values($parameters), $permalink_structure);
return rtrim($url, '/');
}
/**
* Get post thumbnail.
*/
protected function getPostThumbnail(Row $row) {
$prefix = $this->getPrefix();
$query = $this->select($prefix . '_postmeta', 'pm', ['target' => 'migrate']);
$query->innerJoin($prefix . '_postmeta', 'pm2', 'pm2.post_id = pm.meta_value');
$query->fields('pm', ['post_id'])
->condition('pm.post_id', $row->getSourceProperty('id'))
->condition('pm.meta_key', '_thumbnail_id')
->condition('pm2.meta_key', '_wp_attached_file');
return $query->execute()->fetchField();
}
}
Contents of the src/Plugin/migrate/source/Thumbnail.php file:
<?php
namespace Drupal\wp_migration\Plugin\migrate\source;
use Drupal\migrate\Row;
/**
* Extract content thumbnails.
*
* @MigrateSource(
* id = "wordpress_thumbnail"
* )
*/
class Thumbnail extends SqlBase {
/**
* {@inheritdoc}
*/
public function query() {
$prefix = $this->getPrefix();
$query = $this->select($prefix . '_postmeta', 'pm', ['target' => 'migrate']);
$query->innerJoin($prefix . '_postmeta', 'pm2', 'pm2.post_id = pm.meta_value');
$query->innerJoin($prefix . '_posts', 'p', 'p.id = pm.post_id');
$query->fields('pm', ['post_id']);
$query->fields('p', ['post_date']);
$query->addField('pm2', 'post_id', 'file_id');
$query->addField('pm2', 'meta_value', 'filepath');
$query
->condition('pm.meta_key', '_thumbnail_id')
->condition('pm2.meta_key', '_wp_attached_file')
->condition('p.post_status', 'publish')
->condition('p.post_type', 'post');
return $query;
}
/**
* {@inheritdoc}
*/
public function fields() {
return [
'post_id' => $this->t('Post ID'),
'post_date' => $this->t('Media Uploaded Date'),
'file_id' => $this->t('File ID'),
'filepath' => $this->t('File Path'),
'filename' => $this->t('File Name'),
];
}
/**
* {@inheritdoc}
*/
public function getIds() {
return [
'post_id' => [
'type' => 'integer',
'alias' => 'pm2',
],
];
}
/**
* {@inheritdoc}
*/
public function prepareRow(Row $row) {
$row->setSourceProperty('filename', basename($row->getSourceProperty('filepath')));
}
}
Contents of the src/Plugin/migrate/source/Content.php file:
<?php
namespace Drupal\wp_migration\Plugin\migrate\source;
use Drupal\migrate\Row;
/**
* Extract content from Wordpress site.
*
* @MigrateSource(
* id = "wordpress_content"
* )
*/
class Content extends SqlBase {
/**
* {@inheritdoc}
*/
public function query() {
$prefix = $this->getPrefix();
$query = $this->select($prefix . '_posts', 'p');
$query
->fields('p', [
'id',
'post_date',
'post_title',
'post_content',
'post_excerpt',
'post_modified',
'post_name'
]);
$query->condition('p.post_status', 'publish');
$query->condition('p.post_type', $this->getPostType());
return $query;
}
/**
* {@inheritdoc}
*/
public function fields() {
return [
'id' => $this->t('Post ID'),
'post_title' => $this->t('Title'),
'thumbnail' => $this->t('Post Thumbnail'),
'post_excerpt' => $this->t('Excerpt'),
'post_content' => $this->t('Content'),
'post_date' => $this->t('Created Date'),
'post_modified' => $this->t('Modified Date'),
'path_alias' => $this->t('URL Alias'),
];
}
/**
* {@inheritdoc}
*/
public function getIds() {
return [
'id' => [
'type' => 'integer',
'alias' => 'p',
],
];
}
/**
* {@inheritdoc}
*/
public function prepareRow(Row $row) {
// This will generate path alias using WP alias settings.
$row->setSourceProperty('path_alias', $this->generatePathAlias($row));
// Get thumbnail ID and pass it to the wp_media migration plugin.
$row->setSourceProperty('thumbnail', $this->getPostThumbnail($row));
}
}
IMPORTANT: You must run migrations in their proper order. In this example you have to run wp_thumbnail first, wp_media second and wp_content last.
Comments Not Loading?
Due to some temporarily SSL cert issue please refresh the page using this link in order to be able to leave comments.