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 🙂 |