Contents
Introducción y objetivo
Este artículo explica con todo lujo de detalles cómo migrar contenido creado con el editor clásico de WordPress a bloques (Gutenberg) realizando el mapeo de etiquetas HTML, imágenes, listas, shortcodes y metadatos a bloques nativos y personalizados usando PHP. Incluye la filosofía del proceso, decisiones prácticas y ejemplos de scripts listos para ejecutar en un entorno WordPress (mu-plugin, plugin temporal o WP-CLI).
Por qué migrar y criterios a considerar
- Beneficios: contenido más estructurado, mejor experiencia WYSIWYG, reutilización y compatibilidad con bloques dinámicos y patterns.
- Riesgos: pérdida de formato si el mapeo no es correcto, imágenes externas no importadas, shortcodes con lógica compleja que requieren reescritura a bloques server-side o client-side.
- Recomendaciones previas: copia de seguridad completa (DB archivos), probar en staging, usar control de versiones y ejecutar la migración en lotes pequeños.
Estrategia de mapeo
Antes de lanzar el script, haz un inventario del contenido que quieres convertir. Una tabla de ejemplo de mapeo podría ser:
| Origen (HTML / Shortcode / Meta) | Destino (Bloque) | Comentarios |
|---|---|---|
| lth1gt-lth6gt | core/heading | mapear el nivel (level) y el contenido |
| ltpgt | core/paragraph | mantener HTML interno simple |
| ltulgt / ltolgt | core/list | convertir ítems li a lista interna |
| ltimg src=…gt | core/image | si es necesario, sideload/importar a librería y añadir ID |
| core/gallery | parsear ids y crear atributos del bloque | |
| [mi_cta texto=…] (shortcode personalizado) | mi-plugin/cta (bloque personalizado) | crear bloque server-side o estático con atributos del shortcode |
Herramientas de PHP en WordPress que usaremos
- parse_blocks() — para analizar contenido que ya tiene bloques.
- serialize_block() — para serializar un array de bloque a su HTML con comentarios .
- has_blocks() — para detectar si un post ya contiene bloques.
- attachment_url_to_postid() y media_sideload_image() — para mapear/importar imágenes a la librería.
- shortcode_parse_atts() — para extraer atributos de un shortcode.
- wp_update_post() y WP-CLI o scripts en background para procesar lotes.
Flujo general recomendado
- Analizar el sitio y contar posts sin bloques: usar has_blocks().
- Definir mapeos exactos (h1 → core/heading(level:1), p → core/paragraph, etc.).
- Crear un script en PHP que recorra posts, parse el HTML (DOMDocument), genere un array de bloques y serialice con serialize_block().
- Actualizar los posts de forma controlada (prueba en 10 posts, verificar resultados, luego lanzar por lotes).
- Revisar shortcodes complejos y convertirlos a bloques personalizados (registro de bloque y mapeo de atributos).
- Test exhaustivo en staging controlar rollback si algo falla.
Ejemplo práctico: script PHP para mapear HTML básico a bloques
El siguiente ejemplo transforma h1-h6, párrafos, listas y ltimggt a bloques nativos. Está pensado para ejecutarse dentro del contexto de WordPress (por ejemplo como mu-plugin o comando WP-CLI). El script omite lógica avanzada (galerías complejas, embed, shortcodes complejos) pero sirve como plantilla base.
lt?php
// Ejemplo de migración simple: transforma HTML clásico a bloques básicos.
// Úsalo en un entorno controlado (staging) y con backups.
// Colócalo en un mu-plugin o ejecútalo vía WP-CLI.
add_action(init, function() {
// Evita ejecución en frontend por accidente.
if (!defined(WP_CLI) !is_admin()) {
return
}
// Función principal para migrar un solo post
function mi_migracion_post_a_bloques(post_id) {
post = get_post(post_id)
if (!post) return false
// Si ya contiene bloques, salimos
if (has_blocks(post->post_content)) {
return false
}
content = post->post_content
if (trim(content) === ) {
return false
}
// Parseamos HTML con DOMDocument
libxml_use_internal_errors(true)
dom = new DOMDocument()
// Convertir a HTML-ENTITIES para preservar acentos
dom->loadHTML(mb_convert_encoding(content, HTML-ENTITIES, UTF-8))
libxml_clear_errors()
body = dom->getElementsByTagName(body)->item(0)
if (!body) return false
blocks = array()
foreach (body->childNodes as node) {
// Saltar nodos vacíos de texto
if (node->nodeType === XML_TEXT_NODE) {
text = trim(node->textContent)
if (text === ) continue
}
nodeName = strtolower(node->nodeName)
switch (nodeName) {
case h1:
case h2:
case h3:
case h4:
case h5:
case h6:
level = intval(substr(nodeName, 1))
inner =
// Guardar el HTML interno del heading
foreach (node->childNodes as c) {
inner .= dom->saveHTML(c)
}
blocks[] = array(
blockName => core/heading,
attrs => array(level => level),
innerHTML => inner,
innerBlocks => array(),
)
break
case p:
inner =
foreach (node->childNodes as c) {
inner .= dom->saveHTML(c)
}
blocks[] = array(
blockName => core/paragraph,
attrs => array(),
innerHTML => inner,
innerBlocks => array(),
)
break
case ul:
case ol:
// Guardar la lista tal cual en innerHTML core/list espera HTML interno de Notas sobre el script anterior
- DOMDocument puede introducir etiquetas lthtmlgt ltbodygt y cambiar entidades por eso se usa mb_convert_encoding y libxml_use_internal_errors.
- media_sideload_image puede ser lento y consumir ancho de banda si hay muchas imágenes externas. Valora hacer esto en segundo plano o solo para imágenes internas.
- serialize_block genera el HTML con los comentarios de bloque adecuados para Gutenberg.
Ejemplo: convertir un shortcode personalizado a un bloque
Imagina que tienes shortcodes tipo [cta texto=Compra ahora color=red] y quieres cambiarlos a bloques mi-plugin/cta. Este snippet localiza el shortcode y lo reemplaza por el bloque serializado.
lt?php
function reemplazar_cta_shortcode_por_bloque(content, post_id) {
// Regex simple para capturar atributos dentro del shortcode [cta ...]
return preg_replace_callback(/[cta([^]])]/i, function(m) use (post_id) {
attr_string = isset(m[1]) ? trim(m[1]) :
attrs = shortcode_parse_atts(attr_string)
if (!is_array(attrs)) attrs = array()
// Normalizar atributos, por ejemplo texto => content
bloque_attrs = array(
texto => isset(attrs[texto]) ? attrs[texto] : ,
color => isset(attrs[color]) ? attrs[color] : default,
)
block = array(
blockName => mi-plugin/cta,
attrs => bloque_attrs,
innerHTML => ,
innerBlocks => array(),
)
return serialize_block(block)
}, content)
}
// Uso: al preparar contenido para migración
post = get_post(123)
nuevo = reemplazar_cta_shortcode_por_bloque(post->post_content, post->ID)
if (nuevo !== post->post_content) {
wp_update_post(array(ID => post->ID, post_content => nuevo))
}
?gt
Migrar metadatos o campos personalizados a bloques
Si tienes datos en postmeta (por ejemplo, un repeatedly used call-to-action guardado en meta _cta_text), puedes crear un bloque con atributos que incluyan esos valores o insertar un bloque que lea esos metadatos en tiempo de renderizado (server-side render).
Ejemplo de flujo:
- Crear un bloque server-side que use render_callback y durante render recupere get_post_meta(post_id, _cta_text, true).
- Si prefieres materializar el contenido en post_content, el script de migración lee get_post_meta y crea serialize_block con esos atributos concretos y lo inserta en content.
Buenas prácticas y recomendaciones finales
- Probar primero en staging: siempre verificar visualmente las migraciones y compararlas con el original.
- Logs y dry-run: añade logs o un modo dry-run que muestre el nuevo HTML sin escribir en la base de datos.
- Batch processing: no proceses miles de posts en una sola petición usa WP-CLI, WP Cron o scripts por lotes para evitar timeouts.
- Versionado: registra cambios en control de versiones si cambias bloques o templates.
- Backups: imprescindible antes de ejecutar cualquier script que modifique post_content.
- Mapping iterativo: empieza migrando contenidos simples y añade reglas para casos especiales (embeds, tablas, shortcodes complejos).
Conclusión
La migración del editor clásico a bloques es un proceso que gana en confiabilidad cuando se diseña un mapeo claro y se implementa con scripts que usen las funciones nativas de WordPress (parse_blocks, serialize_block, attachment helpers). El ejemplo anterior proporciona una base sólida que puedes ampliar: añadir detección de embeds, soporte para galleries, conversión de shortcodes a bloques personalizados y manejo avanzado de imágenes. Ejecuta el proceso en entornos controlados, con backups y por lotes para minimizar riesgos.
Enlaces útiles
|
|
Acepto donaciones de BAT's mediante el navegador Brave 🙂 |
