Skip to content

Instantly share code, notes, and snippets.

@mediaformat
Created January 3, 2026 08:28
Show Gist options
  • Select an option

  • Save mediaformat/4b4fbd79b2098270d1004fd01fce9a9c to your computer and use it in GitHub Desktop.

Select an option

Save mediaformat/4b4fbd79b2098270d1004fd01fce9a9c to your computer and use it in GitHub Desktop.
Migrate WP Bakery & Minti shortcodes to blocks
<?php
/**
* Plugin Name: Migrate 2 Gutenberg - DEV
* Description: Migrate old content into blocks
* Version: 0.0.1
* Requires at least: 6.8
* Tested up to: X.X.X
* Author: Django Doucet
* Author URI: https://mediaformat.org
*/
use Palasthotel\WordPress\MigrateToGutenberg\Plugin;
include dirname( __FILE__ ) . "/public/m2g.php";
register_activation_hook(__FILE__, function($multisite){
Plugin::instance()->onActivation($multisite);
});
register_deactivation_hook(__FILE__, function($multisite){
Plugin::instance()->onDeactivation($multisite);
});
add_filter(\Palasthotel\WordPress\MigrateToGutenberg\Plugin::FILTER_SHORTCODE_TRANSFORMATIONS, function($transformations){
return array_merge(
$transformations,
[
new MintiHeadline(),
new MintiSpacer(),
new MintiImage(),
new MintiVideo(),
new MintiPlayVideo(),
new MintiBox(),
new MintiButton(),
new MintiCallout(),
new MintiTestimonial(),
new MintiIcon(),
new MintiIconBox(),
new MintiDivider(),
new MintiNewDivider(),
new VC_TTA_Accordion(),
new VC_TTA_Section(),
new IFrame(),
new VCRawHTML(),
]
);
});
class MintiHeadline implements \Palasthotel\WordPress\MigrateToGutenberg\Interfaces\ShortcodeTransformation {
function tag() : string{
return "minti_headline";
}
function transform($attrs,string $content) : string{
// our content here was full of h1 tags, so this is all to normalize the content
$is_heading = false;
if ( in_array( 'type', $attrs ) && str_starts_with( $attrs['type'], "h" ) ) {
$h_level = str_replace( 'h', '', $attrs['type'] );
$heading_level = ( (int) $h_level + 1);// start from h2
// this was cursed, but basically if the size was below x, it shouldn't be a heading
$is_heading = (int) ( array_key_exists( 'size', $attrs ) ? str_contains( $attrs['size'], 'x' ) : false );
$heading_content = $content;
$heading_json = ( 2 !== $heading_level) ? '{"level":"h'.$heading_level.'"}' : '';
} elseif ( str_contains( $content, "<h" ) ) {
$html = new WP_HTML_Tag_Processor( $content );
$html->next_tag() === true;
$tag = $html->get_tag();
$h_level = abs((int) filter_var($tag, FILTER_SANITIZE_NUMBER_INT));
$html->next_token();
$heading_content = $html->get_modifiable_text();//this won't get all the text if there are inner tags (span, i, strong)
$heading_level = ( (int) $h_level + 1);
$is_heading = true;
$heading_json = ( 2 !== $heading_level) ? '{"level":'.$heading_level.'}' : '';
}
if ( !$is_heading ) {
$migrated_content = sprintf(
"<!-- wp:paragraph -->\n<p>%s</p>\n<!-- /wp:paragraph -->\n\n",
$content
);
} else {
$migrated_content = sprintf(
"<!-- wp:heading %s -->\n<h%s class=\"wp-block-heading\">%s</h%s>\n<!-- /wp:heading -->\n\n",
$heading_json,
$heading_level,
$heading_content,
$heading_level,
);
}
return $migrated_content;
}
}
class MintiSpacer implements \Palasthotel\WordPress\MigrateToGutenberg\Interfaces\ShortcodeTransformation {
function tag() : string{
return "minti_spacer";
}
function transform($attrs,string $content) : string{
$migrated_content = sprintf(
"<!-- wp:spacer %s -->\n%s\n<!-- /wp:spacer -->\n\n",
'{"height":"40px"}',
'<div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>'
);
return $migrated_content;
}
}
class MintiImage implements \Palasthotel\WordPress\MigrateToGutenberg\Interfaces\ShortcodeTransformation {
function tag() : string{
return "minti_image";
}
function transform($attrs,string $content) : string{
$img_id = $attrs['img'];
$img_size = $attrs['size'] ?? 'medium';
$img_tag = wp_get_attachment_image( $img_id, $img_size, false, ['class'=> 'wp-image-'.$img_id] );
$migrated_content = sprintf(
"<!-- wp:image %s -->\n%s<!-- /wp:image -->\n\n",
'{"id":"'.$img_id.'", "slugSize": "'.$img_size.'"}',
'<figure class="wp-block-image size-'.$img_size.'">'.$img_tag.'</figure>'
);
return $migrated_content;
}
}
class MintiVideo implements \Palasthotel\WordPress\MigrateToGutenberg\Interfaces\ShortcodeTransformation {
function tag() : string{
return "minti_video";
}
function transform($attrs,string $content) : string{
$providerHost = parse_url( $content, PHP_URL_HOST );
$providerNameSlug = explode( '.', $providerHost )[0];
$migrated_content = sprintf(
"<!-- wp:embed %s -->\n%s<!-- /wp:embed -->\n\n",
'{"url":"'.$content.'","type":"video","providerNameSlug":"'.$providerNameSlug.'","responsive":true}',
sprintf(
'<figure class="wp-block-embed is-type-video is-provider-%s wp-block-embed-%s"><div class="wp-block-embed__wrapper">%s</div></figure>',
$providerNameSlug,
$providerNameSlug,
$content,
),
);
return $migrated_content;
}
}
class MintiPlayVideo implements \Palasthotel\WordPress\MigrateToGutenberg\Interfaces\ShortcodeTransformation {
function tag() : string{
return "minti_playvideo";
}
function transform($attrs,string $content) : string{
$video_url = $attrs['url'];
$providerHost = parse_url( $video_url, PHP_URL_HOST );
$providerNameSlug = explode( '.', $providerHost )[0];
return sprintf(
"<!-- wp:embed %s -->\n%s<!-- /wp:embed -->\n\n",
'{"url":"'.$video_url.'","type":"video","providerNameSlug":"'.$providerNameSlug.'","responsive":true}',
sprintf(
'<figure class="wp-block-embed is-type-video is-provider-%s wp-block-embed-%s"><div class="wp-block-embed__wrapper">%s</div></figure>',
$providerNameSlug,
$providerNameSlug,
$video_url,
),
);
}
}
class MintiBox implements \Palasthotel\WordPress\MigrateToGutenberg\Interfaces\ShortcodeTransformation {
function tag() : string{
return "minti_box";
}
function transform($attrs,string $content) : string{
if (
( strpos( $content, '“' ) !== false )
&& ( 1 === substr_count( $content, "\n" ) )
) {
$content_arr = explode( $content, "\n" );
$bare_content = wp_strip_all_tags( $content[0] );
$cite_content = wp_strip_all_tags( $content[1] );
$updated_content = wpautop( $bare_content );
$migrated_content = sprintf(
"<!-- wp:quote -->\n%s<!-- /wp:quote -->\n\n",
sprintf(
'<blockquote class="wp-block-quote">%s</div>',
sprintf(
"<!-- wp:paragraph -->\n%s<!-- /wp:paragraph -->\n%s",
"$updated_content",
"<cite>$cite_content</cite>"
),
),
);
} else {
// "The string does not contain double quotes.";
$bare_content = wp_strip_all_tags( $content );
$updated_content = wpautop( $bare_content );
$migrated_content = sprintf(
"<!-- wp:group %s -->\n%s<!-- /wp:group -->\n\n",
'{"layout":{"type":"constrained"}}',
sprintf(
'<div class="wp-block-group">%s</div>',
sprintf(
"<!-- wp:paragraph -->\n%s<!-- /wp:paragraph -->",
"$updated_content",
),
),
);
}
return $migrated_content;
}
}
class MintiTestimonial implements \Palasthotel\WordPress\MigrateToGutenberg\Interfaces\ShortcodeTransformation {
function tag() : string{
return "minti_testimonial";
}
function transform($attrs,string $content) : string{
$author = esc_attr( $attrs['author'] );
$company = esc_attr( $attrs['company'] );
return sprintf(
"<!-- wp:quote -->\n%s<!-- /wp:quote -->\n",
sprintf(
'<blockquote class="wp-block-quote">%s</blockquote>',
sprintf(
"<!-- wp:paragraph -->\n%s<!-- /wp:paragraph -->\n%s",
$content,
"<cite><strong>$author</strong><br>$company</cite>"
),
),
);
}
}
class MintiButton implements \Palasthotel\WordPress\MigrateToGutenberg\Interfaces\ShortcodeTransformation {
function tag() : string{
return "minti_button";
}
function transform($attrs,string $content) : string{
$link = $attrs['link'];
return sprintf(
"<!-- wp:buttons -->\n%s<!-- /wp:buttons -->\n\n",
sprintf(
"<div class=\"wp-block-buttons\"><!-- wp:button -->%s<!-- /wp:button --></div>",
sprintf(
"<div class=\"wp-block-button\"><a class=\"wp-block-button__link wp-element-button\" href=\"%s\">%s</a></div>",
$link,
$content,
),
),
);
}
}
class MintiCallout implements \Palasthotel\WordPress\MigrateToGutenberg\Interfaces\ShortcodeTransformation {
function tag() : string{
return "minti_callout";
}
function transform($attrs,string $content) : string{
$url = $attrs['url'];
$buttontext = $attrs['buttontext'];
return sprintf(
"<!-- wp:group %s -->\n%s<!-- /wp:group -->\n\n",
'{"layout":{"type":"flex","flexWrap":"nowrap","justifyContent":"center"}}',
sprintf(
"<div class=\"wp-block-group\">%s\n\n%s</div>",
sprintf(
"<!-- wp:paragraph -->\n%s<!-- /wp:paragraph -->",
"$content",
),
sprintf(
"<!-- wp:buttons -->\n<div class=\"wp-block-buttons\">%s</div><!-- /wp:buttons -->",
"<!-- wp:button --><div class=\"wp-block-button\"><a class=\"wp-block-button__link wp-element-button\" href=\"$url\">$buttontext</a></div><!-- /wp:button -->",
),
),
);
}
}
class MintiDivider implements \Palasthotel\WordPress\MigrateToGutenberg\Interfaces\ShortcodeTransformation {
function tag() : string{
return "minti_divider";
}
function transform($attrs,string $content) : string{
return "<!-- wp:separator {\"className\":\"is-style-wide\"} --><hr class=\"wp-block-separator has-alpha-channel-opacity is-style-wide\"/><!-- /wp:separator -->\n\n";
}
}
class MintiNewDivider implements \Palasthotel\WordPress\MigrateToGutenberg\Interfaces\ShortcodeTransformation {
function tag() : string{
return "minti_newdivider";
}
function transform($attrs,string $content) : string{
return "<!-- wp:separator {\"className\":\"is-style-wide\"} --><hr class=\"wp-block-separator has-alpha-channel-opacity is-style-wide\"/><!-- /wp:separator -->\n\n";
}
}
class MintiIconBox implements \Palasthotel\WordPress\MigrateToGutenberg\Interfaces\ShortcodeTransformation {
function tag() : string{
return "minti_iconbox";
}
function transform($attrs,string $content) : string{
$title = esc_attr($attrs['title']);
// not migrating icons here
return sprintf(
"<!-- wp:group %s -->\n%s<!-- /wp:group -->\n\n",
'{"layout":{"type":"constrained"}}',
sprintf(
"<div class=\"wp-block-group\">%s\n\n%s</div>",
"<!-- wp:heading {\"level\":3} -->\n<h3 class=\"wp-block-heading\">\n$title\n</h3><!-- /wp:heading -->\n",
"<!-- wp:paragraph -->\n<p>$content</p><!-- /wp:paragraph -->",
),
);
}
}
class MintiIcon implements \Palasthotel\WordPress\MigrateToGutenberg\Interfaces\ShortcodeTransformation {
function tag() : string{
return "minti_icon";
}
function transform($attrs,string $content) : string{
$icon = esc_attr( $attrs['icon'] );
return "<!-- wp:getbutterfly/font-awesome {\"faClass\":\"fa $icon\"} /-->";
}
}
class VC_TTA_Accordion implements \Palasthotel\WordPress\MigrateToGutenberg\Interfaces\ShortcodeTransformation {
function tag() : string{
return "vc_tta_accordion";
}
function transform($attrs,string $content) : string{
$heading_level = 3; //hardcoding to 3, can be changed in editor
return "<!-- wp:accordion {\"headingLevel\":$heading_level} --><div role=\"group\" class=\"wp-block-accordion\">\n$content</div><!-- /wp:group -->\n\n";
}
}
class VC_TTA_Section implements \Palasthotel\WordPress\MigrateToGutenberg\Interfaces\ShortcodeTransformation {
function tag() : string{
return "vc_tta_section";
}
function transform($attrs,string $content) : string{
$title = $attrs['title'];
return sprintf(
"<!-- wp:accordion-item --><div class=\"wp-block-accordion-item\">\n%s</div><!-- /wp:accordion-item -->\n\n",
sprintf(
"<!-- wp:accordion-heading {\"level\":3} --><h3 class=\"wp-block-accordion-heading\">%s</h3><!-- /wp:accordion-heading -->\n<!-- wp:accordion-panel --><div role=\"region\" class=\"wp-block-accordion-panel\">%s</div><!-- /wp:accordion-panel -->",
"<button class=\"wp-block-accordion-heading__toggle\"><span class=\"wp-block-accordion-heading__toggle-title\">$title</span><span class=\"wp-block-accordion-heading__toggle-icon\" aria-hidden=\"true\">+</span></button>",
$content
),
);
}
}
class IFrame implements \Palasthotel\WordPress\MigrateToGutenberg\Interfaces\ShortcodeTransformation {
function tag() : string{
return "iframe";
}
function transform($attrs,string $content) : string{
$providerHost = parse_url( esc_attr($attrs['src']), PHP_URL_HOST );
if ( str_contains( $providerHost, 'youtube.com' ) ) {// these were all youtube.com/embed
error_log('src:' . print_r( $attrs['src'], true ) );
$url = $attrs['src'];
$providerNameSlug = 'embed-handler';
$migrated_content = sprintf(
"<!-- wp:embed %s -->\n%s<!-- /wp:embed -->\n\n",
'{"url":"'.$url.'","type":"rich","providerNameSlug":"'.$providerNameSlug.'","responsive":true,"className":"wp-embed-aspect-4-3 wp-has-aspect-ratio"}',
sprintf(
'<figure class="wp-block-embed is-type-rich is-provider-embed-handler wp-block-embed-embed-handler wp-embed-aspect-4-3 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">%s</div></figure>',
$url,
),
);
} else {
$migrated_content = "<!-- wp:html -->\n<div class=\"responsive-container\"><iframe src=\"$url\" style=\"aspect-ratio: 9/16; width: 100%;\" loading=\"lazy\" width=\"500\" height=\"150\" frameborder=\"0\" allowfullscreen></iframe></div>\n<!-- /wp:embed -->\n";
}
return $migrated_content;
}
}
class VCRawHTML implements \Palasthotel\WordPress\MigrateToGutenberg\Interfaces\ShortcodeTransformation {
function tag() : string{
return "vc_raw_html";
}
function transform($attrs,string $content) : string{
$decoded_content = urldecode( base64_decode( $content ) );
return "<!-- wp:html -->\n$decoded_content<!-- /wp:embed -->\n";
}
}
@mediaformat
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment