Contenido
Esta situación se me ha dado varias veces en los últimos años. Nos viene una web hecha con Visual Composer (WP Bakery), que incluso la hemos hecho nosotros en el Pleistoceno, y nos planteamos rediseñarla con Elementor o Bricks, o incluso con bloques (mentira, esto último en mi caso no…) Y al entrar a los posts descubres que el cliente ha tenido la feliz idea de maquetar los posts con Visual Composer… QUÉ CHORPRECHA!!
Esto plantea el problema de que al desactivar WP Bakery en los posts quedarán unos bonitos shortcodes tipo [vc_loquesea], lo cual hasta hace poco tenía una solución por la vía rápida y contundente: eliminar u ocultar lo shortcodes y dejarlo “plano”, soso como unas espinacas al vapor.
Como decía, durante años utilicé un plugin freemium que en su versión gratuita solo ocultaba los shortcodes, y en su versión de pago te permitía borrarlos permanentemente.
NOTA: El plugin gratuito ha sido bloqueado en el repo de WordPress.
También hay una manera muy drástica de eliminar de la base de datos todos los shortcodes, utilizando expresiones regulares, por ejemplo, con una consulta como esta:
UPDATE wp_posts SET post_content = REGEXP_REPLACE(post_content, "\\[\/?vc(.*?)\]", "");
Te ahorras los 21€ del plugin de Envato, pero al final los posts quedan planchados, sin contenido y sin gracia alguna.
La solución se me ocurrió mientras trabajaba con ChatGPT en otro script que no tenía nada que ver; en ese momento teníamos un proyecto que estábamos rediseñando desde WP Bakery a Elementor y había como unos 100 posts que el cliente a lo largo de los años había diseñado con muchas galerías y fotos sueltas (es un fotógrafo).
Cuando le explicamos que perdería las imágenes de los posts, su primera intención era volver a colocarles las fotos poco a poco, con bloques…
Pero entonces se nos ocurrió que quizá había alguna manera de “mapear” o convertir esos shortcodes a bloques, y que ChatGPT nos podría ayudar.
Y aunque le podemos dar muchas formas, hacer un plugin en el cual seleccionásemos a cuáles posts se le aplica y a cuáles no, la primera aproximación y que a nosotros nos ha servido ha sido meter una función en el “functions.php” y luego ejecutarla en el propio “functions.php” para que procese todos los posts a saco.
Dicho así, el código se compone de 2 partes que van en tu “functions.php”:
Paso 1: Declaramos la función de sustituir shortcodes y reemplazarlos por código de bloques:
// SCRIPT PARA LIMPIAR SHORTCODES DE WP BAKERY (VISUAL COMPOSER) Y CONVERTIRLOS A BLOQUES DE GUTENBERG
function convertir_shortcodes_wp_bakery_a_bloques( $content ) {
// Convertir comillas tipográficas a comillas normales
$content = str_replace(['«', '»'], ['"', '"'], $content);
// Eliminar shortcodes que no nos interesan
$shortcodes_a_eliminar = [
'vc_row',
'vc_column',
'vc_separator',
'vc_column_text',
];
foreach ( $shortcodes_a_eliminar as $sc ) {
$content = preg_replace( '/\[' . $sc . '[^\]]*\]/', '', $content );
$content = preg_replace( '/\[\/' . $sc . '\]/', '', $content );
}
// Convertir [vc_single_image ...]
$content = preg_replace_callback(
'/\[vc_single_image\s+([^\]]+)\]/',
function( $matches ) {
$attrs_str = $matches[1];
$attrs = [];
preg_match_all('/(\w+)="([^"]*)"/', $attrs_str, $attr_matches, PREG_SET_ORDER);
foreach ( $attr_matches as $attr ) {
$attrs[$attr[1]] = $attr[2];
}
if ( empty( $attrs['image'] ) ) {
return '';
}
$image_id = intval( $attrs['image'] );
$size = isset( $attrs['img_size'] ) ? $attrs['img_size'] : 'full';
$alignment = isset( $attrs['alignment'] ) ? $attrs['alignment'] : '';
$caption = isset( $attrs['add_caption'] ) && $attrs['add_caption'] === 'yes';
$block = [
'id' => $image_id,
'sizeSlug' => $size,
];
if ( $alignment ) {
$block['align'] = $alignment;
}
$block_json = json_encode( $block );
return $caption
? "<!-- wp:image {$block_json} --><figure class=\"wp-block-image\"><img src=\"" . wp_get_attachment_url($image_id) . "\" /></figure><!-- /wp:image -->"
: "<!-- wp:image {$block_json} /-->";
},
$content
);
// Convertir [vc_gallery images="123,456,789"]
$content = preg_replace_callback(
'/\[vc_gallery\s+([^\]]+)\]/',
function( $matches ) {
$attrs_str = $matches[1];
$attrs = [];
preg_match_all('/(\w+)="([^"]*)"/', $attrs_str, $attr_matches, PREG_SET_ORDER);
foreach ( $attr_matches as $attr ) {
$attrs[$attr[1]] = $attr[2];
}
if ( empty( $attrs['images'] ) ) {
return '';
}
$ids = array_map('intval', explode(',', $attrs['images']));
$block = [
'ids' => $ids
];
return '<!-- wp:gallery ' . json_encode($block) . ' /-->';
},
$content
);
return trim( $content );
}
Nos interesa purgar todo lo que son filas, columnas, separadores… y nos quedamos con los bloques de imágenes y galerías.
En el caso de [vc_column_text], lo que hace es eliminar los corchetes y mantener solo el contenido de dentro del shortcode.
En lo referente a imágenes sueltas y galerías, el script convierte [vc_single_image] y [vc_gallery] a código compatible con bloques, respetando su alineación también.
Paso 2: Ejecutamos la función en el propio “functions.php”:
// EJECUTAMOS LA FUNCIÓN
add_action('init', function() {
// Solo se ejecuta en el admin para evitar sobrecarga en el frontend
if ( !is_admin() ) return;
$args = [
'post_type' => 'post',
'posts_per_page' => -1,
'post_status' => 'any',
'fields' => 'ids',
];
$posts = get_posts( $args );
foreach ( $posts as $post_id ) {
// Saltar si ya fue convertido
if ( get_post_meta( $post_id, '_conversion_realizada', true ) ) {
continue;
}
$post = get_post( $post_id );
if ( !$post ) continue;
$nuevo_contenido = convertir_shortcodes_wp_bakery_a_bloques( $post->post_content );
if ( $nuevo_contenido !== $post->post_content ) {
wp_update_post([
'ID' => $post_id,
'post_content' => $nuevo_contenido,
]);
update_post_meta( $post_id, '_conversion_realizada', '1' );
error_log("Post {$post_id} convertido.");
} else {
update_post_meta( $post_id, '_conversion_realizada', '1' );
error_log("Post {$post_id} no necesitaba cambios.");
}
}
error_log('Conversión terminada para todas las entradas.');
});
Una vez que pegues todo esto en tu “functions.php”, solo tendrás que ir al Dashboard y recargar cualquier página del backoffice, eso hará que la función se ejecute y, aunque no te dará ningún aviso en pantalla en caso de éxito, sí guardará un log de todo el proceso.
Paso 3: No olvides eliminar las funciones al acabar
Después de la conversión no es necesario que mantengas el código en tu “functions.php”, borra ambas funciones, que si no cada vez que recargues una página, el sistema estará buscando dentro de todos los posts…
A mí me ha funcionado bien y ya le tengo reservado un lugar en el Olimpo de los snippets de mi Wiki de WordPress.
¡¡Espero que os ayuda y podáis jubilar a muchos Visual Composers!!
Deja una respuesta