Como crear un bloque que renderiza en servidor con render_callback (PHP) en WordPress

Contents

Introducción

Un bloque renderizado en servidor (server-rendered block) en WordPress es un bloque cuyo marcado HTML final se genera en PHP cuando se carga la página o se obtiene el contenido, en lugar de generarlo totalmente en el editor con JavaScript. Esto permite combinar datos dinámicos del servidor, ejecutar lógica compleja, aplicar sanitización estricta y controlar rendimiento (caché) desde PHP. En este artículo se explican con todo detalle los pasos para crear un bloque que utiliza render_callback en PHP, ejemplos completos de código, buenas prácticas de seguridad y rendimiento, y cómo empaquetarlo como plugin.

Requisitos previos

  • WordPress 5.0 (recomendado 5.8 para API de bloques moderna).
  • Conocimientos básicos de PHP, JavaScript (ESNext), y React/JSX para el editor.
  • Acceso al servidor para crear un plugin o los archivos del tema.
  • WP_DEBUG activado para depurar (opcional pero recomendado).

Concepto general y flujo

Flujo básico de un bloque con render_callback:

  1. Se registra el bloque (block.json script del editor y estilos).
  2. En el editor, el bloque muestra controles y permite editar atributos.
  3. Los atributos se guardan en el contenido (serialized dentro del comentario del bloque).
  4. En el front-end (o en REST cuando se solicita), WordPress llama a la función render_callback en PHP, que recibe los atributos y devuelve el HTML final del bloque.

Estructura recomendada del plugin / bloque

Archivo / Carpeta Descripción
my-dynamic-block/ Carpeta raíz del plugin
my-dynamic-block/block.json Metadatos del bloque
my-dynamic-block/src/index.js Script del editor (JS/React)
my-dynamic-block/src/editor.css Estilos para el editor
my-dynamic-block/src/style.css Estilos para el front-end
my-dynamic-block/my-dynamic-block.php Archivo principal del plugin con register_block_type y render_callback

Paso 1 — block.json (metadatos)

Ejemplo minimalista de block.json para un bloque que renderiza en servidor. Define atributos y los scripts/estilos que se usan.

{
  apiVersion: 2,
  name: mi-plugin/testimonial-dynamic,
  title: Testimonial Dinámico,
  category: widgets,
  icon: format-quote,
  description: Un testimonio renderizado en servidor con render_callback.,
  attributes: {
    quote: {
      type: string,
      source: html,
      selector: .testimonial-quote
    },
    author: {
      type: string,
      source: text,
      selector: .testimonial-author
    }
  },
  editorScript: file:./build/index.js,
  editorStyle: file:./build/editor.css,
  style: file:./build/style.css
}

Paso 2 — Script del editor (src/index.js)

En el editor utilizamos componentes de RichText y guardamos atributos. La versión save devuelve null (o no se declara), porque el HTML lo produce PHP en render_callback. Para la mayoría de bloques dinámicos con API v2, save debe devolver null.

import { registerBlockType } from @wordpress/blocks
import { RichText, InspectorControls } from @wordpress/block-editor
import { PanelBody, TextControl } from @wordpress/components
import { __ } from @wordpress/i18n

registerBlockType( mi-plugin/testimonial-dynamic, {
  edit: ( props ) => {
    const { attributes, setAttributes } = props
    const { quote = , author =  } = attributes

    return (
      
setAttributes( { author: value } ) } /> setAttributes( { quote: value } ) } placeholder={ __( Escribe el testimonio..., mi-plugin ) } />
setAttributes( { author: value } ) } placeholder={ __( Autor, mi-plugin ) } />
) }, save: () => { // Save en server: devolver null hace que WP use render_callback en PHP return null }, } )

Paso 3 — Archivo principal del plugin y render_callback (PHP)

Registro del bloque y definición de la función que genera el HTML final. Aquí se muestra un plugin simple que registra el bloque leyendo block.json y pasando la función de render.

 mi_testimonial_dynamic_render_callback,
    ) )
}
add_action( init, mi_testimonial_dynamic_register_block )

/
  Función de renderizado en servidor.
 
  @param array attributes Atributos del bloque.
  @param string content Contenido en bruto (no siempre presente).
  @return string HTML final del bloque.
 /
function mi_testimonial_dynamic_render_callback( attributes, content ) {
    // Atributos por defecto
    defaults = array(
        quote  => ,
        author => ,
    )
    atts = wp_parse_args( attributes, defaults )

    // Saneamiento de atributos (evitar XSS)
    quote  = isset( atts[quote] ) ? wp_kses_post( atts[quote] ) : 
    author = isset( atts[author] ) ? sanitize_text_field( atts[author] ) : 

    // Si no hay contenido útil, devolver vacío para evitar output innecesario
    if ( empty( trim( wp_strip_all_tags( quote ) ) ) ) {
        return 
    }

    // Construcción del HTML con escapado correcto
    html  = 

    return html
}

Notas sobre el registro con register_block_type vs register_block_type_from_metadata

En el ejemplo anterior se usa register_block_type pasando la ruta al block.json, que funciona con las versiones modernas de WordPress y en muchos contextos. También puedes usar register_block_type_from_metadata si quieres comportamientos específicos. Lo esencial es que la función PHP pase la opción render_callback para indicar que el bloque es dinámico y su output lo genera PHP.

Seguridad y saneamiento

  • wp_kses_post() o wp_kses() para permitir HTML seguro en atributos que contienen HTML (por ejemplo, quote).
  • sanitize_text_field() o esc_html() para datos simples de texto (p. ej. autor).
  • Evitar concatenar atributos sin escapar. Usar esc_attr(), esc_url() según corresponda.
  • Validar atributos esperados y establecer valores por defecto con wp_parse_args.

Encolado de estilos y scripts

Si utilizas block.json y build con @wordpress/scripts, WordPress registrará y encolará los assets correctamente cuando uses register_block_type con la ruta a block.json. Si no, puedes registrar estilos manualmente en PHP y pasarlos en register_block_type.

function mi_testimonial_register_assets() {
    dir = plugin_dir_url( __FILE__ )

    wp_register_style(
        mi-testimonial-style,
        dir . build/style.css,
        array(),
        filemtime( plugin_dir_path( __FILE__ ) . build/style.css )
    )

    wp_register_style(
        mi-testimonial-editor-style,
        dir . build/editor.css,
        array( wp-edit-blocks ),
        filemtime( plugin_dir_path( __FILE__ ) . build/editor.css )
    )

    register_block_type( __DIR__ . /block.json, array(
        render_callback => mi_testimonial_dynamic_render_callback,
        style           => mi-testimonial-style,
        editor_style    => mi-testimonial-editor-style,
    ) )
}
add_action( init, mi_testimonial_register_assets )

Ejemplo avanzado: datos dinámicos del servidor y cache con transients

Si tu bloque consulta datos costosos (p. ej. una API externa o WP_Query complejo), guarda resultados en transients para mejorar rendimiento y evitar cálculo en cada solicitud.

function mi_testimonial_dynamic_render_callback( attributes ) {
    cache_key = mi_testimonial_html_ . md5( serialize( attributes ) )
    cached = get_transient( cache_key )
    if ( cached ) {
        return cached
    }

    // Ejemplo: consulta de datos costosa (simulada)
    quote_html = 
. wp_kses_post( attributes[quote] ) .
author_html = ! empty( attributes[author] ) ?

. esc_html( attributes[author] ) .

: html = // Guardar en transient por 1 hora set_transient( cache_key, html, HOUR_IN_SECONDS ) return html }

Depuración y pruebas

  • Activa WP_DEBUG y WP_DEBUG_LOG para ver errores en el archivo debug.log.
  • Usa error_log() en la función PHP para comprobar valores de atributos en tiempo de renderizado (temporalmente).
  • Comprueba en el editor que al editar y guardar los atributos se reflejan correctamente en el HTML generado en front.
  • Si usas build con @wordpress/scripts, abre la consola del navegador para ver errores de JS en el editor.

Buenas prácticas

  • Usa atributos simples y evita guardar HTML complejo en atributos si puedes en su lugar, genera HTML en PHP usando los datos guardados.
  • Sanitiza siempre en PHP: editar en el navegador no sustituye el saneamiento del servidor.
  • Considera la accesibilidad: roles ARIA, etiquetas semánticas y estructura HTML adecuada.
  • Si el bloque es público y presenta datos externos, planifica una estrategia de cache y invalidación (transients, cache de objeto, etc.).

Resumen técnico

Crear un bloque que renderiza en servidor con render_callback implica:

  1. Definir la metadata del bloque en block.json (atributos, scripts, estilos).
  2. Crear el script del editor en JavaScript que permita editar atributos y devolver null en save().
  3. Registrar el bloque en PHP y proporcionar la función render_callback que genere el HTML final.
  4. Saneamiento en PHP con wp_kses_post, sanitize_text_field, esc_html, esc_url, etc.
  5. Considerar encolado de assets, rendimiento (cache) y pruebas en entornos con WP_DEBUG.

Recursos útiles



Acepto donaciones de BAT's mediante el navegador Brave 🙂



Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *