A reusable Drupal migration module for transferring structured content from WordPress into Drupal.
The module supports migration workflows for posts, pages, users, taxonomies, media, metadata and custom fields while using Drupal APIs and Drush-based commands.
- WordPress posts and pages migration
- User and author mapping
- Category and taxonomy migration
- Media and attachment migration
- Custom-field mapping
- Drupal Entity API integration
- Drush-based execution
- Configurable source database connection
- Migration logging and troubleshooting support
- PHP
- Drupal
- WordPress
- Drupal Entity API
- Drush
- MySQL
- Content Migration
- Taxonomy Mapping
WordPress to Drupal Migration is a Drupal custom module that imports WordPress content into Drupal using Drupal entity APIs instead of direct SQL writes.
The module migrates:
- WordPress posts
- WordPress pages
- WordPress custom post types
- WordPress custom fields and ACF-style post meta
- WordPress categories, tags, and custom taxonomies
- WordPress featured images
- WordPress child attachments
- WordPress inline images and inline file links inside body HTML
- WordPress slugs into Drupal path aliases
- WordPress author ownership by matching author email to an existing Drupal user
- Designed the migration architecture and content-mapping strategy
- Defined source-to-target entity relationships
- Implemented reusable migration components
- Handled taxonomy, media, metadata and user mapping
- Added validation, logging and error-handling considerations
- Documented installation, configuration and execution workflows
- Structured the module for maintainability and future extension
- PHP 8.1 or higher
- Drupal 10 or Drupal 11
- Drush 12 or Drush 13
- Drupal modules:
node,file,image,taxonomy,path_alias - Source WordPress MySQL/MariaDB database access
- Local filesystem or HTTP access to
wp-content/uploads
wp-to-drupal-migration/
├── README.md
├── LICENSE
├── composer.json
├── .gitignore
├── wp_to_drupal_migration.info.yml
├── wp_to_drupal_migration.services.yml
├── drush.services.yml
├── config/
│ ├── install/
│ │ └── wp_to_drupal_migration.settings.yml
│ └── schema/
│ └── wp_to_drupal_migration.schema.yml
└── src/
├── Commands/
│ └── WordPressToDrupalMigrationCommands.php
└── Service/
└── WordPressMigrationService.php
Place the module directory here:
web/modules/custom/wp_to_drupal_migrationAdd the WordPress database connection to web/sites/default/settings.php:
$databases['wordpress']['default'] = [
'database' => 'wordpress_database_name',
'username' => 'wordpress_database_user',
'password' => 'wordpress_database_password',
'prefix' => '',
'host' => '127.0.0.1',
'port' => '3306',
'namespace' => 'Drupal\\mysql\\Driver\\Database\\mysql',
'driver' => 'mysql',
];Edit:
web/modules/custom/wp_to_drupal_migration/config/install/wp_to_drupal_migration.settings.yml
Set the correct WordPress uploads URL and local path:
wordpress_uploads_url: 'https://example.com/wp-content/uploads'
wordpress_uploads_path: '/var/www/wordpress/wp-content/uploads'Map WordPress post types to Drupal content types:
post_type_bundle_map:
post: article
page: page
product: productMap WordPress taxonomies to Drupal vocabularies:
taxonomy_vocabulary_map:
category: categories
post_tag: tags
product_cat: product_categoriesMap WordPress taxonomies to Drupal entity reference fields:
taxonomy_field_map:
category: field_categories
post_tag: field_tags
product_cat: field_product_categoriesMap WordPress custom fields/post meta to Drupal fields:
custom_field_map:
_yoast_wpseo_title: field_meta_title
_yoast_wpseo_metadesc: field_meta_description
subtitle: field_subtitle
hero_title: field_hero_titleCreate these fields on target Drupal content types as needed:
field_wp_id Integer
field_wp_raw_meta Text formatted, long
field_image Image
field_attachments File
field_categories Taxonomy term reference
field_tags Taxonomy term reference
Create additional fields that are listed in custom_field_map.
drush en node file image taxonomy path_alias wp_to_drupal_migration -y
drush crdrush wp-to-drupal:migrate --update=1drush wp-to-drupal:migrate --update=1 --skip-attachments=1drush wp-to-drupal:migrate --post-type=post --update=1drush wp-to-drupal:migrate --post-type=page --update=1drush wp-to-drupal:migrate --post-type=product --update=1drush wp-to-drupal:migrate --post-type=post --limit=100 --offset=0 --update=1
drush wp-to-drupal:migrate --post-type=post --limit=100 --offset=100 --update=1
drush wp-to-drupal:migrate --post-type=post --limit=100 --offset=200 --update=1drush wp-to-drupal:reset-statedrush wp-to-drupal:reset-state --type=postdrush wp-to-drupal:reset-state --type=attachmentAdd custom post type mappings in post_type_bundle_map:
post_type_bundle_map:
portfolio: portfolio
case_study: case_study
product: productEach mapped Drupal bundle must exist before running migration.
Add custom taxonomy mappings in taxonomy_vocabulary_map and taxonomy_field_map:
taxonomy_vocabulary_map:
industry: industries
location: locations
taxonomy_field_map:
industry: field_industries
location: field_locationsEach mapped Drupal vocabulary and entity reference field must exist before running migration.
Add WordPress meta keys to custom_field_map:
custom_field_map:
hero_title: field_hero_title
hero_image: field_hero_image
gallery: field_gallery
cta_link: field_cta_linkSupported Drupal field types include:
stringstring_longtexttext_longtext_with_summarybooleanintegerdecimalfloatlinkfileimage
- Fork the repository.
- Create a feature branch.
- Follow Drupal coding standards.
- Keep migration logic inside services where possible.
- Add clear comments for new migration mappings.
- Test on a copy of the Drupal database and WordPress database.
- Submit a pull request with a clear description of the change.
This project is licensed under the MIT License.