一键导入
drupal-migration
Drupal migration expertise. Use when working with D7-to-D10 migrations, CSV imports, JSON API imports, or custom migration plugins.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Drupal migration expertise. Use when working with D7-to-D10 migrations, CSV imports, JSON API imports, or custom migration plugins.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Drupal Commerce 9-to-10 upgrade expertise. Use when upgrading Drupal Commerce sites from Drupal 9 to Drupal 10, resolving Commerce-specific update hooks, or recovering from failed database updates.
Drupal 10/11 development expertise. Use when working with Drupal modules, themes, hooks, services, configuration, or migrations. Triggers on mentions of Drupal, Drush, Twig, modules, themes, or Drupal API.
Drupal security expertise. Auto-activates when writing forms, controllers, queries, or handling user input. Prevents XSS, SQL injection, and access bypass vulnerabilities.
DDEV local development expertise. Use when working with DDEV projects, containers, configuration, or troubleshooting DDEV environments.
Custom Docker Compose local development patterns. Use when working with Docker-based local environments, container configuration, or troubleshooting Docker setups.
| name | drupal-migration |
| description | Drupal migration expertise. Use when working with D7-to-D10 migrations, CSV imports, JSON API imports, or custom migration plugins. |
You are an expert in Drupal's Migrate API, helping with D7 to D10/D11 migrations, CSV imports, and custom data migrations.
# Core migration modules
drush en migrate migrate_drupal migrate_drupal_ui
# Contrib essentials
composer require drupal/migrate_plus drupal/migrate_tools drupal/migrate_file
drush en migrate_plus migrate_tools migrate_file
| Module | Purpose |
|---|---|
migrate | Core migration framework |
migrate_drupal | D6/D7 migration support |
migrate_drupal_ui | Browser-based migration wizard |
migrate_plus | Config-based migrations, extra source plugins |
migrate_tools | Drush commands for migrations |
migrate_file | File migration handling |
# migrations/migrate_plus.migration.my_migration.yml
id: my_migration
label: 'My Migration'
migration_group: my_group
source:
plugin: source_plugin_name
# Source configuration
process:
# Field mappings
destination_field: source_field
destination:
plugin: 'entity:node'
default_bundle: article
migration_dependencies:
required:
- other_migration
// settings.php
$databases['migrate']['default'] = [
'driver' => 'mysql',
'database' => 'drupal7_db',
'username' => 'db_user',
'password' => 'db_pass',
'host' => 'localhost',
'prefix' => '',
];
drush en migrate_drupal_ui
# Visit /upgrade to use wizard
# Generate migrations from D7
drush migrate:upgrade --legacy-db-key=migrate --configure-only
# List generated migrations
drush migrate:status
# Run all migrations
drush migrate:import --all
# Run specific migration
drush migrate:import upgrade_d7_node_article
# Rollback
drush migrate:rollback upgrade_d7_node_article
Override generated migrations with custom YAML:
# migrations/migrate_plus.migration.upgrade_d7_node_article.yml
id: upgrade_d7_node_article
label: 'Article nodes from D7'
migration_group: migrate_drupal_7
source:
plugin: d7_node
node_type: article
process:
type:
plugin: default_value
default_value: article
title: title
uid:
plugin: migration_lookup
migration: upgrade_d7_user
source: uid
body:
plugin: sub_process
source: body
process:
value: value
format:
plugin: static_map
source: format
map:
full_html: full_html
filtered_html: basic_html
default_value: basic_html
field_image:
plugin: migration_lookup
migration: upgrade_d7_file
source: field_image/0/fid
destination:
plugin: 'entity:node'
default_bundle: article
migration_dependencies:
required:
- upgrade_d7_user
- upgrade_d7_file
# migrations/migrate_plus.migration.import_products.yml
id: import_products
label: 'Import products from CSV'
migration_group: imports
source:
plugin: csv
path: 'modules/custom/my_module/data/products.csv'
ids:
- sku
header_row_count: 1
# Optionally define columns explicitly
column_names:
0:
sku: 'Product SKU'
1:
name: 'Product Name'
2:
price: 'Price'
3:
category: 'Category'
process:
type:
plugin: default_value
default_value: product
title: name
field_sku: sku
field_price: price
field_category:
plugin: entity_lookup
source: category
entity_type: taxonomy_term
bundle: product_categories
bundle_key: vid
value_key: name
destination:
plugin: 'entity:node'
default_bundle: product
# Import
drush migrate:import import_products
# Update existing records
drush migrate:import import_products --update
# Reset status if stuck
drush migrate:reset-status import_products
id: import_api_users
label: 'Import users from API'
source:
plugin: url
data_fetcher_plugin: http
data_parser_plugin: json
urls:
- 'https://api.example.com/users'
item_selector: data
ids:
id:
type: integer
fields:
- name: id
selector: id
- name: email
selector: email
- name: full_name
selector: attributes/name
process:
name: full_name
mail: email
init: email
status:
plugin: default_value
default_value: 1
destination:
plugin: 'entity:user'
process:
# Direct mapping
title: source_title
# Default value
status:
plugin: default_value
default_value: 1
# Static mapping
field_type:
plugin: static_map
source: type
map:
old_type_1: new_type_1
old_type_2: new_type_2
default_value: default_type
# Concatenate
title:
plugin: concat
source:
- first_name
- last_name
delimiter: ' '
# Substring
field_summary:
plugin: substr
source: body
start: 0
length: 200
process:
# Migration lookup (referenced entity was migrated)
uid:
plugin: migration_lookup
migration: users
source: author_id
# Entity lookup (entity already exists)
field_category:
plugin: entity_lookup
source: category_name
entity_type: taxonomy_term
bundle: categories
bundle_key: vid
value_key: name
# Entity generate (create if not exists)
field_tags:
plugin: entity_generate
source: tags
entity_type: taxonomy_term
bundle: tags
bundle_key: vid
value_key: name
process:
# Handle multiple values
field_tags:
plugin: sub_process
source: tags
process:
target_id:
plugin: entity_generate
source: name
entity_type: taxonomy_term
bundle: tags
value_key: name
# Explode string to array
field_keywords:
- plugin: explode
source: keywords
delimiter: ','
- plugin: entity_generate
entity_type: taxonomy_term
bundle: keywords
value_key: name
process:
# Skip if empty
field_image:
plugin: skip_on_empty
method: process
source: image_url
# Skip row if condition
pseudo_skip:
plugin: skip_on_value
source: status
method: row
value: 'draft'
<?php
declare(strict_types=1);
namespace Drupal\my_module\Plugin\migrate\source;
use Drupal\migrate\Attribute\MigrateSource;
use Drupal\migrate\Plugin\migrate\source\SqlBase;
use Drupal\migrate\Row;
/**
* Custom source for legacy products.
*/
#[MigrateSource(
id: 'legacy_products',
source_module: 'my_module',
)]
class LegacyProducts extends SqlBase {
/**
* {@inheritdoc}
*/
public function query() {
$query = $this->select('legacy_products', 'p');
$query->fields('p', ['id', 'name', 'price', 'description']);
$query->condition('p.status', 'active');
$query->orderBy('p.id');
return $query;
}
/**
* {@inheritdoc}
*/
public function fields() {
return [
'id' => $this->t('Product ID'),
'name' => $this->t('Product name'),
'price' => $this->t('Price'),
'description' => $this->t('Description'),
];
}
/**
* {@inheritdoc}
*/
public function getIds() {
return [
'id' => [
'type' => 'integer',
'alias' => 'p',
],
];
}
/**
* {@inheritdoc}
*/
public function prepareRow(Row $row) {
// Add computed fields or modify data
$price = $row->getSourceProperty('price');
$row->setSourceProperty('price_with_tax', $price * 1.21);
return parent::prepareRow($row);
}
}
<?php
declare(strict_types=1);
namespace Drupal\my_module\Plugin\migrate\process;
use Drupal\migrate\Attribute\MigrateProcess;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\ProcessPluginBase;
use Drupal\migrate\Row;
/**
* Converts price from cents to decimal.
*
* Example usage:
* @code
* process:
* field_price:
* plugin: cents_to_decimal
* source: price_cents
* @endcode
*/
#[MigrateProcess(id: 'cents_to_decimal')]
class CentsToDecimal extends ProcessPluginBase {
/**
* {@inheritdoc}
*/
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
if (empty($value) || !is_numeric($value)) {
return NULL;
}
return number_format((float) $value / 100, 2, '.', '');
}
}
# List all migrations
drush migrate:status
# Run migration
drush migrate:import migration_id
# Run with options
drush migrate:import migration_id --limit=100
drush migrate:import migration_id --update
drush migrate:import migration_id --sync
# Rollback
drush migrate:rollback migration_id
# Reset stuck migration
drush migrate:reset-status migration_id
# Stop running migration
drush migrate:stop migration_id
# Show messages/errors
drush migrate:messages migration_id
drush migrate:import migration_id -vvv
# Add to migration YAML
migration_tags:
- debug
// In custom process plugin
\Drupal::logger('my_migration')->notice('Processing: @value', ['@value' => $value]);
"Migration is busy":
drush migrate:reset-status migration_id
Memory errors:
drush migrate:import migration_id --limit=500
# Process in batches
Missing dependencies:
Check migration_dependencies in YAML matches actual migration IDs.
--limit=10 before full import--update for re-running updated migrationsmy_migration/
├── my_migration.info.yml
├── my_migration.module
├── config/
│ └── install/
│ ├── migrate_plus.migration_group.my_group.yml
│ ├── migrate_plus.migration.users.yml
│ └── migrate_plus.migration.content.yml
├── src/
│ └── Plugin/
│ └── migrate/
│ ├── source/
│ │ └── LegacyProducts.php
│ └── process/
│ └── CentsToDecimal.php
└── data/
└── import.csv