Is there a way to do a mass conversion of shortcode embeds to Gutenberg block-style embeds, including converting a classic block to a Gutenberg block?
I'm in the process of moving a WordPress site over that hasn't has its theme updated in almost ten years. It has thousands of audio files embedded with a SoundCloud shortcode that looks something like this:
[soundcloud url="; params="auto_play=false&show_artwork=false&color=ff7700" width="100%" height="180" iframe="true" /]
However, in order for them to work automatically with an on-screen player which shows the audio files at the bottom of the page when scrolling, they need to be converted to block-style embeds:
<figure class="wp-block-embed is-type-rich is-provider-soundcloud wp-block-embed-soundcloud"><div class="wp-block-embed__wrapper">;/div></figure>
It's easy enough to do a regex search of the database and change these.
However, the old shortcodes are in classic blocks and if those classic blocks aren't converted to Gutenberg blocks before the regex search-and-replace, then WordPress doesn't treat the newly replaced text as proper block-style embeds. It just treats them as meaningless code that it does not interpret.
So the question is, is there a way to mass-convert classic blocks to to Gutenberg blocks? I have seen and tried all of the plugins in the WordPress store that purport to do this, and they no longer work, and solutions offered in their comments do not work, either. I have also looked at their code to determine if I could make them work, but that is beyond my skill level.
Is there a way to do a mass conversion of shortcode embeds to Gutenberg block-style embeds, including converting a classic block to a Gutenberg block?
I'm in the process of moving a WordPress site over that hasn't has its theme updated in almost ten years. It has thousands of audio files embedded with a SoundCloud shortcode that looks something like this:
[soundcloud url="http://api.soundcloud.com/tracks/11111111" params="auto_play=false&show_artwork=false&color=ff7700" width="100%" height="180" iframe="true" /]
However, in order for them to work automatically with an on-screen player which shows the audio files at the bottom of the page when scrolling, they need to be converted to block-style embeds:
<figure class="wp-block-embed is-type-rich is-provider-soundcloud wp-block-embed-soundcloud"><div class="wp-block-embed__wrapper">http://api.soundcloud.com/tracks/11111111</div></figure>
It's easy enough to do a regex search of the database and change these.
However, the old shortcodes are in classic blocks and if those classic blocks aren't converted to Gutenberg blocks before the regex search-and-replace, then WordPress doesn't treat the newly replaced text as proper block-style embeds. It just treats them as meaningless code that it does not interpret.
So the question is, is there a way to mass-convert classic blocks to to Gutenberg blocks? I have seen and tried all of the plugins in the WordPress store that purport to do this, and they no longer work, and solutions offered in their comments do not work, either. I have also looked at their code to determine if I could make them work, but that is beyond my skill level.
Share Improve this question asked Oct 8, 2021 at 4:00 Grant BarrettGrant Barrett 314 bronze badges 3 |1 Answer
Reset to default 2Ultimately, I solved the problem by exporting the wp_posts table from the database and doing a regex search along the lines of
'([0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]', '[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9])', '(.*?)\[soundcloud url=\\"http://api\.soundcloud\.com/tracks/(.*?)\\" params=\\"auto_play=false&show_artwork=false&color=ff7700&show_playcount=false\\" width=\\"100%\\" height=\\"180\\" iframe=\\"true\\" /]
and replacing it with
'\1', '<!-- wp:paragraph -->\2<!-- /wp:paragraph --><!-- wp:embed \{"url":"http://api.soundcloud\.com/tracks/\3","type":"rich","providerNameSlug":"soundcloud","responsive":true\} --> <figure class="wp-block-embed is-type-rich is-provider-soundcloud wp-block-embed-soundcloud"><div class="wp-block-embed__wrapper"> http://api\.soundcloud\.com/tracks/\3 </div></figure> <!-- /wp:embed -->
Although this successfully converts each entire post (more than 5000) to two Gutenberg blocks, WordPress believes the paragraph block is damaged and needs to be recovered. To solve this, on a Github comment I found Javascript code for the edit admin page that will silently recover all supposedly damaged blocks when a post is opened for editing. I am including the code here (credit to AjXUthaya) in case the comment disappears.
admin.js:
import autoRecoverBlocks from './wordpress/autoRecoverBlocks';
// DECONSTRUCT: WP
const { wp = {} } = window || {};
const { domReady, data } = wp;
// AWAIT: jQuery to get ready
jQuery(document).ready(function ($) {
// DEFINE: Validation variables
const hasGutenbergClasses = $('body').hasClass('post-php') === true && $('.block-editor').length >= 1;
const gutenbergHasObject = domReady !== undefined && data !== undefined;
const gutenbergIsPresent = hasGutenbergClasses === true && gutenbergHasObject === true;
// IF: Gutenberg editor is present
if (gutenbergIsPresent === true) {
autoRecoverBlocks(false);
}
});
autoRecoverBlocks.js:
// FUNCTION: Recover block
const recoverBlock = (block = null, autoSave = false) => {
// DECONSTRUCT: WP object
const { wp = {} } = window || {};
const { data = {}, blocks = {} } = wp;
const { dispatch, select } = data;
const { createBlock } = blocks;
const { replaceBlock } = dispatch('core/block-editor');
const wpRecoverBlock = ({ name = '', attributes = {}, innerBlocks = [] }) => createBlock(name, attributes, innerBlocks);
// DEFINE: Validation variables
const blockIsValid = block !== null
&& typeof block === 'object'
&& block.clientId !== null
&& typeof block.clientId === 'string';
// IF: Block is not valid
if (blockIsValid !== true) {
return false;
}
// GET: Block based on ID, to make sure it exists
const currentBlock = select('core/block-editor').getBlock(block.clientId);
// IF: Block was found
if (!currentBlock !== true) {
// DECONSTRUCT: Block
const {
clientId: blockId = '',
isValid: blockIsValid = true,
innerBlocks: blockInnerBlocks = [],
} = currentBlock;
// DEFINE: Validation variables
const blockInnerBlocksHasLength = blockInnerBlocks !== null
&& Array.isArray(blockInnerBlocks)
&& blockInnerBlocks.length >= 1;
// IF: Block is not valid
if (blockIsValid !== true) {
// DEFINE: New recovered block
const recoveredBlock = wpRecoverBlock(currentBlock);
// REPLACE: Broke block
replaceBlock(blockId, recoveredBlock);
// IF: Auto save post
if (autoSave === true) {
wp.data.dispatch("core/editor").savePost();
}
}
// IF: Inner blocks has length
if (blockInnerBlocksHasLength) {
blockInnerBlocks.forEach((innerBlock = {}) => {
recoverBlock(innerBlock, autoSave);
})
}
}
// RETURN
return false;
};
// FUNCTION: Attempt to recover broken blocks
const autoRecoverBlocks = (autoSave = false) => {
// DECONSTRUCT: WP object
const { wp = {} } = window || {};
const { domReady, data = {} } = wp;
const { select } = data;
// AWAIT: For dom to get ready
domReady(function () {
setTimeout(
function () {
// DEFINE: Basic variables
const blocksArray = select('core/block-editor').getBlocks();
const blocksArrayHasLength = Array.isArray(blocksArray)
&& blocksArray.length >= 1;
// IF: Blocks array has length
if (blocksArrayHasLength === true) {
blocksArray.forEach((element = {}) => {
recoverBlock(element, autoSave);
});
}
},
1
)
});
}
// EXPORT
export default autoRecoverBlocks;
To use the Javascript, save the two sections as two files. Put them in a /js/ directory in your activated template's directory on your server. Then add an enqueuing function in your template's functions.php file. My code is straightforward:
function add_script_to_menu_page()
{
// $pagenow, is a global variable referring to the filename of the current page,
// such as ‘admin.php’, ‘post-new.php’
global $pagenow;
if ($pagenow != 'post.php') {
return;
}
// loading js
wp_register_script( 'autoRecoverBlocks', get_template_directory_uri().'/js/autoRecoverBlocks.js', array('jquery-core'), false, true );
wp_enqueue_script( 'autoRecoverBlocks' );
}
add_action( 'admin_enqueue_scripts', 'add_script_to_menu_page' );
Additionally, for pages that do not have broken blocks but for which I do want to have the classic blocks converted to Gutenberg blocks, I have installed the Convert to Blocks plugin, which silently does the conversion when a post is saved.
<!-- wp:embed {"url":"http://api.soundcloud.com/tracks/$1","type":"rich","providerNameSlug":"soundcloud","responsive":true} --> <figure class="wp-block-embed is-type-rich is-provider-soundcloud wp-block-embed-soundcloud"><div class="wp-block-embed__wrapper"> http://api.soundcloud.com/tracks/$1 </div></figure> <!-- /wp:embed -->
But I still have to change each post to blocks from classic as the embeds do not work with the player. – Grant Barrett Commented Oct 8, 2021 at 15:21