Cuando migramos contenido a Drupal desde otra fuente (CSV, Drupal 7, sistemas externos, etc.), es muy común trabajar con imágenes y archivos. Desde Drupal 8 y especialmente en Drupal 9–11, las entidades Media son la forma recomendada de manejar imágenes y archivos en lugar de usar campos de imagen/archivo directamente.
Este artículo explica cómo migrar imágenes a entidades Media usando Migrate, paso a paso, y luego referenciar esas entidades Media desde el contenido. Los ejemplos están basados en una fuente CSV, pero los mismos conceptos aplican a otras fuentes.
¿Por qué usar Media en lugar de campos file/image?
El módulo Media ha estado en el núcleo de Drupal durante años y es maduro y estable en Drupal 10 y Drupal 11. Usar entidades Media te ofrece:
- Imágenes y archivos reutilizables entre contenidos
- Una biblioteca de medios centralizada
- Campos adicionales en los medios (copyright, autor, alt por defecto, etc.)
- Mejor experiencia editorial
En Omitsis, usar Media es ahora, y desde hace años, un estándar por defecto para proyectos Drupal.
La desventaja es que migrar a Media es ligeramente más complejo que migrar directamente a campos file. Este artículo se enfoca en resolver eso.
Prerrequisitos
Este artículo asume conocimientos básicos de la API de Migrate.
Si eres nuevo en migraciones, se recomienda leer primero una introducción sobre migración desde CSV usando el módulo Migrate.
No usaremos helpers de contrib como migrate_files_to_media. En su lugar, nos basaremos únicamente en plugins de migrate del core/contrib para que entiendas completamente lo que está sucediendo.
Módulos requeridos (Drupal 10 / 11)
Instala los módulos requeridos vía Composer:
composer require drupal/migrate_plus drupal/migrate_tools drupal/migrate_source_csv drupal/config_devel
Habilítalos:
drush en -y migrate migrate_plus migrate_tools migrate_source_csv config_devel
config_devel es opcional pero muy conveniente durante el desarrollo para auto-instalar archivos YAML de migración.
Resumen de la estrategia de migración
Dividiremos el proceso en tres migraciones:
- Migración de archivos – copiar archivos de imagen a Drupal y crear entidades file
- Migración de Media – crear entidades media:image referenciando esos archivos
- Migración de contenido – crear nodos referenciando las entidades Media
Esta separación hace que las migraciones sean más fáciles de depurar, re-ejecutar y reutilizar.
1. Migrando archivos de imagen
Primero, migramos los archivos físicos de imagen y creamos entidades file.
Archivo de migración: migrate_plus.migration.migrate_files.yml
id: migrate_files
label: Migrate Files
source:
plugin: csv
path: modules/custom/custom_migrate/data/products.csv
delimiter: ','
enclosure: '"'
header_offset: 0
ids:
- code
fields:
0:
name: cat
label: 'Category'
1:
name: code
label: 'Product code'
2:
name: title
label: 'Title'
3:
name: image
label: 'Image'
constants:
file_source_uri: 'public://import/source/images'
file_dest_uri: 'public://imports/dest/images'
process:
file_source:
- plugin: concat
delimiter: '/'
source:
- constants/file_source_uri
- image
- plugin: urlencode
file_dest:
- plugin: concat
delimiter: '/'
source:
- constants/file_dest_uri
- image
- plugin: urlencode
uri:
plugin: file_copy
source:
- '@file_source'
- '@file_dest'
uid:
plugin: default_value
default_value: 1
destination:
plugin: entity:file
Puntos clave
- Las constantes definen los directorios de origen y destino
- file_copy copia la imagen y crea una entidad file
- El CSV solo contiene el nombre del archivo de imagen, no rutas completas
- file_copy soporta opciones de overwrite y reuse si es necesario
En este punto, Drupal conoce los archivos, pero aún no como Media.
2. Creando entidades Media desde archivos
Ahora convertimos los archivos en entidades media:image.
Archivo de migración: migrate_plus.migration.media_images.yml
id: media_images
label: Media images
source:
plugin: csv
path: modules/custom/custom_migrate/data/products.csv
delimiter: ','
enclosure: '"'
header_offset: 0
ids:
- code
fields:
0:
name: cat
label: 'Category'
1:
name: code
label: 'Product code'
2:
name: title
label: 'Title'
3:
name: image
label: 'Image'
process:
# Evitar crear entidades media duplicadas
skip:
- plugin: entity_lookup
entity_type: media
bundle: image
value_key: name
source: image
ignore_case: true
access_check: false
- plugin: skip_on_not_empty
method: row
message: 'Skipping already existing media'
field_media_image/target_id:
plugin: migration_lookup
migration: migrate_files
source: code
no_stub: true
uid:
plugin: default_value
default_value: 1
destination:
plugin: entity:media
default_bundle: image
migration_dependencies:
optional:
- migrate_files
Puntos clave
- La reutilización de Media es crítica: una imagen = una entidad Media
- entity_lookup verifica si ya existe un Media con el mismo nombre
- migration_lookup obtiene el fid de la migración anterior
- default_bundle está configurado como image
Este enfoque previene entidades media duplicadas cuando la misma imagen aparece múltiples veces en el CSV.
3. Migrando contenido y referenciando Media
Finalmente, migramos el contenido (nodos) y referenciamos las entidades Media.
Archivo de migración: migrate_plus.migration.products.yml
id: products
label: Import products
source:
plugin: csv
path: modules/custom/custom_migrate/data/products.csv
delimiter: ','
enclosure: '"'
header_offset: 0
ids:
- code
fields:
0:
name: cat
label: 'Category'
1:
name: code
label: 'Product code'
2:
name: title
label: 'Title'
3:
name: image
label: 'Image'
process:
field_cat:
plugin: entity_lookup
entity_type: taxonomy_term
bundle: cat_producto
value_key: name
source: cat
ignore_case: true
field_producto_codigo: code
title:
- plugin: callback
callable: mb_strtolower
source: title
- plugin: callback
callable: ucfirst
type:
plugin: default_value
default_value: producto
field_imagen/target_id:
plugin: entity_lookup
entity_type: media
bundle: image
value_key: name
source: image
ignore_case: true
access_check: false
destination:
plugin: entity:node
migration_dependencies:
optional:
- migrate_files
- media_images
Puntos clave
- Las entidades Media se referencian usando entity_lookup
- La búsqueda se hace por el nombre del media (nombre del archivo de imagen)
- Esto mantiene las migraciones de contenido limpias e independientes
Registrando migraciones automáticamente
Usando config_devel, podemos auto-instalar migraciones declarándolas en el .info.yml del módulo:
config_devel:
install:
- migrate_plus.migration.migrate_files
- migrate_plus.migration.media_images
- migrate_plus.migration.products
Ejecutando las migraciones
Recarga la configuración de migración:
drush cdi custom_migrate
Ejecuta las migraciones en orden:
drush mim migrate_files
drush mim media_images
drush mim products
Resultado final
- Los archivos se copian y registran
- Las entidades Media se crean y reutilizan
- Los nodos referencian Media correctamente
Este enfoque es estable, reutilizable y preparado para el futuro en proyectos Drupal 10 y Drupal 11, y funciona igualmente bien con migraciones CSV, SQL o de Drupal a Drupal.