Created
January 3, 2026 08:28
-
-
Save mediaformat/4b4fbd79b2098270d1004fd01fce9a9c to your computer and use it in GitHub Desktop.
Migrate WP Bakery & Minti shortcodes to blocks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?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"; | |
| } | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This works with https://github.com/palasthotel/migrate-2-gutenberg