Skip to content

Instantly share code, notes, and snippets.

@herbdool
Last active November 18, 2023 02:26
Show Gist options
  • Save herbdool/d50baf524f5a55f55786a5d522153ed5 to your computer and use it in GitHub Desktop.
Save herbdool/d50baf524f5a55f55786a5d522153ed5 to your computer and use it in GitHub Desktop.
Convert D7 Media to Backdrop Media
<?php
/**
* Convert d7 media to Backdrop media
*
* bee php-script convert-d7media2backdrop.php
*
* @todo add batching.
*/
define('VIDEO_SETTINGS', array(
'set_alignment' => TRUE,
));
/**
* Video Codecs
* The key is first part of the uri in file_managed.
* The value is the part that goes before the unique code.
*/
define('VIDEO_CODECS', array(
'youtube:' => '//www.youtube.com/watch?v=',
'vimeo:' => '//www.vimeo.com/watch?v=',
# Add more.
));
/**
* Don't edit below
*/
$number_updated = array();
$number_updated['Blocks'] = convert_custom_blocks();
$number_updated['Layouts'] = convert_layouts();
$number_updated['Entity Fields'] = convert_entity_fields();
print_r($number_updated);
/**
* Convert media in custom blocks
*/
function convert_custom_blocks() {
$custom_blocks = config_get_names_with_prefix('block.custom');
$num = 0;
foreach ($custom_blocks as $custom_block) {
$block_updated = FALSE;
$block_config = config($custom_block);
$update = update_string_with_conversions($block_config->get('body.value'));
if ($update != $block_config->get('body.value')) {
$block_config->set('body.value', $update);
$block_updated = TRUE;
}
$translations = $block_config->get('translations');
if ($translations) {
foreach ($translations as $langcode => $translation) {
$update = update_string_with_conversions($translation['body']['value']);
if ($update != $translation['body']['value']) {
$block_config->set('translations.' . $langcode . '.body.value', $update);
$block_updated = TRUE;
}
}
}
if ($block_updated) {
$block_config->save();
$num++;
}
}
return $num;
}
/**
* Convert media in layouts
*/
function convert_layouts() {
$layouts = config_get_names_with_prefix('layout.layout');
$num = 0;
foreach ($layouts as $layout) {
$layout_updated = FALSE;
$layout_config = config($layout);
$content_items = $layout_config->get('content');
foreach ($content_items as $uuid => $item) {
if ($item['plugin'] != 'layout:custom_block') {
continue;
}
$update = update_string_with_conversions($item['data']['settings']['content']);
$layout_config->set('content.' . $uuid . '.data.settings.content', $update);
$layout_updated = TRUE;
}
if ($layout_updated) {
$layout_config->save();
$num++;
}
}
return $num;
}
/**
* Convert media in entity fields.
*/
function convert_entity_fields() {
$languages = language_list(TRUE, TRUE);
$langcodes = array_keys($languages);
$langcodes[] = 'und';
$num = 0;
$field_bundles = field_info_bundles();
$entity_types = array_keys($field_bundles);
foreach ($entity_types as $entity_type) {
$query = new EntityFieldQuery();
$query = $query->entityCondition('entity_type', $entity_type)
->addTag('DANGEROUS_ACCESS_CHECK_OPT_OUT');
$result = $query->execute();
$fields = field_info_fields();
$convert_fields = array();
foreach ($fields as $key => $field) {
if (!in_array($entity_type, $field['entity_types'])) {
continue;
}
if ($field['type'] == 'text_with_summary') {
$convert_fields[] = array(
'name' => $field['field_name'],
'cardinality' => $field['cardinality'],
'columns' => array('value', 'summary'),
);
}
if ($field['type'] == 'text_long') {
$convert_fields[] = array(
'name' => $field['field_name'],
'cardinality' => $field['cardinality'],
'columns' => array('value'),
);
}
}
// Entity doesn't have fields that concern us.
if (empty($convert_fields)) {
continue;
}
foreach ($result[$entity_type] as $id => $item) {
$entity = entity_load($entity_type, $id);
$field_updated = FALSE;
foreach ($convert_fields as $convert_field) {
$field_name = $convert_field['name'];
foreach ($langcodes as $langcode) {
if (!isset($entity->$field_name[$langcode])) {
continue;
}
foreach ($convert_field['columns'] as $column) {
for ($i = 0; $i < $convert_field['cardinality']; $i++) {
$original = $entity->$field_name[$langcode][$i][$column];
$update = update_string_with_conversions($original);
if ($update != $original) {
$entity->$field_name[$langcode][$i][$column] = $update;
$field_updated = TRUE;
}
}
}
}
}
if ($field_updated) {
$entity->save();
$num++;
}
}
}
return $num;
}
/**
* Update string with conversion.
*
* @param string $string
* @return string
* Updated string with new image formats.
*/
function update_string_with_conversions($string) {
$chunks = preg_split('/\}\}\]\]/', $string);
$searches = array();
$replacements = array();
foreach ($chunks as $chunk) {
$matches = array();
preg_match('/\[\[\{(?<=\[\[\{)(.*)/', $chunk, $matches);
if (empty($matches)) {
continue;
}
$media = json_decode($matches[0] . '}}]]');
$fid = $media[0][0]->fid;
$file = file_load($fid);
if (!is_object($file)) {
continue;
}
if ($file->type == 'image') {
$replacement = format_image($media[0][0], $file);
}
if ($file->type == 'video') {
$replacement = format_video($media[0][0], $file);
}
if (isset($replacement)) {
$searches[] = $matches[0] . '}}]]';
$replacements[] = $replacement;
}
}
return str_replace($searches, $replacements, $string);
}
/**
* Format Image
*
* @param object $media
* @param object $file
* @return string
*/
function format_image($media, $file) {
// Example from D7 embedded image:
// [[{"fid":"3231","view_mode":"default","fields":{"format":"default","alignment":"","field_file_image_alt_text[und][0][value]":"Graphic","field_file_image_title_text[und][0][value]":false},"type":"media","field_deltas":{"3":{"format":"default","alignment":"","field_file_image_alt_text[und][0][value]":"Graphic","field_file_image_title_text[und][0][value]":false}},"attributes":{"alt":"Graphic","height":"251","width":"496","style":"display: block; margin-left: auto; margin-right: auto;","class":"media-element file-default","data-delta":"3"}}]]
$file_directory = config_get('system.core', 'file_public_path');
$src = preg_replace('/public:\/\//', '/' . $file_directory . '/', $file->uri);
$alt = isset($media->attributes->alt) ? $media->attributes->alt : '';
$caption = isset($media->attributes->title) ? $media->attributes->title : '';
// Get width and height.
$width = isset($file->width) ? $file->width : '';
$height = isset($file->height) ? $file->height : '';
// Get from display mode if it has either width or height set.
// @todo Figure out what to do about cropping.
$view_mode = $media->view_mode;
$config_file_display = config('file_display.image');
$formatter = $config_file_display->get($view_mode . '.formatter');
$image_style = $config_file_display->get($view_mode . '.settings.' . $formatter . '.image_style');
if ($image_style) {
$config_image_style = config('image.style.' . $image_style);
$image_style_width = $config_image_style->get('effects.data.width');
$image_style_height = $config_image_style->get('effects.data.height');
if ($image_style_width) {
$width = $image_style_width;
}
if ($image_style_height) {
$width = $image_style_height;
}
}
// If set in the embedded json use that instead.
if (isset($media->attributes->width)) {
$width = $media->attributes->width;
}
if (isset($media->attributes->height)) {
$height = $media->attributes->height;
}
// Maybe don't use original if it's wider than the screen.
// 72.25rem = 1040 px (base font 14.4 px)
if ($width > 1040) {
$width = 1040;
$height = '';
}
$alignment = isset($media->fields->alignment) ? $media->fields->alignment : '';
// Example result:
// <img alt="hello" data-align="right" data-caption="Bye" data-file-id="1" height="533" src="/files/field/image/card1-layout_1.png" width="800" />
$image = '<img alt="' . $alt . '" data-file-id="' . $file->fid . '" ';
$image .= $alignment ? 'data-align="' . $alignment . '" ' : '';
$image .= $caption ? 'data-caption="' . $caption . '" ' : '';
$image .= 'src="' . $src . '" width="' . $width . '" height="' . $height . '" />';
return $image;
}
/**
* Format Video
* Returns a Video Filter format.
*
* @param object $media
* @param object $file
* @return string
*/
function format_video($media, $file) {
// Example D7 embedded video:
// [[{"fid":"3992","view_mode":"media_original","fields":{"format":"media_original","alignment":"left"},"link_text":"Test","type":"media","field_deltas":{"1":{"format":"media_original","alignment":"left"}},"attributes":{"class":"media-element file-media-original media-wysiwyg-align-left","data-delta":"1"}}]]
// Converted (examples):
// [video://www.vimeo.com/123456]
// [video:/www.youtube.com/watch?v=123456 width:900 align:left]
// Ignoring view_mode and format since all these videos are being displayed.
// Ignoring link text.
$width = '';
$height = '';
if (isset($media->attributes->width)) {
$width = $media->attributes->width;
}
if (isset($media->attributes->height)) {
$height = $media->attributes->height;
}
// Maybe don't use original if it's wider than the screen.
// 72.25rem = 1040 px (base font 14.4 px)
if ($width > 1040) {
$width = 1040;
$height = '';
}
$alignment = isset($media->fields->alignment) ? $media->fields->alignment : '';
$uri_parts = explode('/', $file->uri);
$uri = VIDEO_CODECS[$uri_parts[0]] . $uri_parts[3];
if (empty($uri)) {
return NULL;
}
$video = '[video:' . $uri;
$video .= $width ? ' width:' . $width : '';
$video .= $height ? ' height:' . $height : '';
if (VIDEO_SETTINGS['set_alignment']) {
$video .= $alignment ? ' align:' . $alignment : '';
}
$video .= ']';
return $video;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment