For my blog Drupal 6 to Drupal 9 Upgrade I finally needed to migrate regular image fields to media fields.
I first tried https://www.drupal.org/project/migrate_file_to_media but wasn't really happy and successful with that. Lots of problems for a relatively simple problem. So I thought about a simpler solution as I don't have many file duplicates in my case.
The result was a simple module to iterate all affected node types and programmatically create media entities from files. Afterwards set them as target for the prepared media fields on the same entity:
<?php
use \Drupal\file\FileInterface;
use \Drupal\media\Entity\Media;
/**
* Defines the entities and source => target fields to run on.
*/
const FILEFILED_TO_MEDIAFIELD_NODE_TYPES = [
'article' => ['field_image' => 'field_media_image'],
'article' => ['field_image2' => 'field_media_image'],
'page' => ['field_image' => 'field_media_image'],
];
/**
* Creates a core media entity from a file entity.
*
* @param FileInterface $file
* @param string $targetMediaBundle
* @param string $targetMediaFieldName
* @return Media
*/
function _filefield_to_mediafield_create_media_entity(FileInterface $file, $targetMediaBundle = 'image', $targetMediaFieldName = 'field_media_image'): Media {
$media_entity = Media::create([
'bundle' => $targetMediaBundle,
'uid' => '1',
'name' => !empty($file->alt) ? $file->alt : $file->label() . ', FID: ' . $file->id(),
'status' => 1,
$targetMediaFieldName => [
'target_id' => $file->id(),
'alt' => $file->alt,
],
]);
$media_entity->save();
return $media_entity;
}
/**
* Copy in filefield_to_media.install CUSTOM DEFINED file field data to a defined media field.
*/
function filefield_to_mediafield_update_800x() {
if (!empty(FILEFILED_TO_MEDIAFIELD_NODE_TYPES)) {
foreach (FILEFILED_TO_MEDIAFIELD_NODE_TYPES as $node_type => $fields) {
foreach ($fields as $sourceFileFieldName => $targetMediaFieldName) {
$nodes = \Drupal::entityTypeManager()
->getStorage('node')
->loadByProperties(['type' => $node_type]);
foreach ($nodes as $node) {
if (!empty($node->{$sourceFileFieldName}->entity)) {
try {
$file = $node->{$sourceFileFieldName}->entity;
$node->{$targetMediaFieldName}->entity = _filefield_to_mediafield_create_media_entity(
$file
);
$node->save();
\Drupal::logger('filefield_to_mediafield')->notice(
'Copied file / image field file: "@file" in node "@node" from field "@sourceFileFieldName" to media field "@targetMediaFieldName".',
['@file' => $file->label() . ', FID:' . $file->id(), '@node' => $node->getTitle(), '@sourceFileFieldName' => $sourceFileFieldName, '@targetMediaFieldName' => $targetMediaFieldName]
);
} catch (Exception $e) {
\Drupal::logger('filefield_to_mediafield')->error($e->getMessage());
}
}
}
}
}
}
}
It can be found here as sandbox project:
https://www.drupal.org/sandbox/anybody/3214753
Please help to improve it for other developers, perhaps by adding the drush command or creating a ui to select the entities, bundles, source and target fields? ;)
Thanks to https://chromatichq.com/insights/migrating-drupal-file-fields-media-ent… which was a good inspiration for the module, even if it was created for media_entity at that time.