Contents
Introducción
Este artículo explica con todo lujo de detalles cómo registrar plantillas de bloque (block templates) para un Custom Post Type (CPT) en WordPress utilizando PHP. Verás desde los requisitos básicos, la sintaxis precisa de la propiedad template en register_post_type, cómo bloquear la inserción o edición de bloques con template_lock, cómo anidar bloques y cómo integrar bloques personalizados en la plantilla. Incluye varios ejemplos listos para copiar y pegar en un plugin o en el archivo functions.php de tu tema (preferible usar un plugin para lógica propia del sitio).
Requisitos y contexto
- Versión mínima recomendada: WordPress 5.8 (Gutenberg estable desde 5.0 algunas utilidades avanzadas mejoran en versiones posteriores).
- Editor de bloques activo: El post type debe usar el editor de bloques para ello normalmente se usa show_in_rest => true y no se declara soporte para el editor clásico.
- Conocimientos previos: PHP básico, cómo crear un plugin o añadir código al archivo functions.php, y nociones básicas de bloques (core y personalizados).
Conceptos clave
- template: argumento de register_post_type que define una estructura de bloques inicial para nuevos posts de ese tipo (o para posts con contenido vacío).
- template_lock: controla si los editores pueden insertar/editar/borrar bloques dentro del template. Valores: false (libre), insert (no se pueden insertar nuevos bloques fuera del template), all (no se pueden mover, eliminar ni insertar).
- Estructura de la plantilla: es una matriz PHP donde cada elemento es un array con: nombre_del_bloque, atributos (array), y opcionalmente array de bloques hijos (inner blocks).
- Aplicación: por defecto la plantilla se aplica a posts nuevos o a posts con contenido vacío no sobreescribe contenido ya existente.
Registro básico de un CPT con plantilla de bloques
Ejemplo práctico: vamos a registrar un CPT llamado libro con una plantilla inicial con título, descripción, imagen destacada y un bloque personalizado para precio.
Libros, public => true, show_in_rest => true, // imprescindible para el editor de bloques supports => array(title,editor,thumbnail,excerpt), // Plantilla de bloques: array de arrays [blockName, attributes, innerBlocks?] template => array( array(core/heading, array(level => 2, placeholder => Subtítulo o autor)), array(core/paragraph, array(placeholder => Introducción o resumen corto)), array(core/image, array()), // Ejemplo de columnas anidadas: array( core/columns, array(), array( array(core/column, array(), array( array(core/paragraph, array(placeholder => Columna 1: características)) )), array(core/column, array(), array( array(core/paragraph, array(placeholder => Columna 2: notas adicionales)) )), ) ), // Bloque personalizado (debe estar registrado en el plugin/theme) array(mi-plugin/precio, array(currency => EUR, placeholder => Precio)), ), // Control del bloqueo: false insert all template_lock => insert, ) register_post_type(libro, args) } ?>
Explicación breve:
- show_in_rest => true permite que el editor de bloques funcione con este post type.
- La plantilla está compuesta por bloques core y por un bloque personalizado mi-plugin/precio (debes registrar ese bloque con el mismo nombre).
- template_lock => insert impide insertar bloques adicionales fuera de los definidos, pero permite editar su contenido y eliminarlos si procede. Si quieres que nadie borre ni mueva nada, usa all.
Cómo definir bloques anidados (innerBlocks)
La estructura para anidar bloques es la tercera posición del array del bloque. El ejemplo anterior muestra core/columns con dos core/column como hijos, y cada columna contiene su propio bloque interno.
Registrar el bloque personalizado en PHP (server-side) o en JS
Si vas a usar bloques propios en la plantilla, tienes dos opciones: registrar el bloque desde JS (bloque estático/dinámico) o registrar un renderizado server-side con register_block_type en PHP. A continuación un ejemplo sencillo de registro server-side en PHP para el bloque mi-plugin/precio:
array( price => array(type => string, default => ), currency => array(type => string, default => EUR), ), render_callback => mi_plugin_render_precio, )) } function mi_plugin_render_precio(attributes) { price = isset(attributes[price]) ? esc_html(attributes[price]) : currency = isset(attributes[currency]) ? esc_html(attributes[currency]) : EUR if (empty(price)) { return // no mostrar si no hay precio } return. currency . . price .} ?>
Nota: el bloque puede también necesitar su script de editor (JS) si quieres que el editor muestre controles personalizados. Registrar la plantilla no obliga a tener el bloque en el servidor, pero si la plantilla incluye un bloque inexistente, el editor mostrará un bloque desconocido y la UX será mala.
Bloqueo de la plantilla: opciones prácticas
- false: el editor es libre la plantilla solo sirve como punto de partida.
- insert: los bloques del template no se pueden duplicar desde fuera ni insertar bloques arbitrarios fuera del template se permite editar contenido dentro de cada bloque definido.
- all: plantilla totalmente rígida no se pueden eliminar ni mover bloques del template (ideal cuando tu CPT debe seguir exactamente una estructura).
Plantillas condicionales o dinámicas por CPT / taxonomía / usuario
Si necesitas aplicar plantillas distintas según condiciones (por ejemplo, plantilla A para un término de taxonomía, plantilla B para otro, o según rol), lo más fiable es no confiar exclusivamente en el argumento template fijo en register_post_type. En su lugar, puedes:
- Registrar el CPT sin plantilla por defecto y, al crear un post nuevo, inyectar la estructura por programación (por ejemplo, con un hook en la pantalla de edición o al insertar el post si está vacío).
- O usar JavaScript para alterar la configuración del editor en tiempo real (filtrar las configuraciones del editor desde un script que evalúe el estado del post).
Ejemplo sencillo (PHP) para poblar posts vacíos del CPT con la plantilla si están vacíos al guardarse:
post_content) ) { return } // Construir contenido de bloques manualmente (ejemplo mínimo). // Aquí se usa markup de bloques para plantillas complejas es mejor generar usando serialización de bloques. block_markup = n block_markup .=Subtítulo o autor
n block_markup .= n block_markup .= nResumen inicial del libro.
nn // Actualizar el post con el contenido generado wp_update_post(array( ID => post_ID, post_content => block_markup, )) } ?>
Importante: si generas contenido en bruto con el markup de bloques debes respetar la sintaxis de comentarios de bloques (). Para estructuras complejas considera usar funciones de serialización nativas o APIs JS que construyan el estado del editor.
Buenas prácticas y consejos
- Registra primero tus bloques personalizados (JS/PHP) antes de declarar la plantilla que los usa, así la UX en el editor será correcta.
- Usa template_lock con cuidado. Para contenidos muy estructurados preferible all, pero para flexibilidad usa insert o false.
- Versiona cambios de plantilla. Si cambias la plantilla después de tener contenido, documenta y crea un script de migración para posts existentes en vez de confiar en que WordPress re-aplique la plantilla.
- Validación y sanitización. Si tu plantilla incluye atributos de bloques que almacenan datos (por ejemplo, precios), asegúrate de sanitizar/escapar al renderizar (esc_html, esc_attr, etc.).
- Plugin vs theme: si la plantilla es parte de la lógica de contenido (por ejemplo, para un CPT de un plugin), colócala en un plugin. Si es específica del diseño del tema, colócala en el tema.
Ejemplo completo minimalista (plugin)
Archivo principal de un mini-plugin que registra el CPT y el bloque dinámico de precio. Funciona como punto de partida:
Libros, public => true, show_in_rest => true, supports => array(title,editor,thumbnail), template => array( array(core/heading, array(level => 2, placeholder => Subtítulo o autor)), array(core/paragraph, array(placeholder => Resumen corto)), array(mi-plugin/precio, array(currency => EUR)), ), template_lock => insert, )) } add_action(init, mi_plugin_registrar_bloque_precio) function mi_plugin_registrar_bloque_precio() { register_block_type(mi-plugin/precio, array( attributes => array( price => array(type => string, default => ), currency => array(type => string, default => EUR), ), render_callback => mi_plugin_render_precio, )) } function mi_plugin_render_precio(attributes) { price = isset(attributes[price]) ? esc_html(attributes[price]) : currency = isset(attributes[currency]) ? esc_html(attributes[currency]) : EUR if (empty(price)) { return } return. currency . . price .} ?>
Recursos adicionales
Documentación oficial y guías útiles:
Resumen
Registrar plantillas de bloque para un CPT desde PHP es directo: define la propiedad template dentro de los argumentos de register_post_type, asegúrate de que show_in_rest sea true, registra cualquier bloque personalizado necesario y decide cómo quieres bloquear la estructura con template_lock. Para cambios posteriores en estructuras ya publicadas, prepara scripts de migración para evitar inconsistencias.
|
Acepto donaciones de BAT's mediante el navegador Brave 🙂 |