Crea bloques personalizados solo con PHP. Adiós a los shortcodes clásicos 🥳
Crear bloques de Gutenberg ha implicado React, Node.js y un pipeline de compilación desde que WordPress 5.0 introdujo el editor de bloques. Si tus habilidades están en PHP —como las mías y las de la mayoría de desarrolladores de WordPress—, esa barrera te ha mantenido al margen durante casi una década. WordPress 7.0 cambia esto. Los bloques solo-PHP te permiten registrar un bloque de Gutenberg totalmente funcional con un único archivo PHP y el flag autoRegister.
Escribes PHP. Obtienes un bloque. Sin herramientas. Sin compilación. 🥳 En este artículo verás cómo funcionan los bloques solo-PHP y recorrerás un ejemplo del mundo real que reemplaza un shortcode clásico por su equivalente en bloque.
¿Qué son los bloques solo-PHP?
Hasta ahora, crear un bloque de Gutenberg personalizado significaba configurar una cadena de herramientas de JavaScript: npm install, un archivo block.json, un paso de compilación con webpack.config.js o @wordpress/scripts, y un componente edit.js escrito en JSX. Cada cambio requería un paso de compilación antes de poder verlo en el editor. Para un desarrollador de PHP que solo quiere registrar un sencillo bloque de presentación, esa sobrecarga siempre ha resultado desproporcionada para la tarea.
Los bloques solo-PHP eliminan todo eso. Ahora, en register_block_type() solo necesitas pasar 'autoRegister' => true, y WordPress se encarga de todo lo del lado de JavaScript automáticamente usando ServerSideRender. El bloque aparece en el insertador, renderiza una vista previa en vivo en el lienzo y genera controles del Inspector en la barra lateral, todo ello sin una sola línea de JavaScript por tu parte.
Los controles se generan automáticamente según el tipo de atributo:
| Tipo de atributo | Control del Inspector generado |
|---|---|
string | Campo de texto |
integer / number | Campo numérico |
boolean | Interruptor |
string + enum | Lista desplegable |
Los controles autogenerados cubren por ahora solo los cuatro tipos anteriores. Cualquier cosa más compleja, como selectores de imágenes, subidas de medios o datos anidados, todavía no está soportada y requeriría un bloque registrado con JavaScript. Los desarrolladores también pueden marcar atributos individuales con un rol local para señalarlos como estado interno; WordPress los omite al construir los controles de la barra lateral.
Los bloques solo-PHP están disponibles hoy en WordPress 7.0 sin ninguna dependencia adicional. Lee más en la nota oficial para desarrolladores en Make WordPress Core.
¿Para quién es esto?
Las agencias más pequeñas y los freelancers sin un profundo conocimiento de JavaScript ahora pueden crear soluciones para el editor de bloques que aprovechen al máximo las funciones nativas de WordPress sin tocar un pipeline de compilación. Si quieres ofrecer bloques de Gutenberg personalizados específicos de un tema —como cajas de autor, citas destacadas, testimonios, banners de CTA, avisos y elementos similares— en lugar de recurrir a los shortcodes, los bloques solo-PHP ayudan a reducir esa barrera de forma significativa.
No son un reemplazo de los bloques registrados con JavaScript cuando necesitas edición de texto enriquecido en línea, una interfaz reactiva en tiempo real o anidamiento de bloques internos, pero para una amplia categoría de bloques de presentación estructurados, dan en el clavo.
La forma antigua: los shortcodes
Antes de los bloques solo-PHP, el enfoque práctico para un desarrollador de PHP era un shortcode. Aquí tienes un sencillo shortcode de testimonio con tres atributos: el nombre del autor, la empresa, una valoración por estrellas, más el contenido interno para el texto de la reseña:
function testimonial_shortcode( $atts, $content = '' ) {
$atts = shortcode_atts( [
'name' => '',
'company' => '',
'stars' => 5,
], $atts );
$stars_count = max( 1, min( 5, intval( $atts['stars'] ) ) );
$stars_html = str_repeat( '★', $stars_count )
. str_repeat( '☆', 5 - $stars_count );
return sprintf(
'<blockquote class="testimonial">
<p class="testimonial__stars">%s</p>
<p class="testimonial__body">%s</p>
<footer class="testimonial__attribution">
<strong>%s</strong>%s
</footer>
</blockquote>',
esc_html( $stars_html ),
wp_kses_post( $content ),
esc_html( $atts['name'] ),
$atts['company'] ? ', ' . esc_html( $atts['company'] ) : ''
);
}
add_shortcode( 'testimonial', 'testimonial_shortcode' );Uso:
[testimonial name="Sarah K." company="Acme Corp" stars="4"]
Saved us hours every week.
[/testimonial]
Funciona... pero no es más que un shortcode 🤷🏻♂️
Estos son solo algunos de los problemas de los shortcodes:
- Invisibles en el editor. El autor ve
[testimonial name="Sarah K." ...]en el editor, no la tarjeta renderizada. No hay vista previa. - No son descubribles. Tienes que saber que el shortcode existe y recordar los nombres de sus parámetros. Nada lo muestra en la interfaz.
- Sin controles de estilo nativos. Ajustar el color, el espaciado o la tipografía requiere CSS personalizado o atributos adicionales conectados manualmente.
- El contenido interno no es texto enriquecido. El cuerpo de la reseña se pasa como una cadena simple en
$content, no como un área de texto enriquecido editable.
Los shortcodes fueron la herramienta adecuada para su época. El editor de bloques ofrece algo mejor, pero ha sido difícil de aprovechar. WordPress 7.0 ofrece un atajo en forma de bloques solo-PHP.
Para que quede claro: la forma correcta y moderna de crear un bloque de Gutenberg sigue siendo un bloque registrado con JavaScript con un componente edit completo. Los bloques solo-PHP son un camino simplificado, deliberadamente acotado a bloques renderizados en el servidor que no necesitan edición enriquecida en el lienzo. No son un reemplazo de los bloques de JavaScript, sino una nueva opción para casos de uso más sencillos donde la sobrecarga de un pipeline de compilación y componentes de React no se justifica.
Una opción más sencilla: los bloques solo-PHP
Construyamos el mismo testimonio como un bloque personalizado de WordPress solo con PHP. La receta: register_block_type() con 'autoRegister' => true en supports, más un render_callback.
Aquí está el código completo del bloque:
function my_plugin_register_testimonial_block() {
register_block_type(
'my-plugin/testimonial', // Block name: namespace/slug
array(
'title' => 'Testimonial', // Shown in the block inserter
'attributes' => array(
// string attributes generate a text input in the sidebar
'name' => array(
'type' => 'string',
'default' => '',
),
'company' => array(
'type' => 'string',
'default' => '',
),
// integer attributes generate a number input
'stars' => array(
'type' => 'integer',
'default' => 5,
),
'body' => array(
'type' => 'string',
'default' => '',
),
),
// render_callback is the PHP function that outputs the block's HTML
'render_callback' => function ( $attributes ) {
$stars_count = max( 1, min( 5, intval( $attributes['stars'] ) ) );
$stars_html = str_repeat( '★', $stars_count )
. str_repeat( '☆', 5 - $stars_count );
// Translatable string for screen readers — standard WordPress i18n, nothing extra needed
/* translators: %d: star rating out of 5 */
$stars_label = sprintf( __( '%d out of 5 stars', 'my-plugin' ), $stars_count );
return sprintf(
'<blockquote %s>
<p class="testimonial__stars" aria-label="%s">%s</p>
<p class="testimonial__body">%s</p>
<cite class="testimonial__attribution">
<strong>%s</strong>%s
</cite>
</blockquote>',
// Merges your class with editor-added colour, spacing, and typography styles
get_block_wrapper_attributes( array( 'class' => 'testimonial wp-block-quote' ) ),
esc_attr( $stars_label ),
esc_html( $stars_html ),
wp_kses_post( $attributes['body'] ),
esc_html( $attributes['name'] ),
$attributes['company'] ? ', ' . esc_html( $attributes['company'] ) : ''
);
},
'supports' => array(
// The key flag — tells WordPress to handle JS registration automatically
'autoRegister' => true,
// The rest unlock native colour, typography, and spacing panels in the sidebar
'color' => array(
'background' => true,
'text' => true,
),
'typography' => array(
'fontSize' => true,
),
'spacing' => array(
'padding' => true,
'margin' => true,
),
),
)
);
}
add_action( 'init', 'my_plugin_register_testimonial_block' );El resultado:

Hay algunas cosas que señalar aquí. Primero, el contenido interno de un shortcode no tiene un equivalente directo en los bloques solo-PHP. El cuerpo de la reseña se convierte en un atributo string editable desde los controles del Inspector de la barra lateral: un campo de texto de una sola línea, no un área de texto enriquecido en el lienzo. Para una cita de testimonio corta esto está bien. Para textos de cuerpo más largos querrías un bloque registrado con JavaScript con un componente RichText.
Segundo, get_block_wrapper_attributes() combina tu clase con lo que el editor añade para el color, la tipografía y el espaciado, de modo que los paneles de estilo nativos funcionan sin ninguna conexión de CSS adicional. El render_callback recibe un array $attributes que contiene solo los valores que el usuario estableció; no hay parámetro $content, porque el contenido interno no está soportado.
Lo que obtienes frente a la versión con shortcode:
- Vista previa en vivo en el lienzo del editor. Se acabó la sintaxis cruda de shortcode: el autor ve la tarjeta de testimonio renderizada mientras edita.
- Controles autogenerados. El nombre, la empresa, el cuerpo (campos de texto) y las estrellas (campo numérico) aparecen automáticamente en los controles del Inspector de la barra lateral.
- Paneles nativos de color, fuente y espaciado. Provienen de
supports, sin necesidad de CSS personalizado. - Descubrible. El bloque aparece en el insertador bajo su nombre, con un icono.
Listo para traducción desde el primer momento
Hay dos preocupaciones de traducción distintas al trabajar con bloques solo-PHP, y conviene tener claro cuál es cuál.
La primera son las cadenas estáticas integradas en tu plantilla de PHP: etiquetas, textos de botones, textos de la interfaz. Estas se gestionan con __() y _e(), igual que en cualquier archivo PHP de WordPress. En el bloque anterior, la etiqueta de las estrellas es un ejemplo:
/* translators: %d: star rating out of 5 */
$stars_label = sprintf( __( '%d out of 5 stars', 'my-plugin' ), $stars_count );Las herramientas estándar de WordPress las detectan automáticamente. No se necesita nada más.
La segunda preocupación es el contenido introducido por el usuario y almacenado como atributos del bloque: el cuerpo del testimonio, el nombre del reseñador, la empresa. Este es el contenido que tus editores realmente escriben en el bloque, y __() no lo toca. En un sitio multilingüe, estos valores de atributos deben traducirse a cada idioma por separado, y eso no es algo que WordPress gestione por sí solo.
Gato AI Translations for Polylang es compatible con los bloques solo-PHP desde el primer momento, del mismo modo que es compatible con Gutenberg, Bricks, Elementor y otros constructores de páginas. No se requiere ninguna configuración adicional.
Todos los atributos de tipo string se registran automáticamente para su traducción. Si un campo concreto no debe traducirse —una referencia interna, una URL, un código numérico almacenado como cadena—, puedes excluirlo con un filtro.
Para el bloque de testimonio de este artículo, el nombre del reseñador, la empresa y el texto del cuerpo se traducen todos automáticamente, sin más configuración que instalar el plugin.
Lo que los bloques solo-PHP (aún) no pueden hacer
Las limitaciones actuales de los bloques solo-PHP:
- Sin bloques internos ni anidamiento. No puedes colocar otros bloques dentro de un bloque solo-PHP.
- Sin edición de texto enriquecido en el lienzo. El componente
RichTextrequiere JavaScript. Los controles de texto se renderizan únicamente como un campo de texto en la barra lateral. - Los campos de cadena de la barra lateral son de una sola línea. Un atributo
stringse convierte en unTextControl, no en unTextareaControl, lo que no es ideal para textos más largos. - Sin atributos de selección de imágenes o medios. El soporte para subida de imágenes/archivos está previsto para una versión posterior a través de la Block Fields API.
- La vista previa del editor tiene un retardo de ida y vuelta. Los cambios de atributos disparan una petición a la REST API para volver a renderizar en el servidor, así que la vista previa no se actualiza al instante.
Para bloques estructurados sencillos —testimonios, CTAs, avisos, biografías de autor, listados de empresas—, los bloques solo-PHP dan en el clavo. Para cualquier cosa que requiera edición enriquecida en el lienzo, el registro con JavaScript sigue siendo la herramienta adecuada.
Lo que viene a continuación
Los bloques solo-PHP de WordPress 7.0 ponen el desarrollo de bloques al alcance de cualquier desarrollador de PHP. Un archivo PHP, una llamada a register_block_type(), y tienes un bloque de Gutenberg totalmente funcional con controles en la barra lateral, una vista previa en vivo en el lienzo y soporte de estilos nativos. Escribes PHP. Obtienes un bloque. Sin herramientas. Sin compilación. Sin JavaScript.
Si estás creando sitios multilingües, Gato AI Translations funciona a la perfección con los bloques solo-PHP: tu contenido es traducible desde el primer día.
¿Listo para ir más allá?
- Developing WordPress blocks without JSX or a build process — para desarrolladores que quieran añadir JavaScript mínimo sin un pipeline de compilación completo
- Beginner WordPress Developer course — una base completa para el desarrollo de bloques