¿Todavía estás desconcertado por Gutenberg? ¿O eres de los que creen firmemente en el potencial del editor de bloques y quieres descubrir hasta dónde puede llegar su creatividad utilizando el editor de bloques?

Sea cual sea la categoría de usuarios a la que pertenezcas, Gutenberg ha llegado para quedarse y este post te dará una visión general en profundidad de lo que ocurre entre bastidores del editor de bloques de WordPress. ¡Pero eso no es todo!

Tras nuestro anterior tutorial, en el que proporcionamos una introducción general al desarrollo de bloques de Gutenberg, este artículo va más allá de lo básico, presentando tipos de bloques más avanzados. Estos bloques se denominan bloques dinámicos.

Hoy aprenderás qué son los bloques dinámicos, cómo funcionan y todo lo que necesitas saber para crear bloques dinámicos desde cero.

Entonces, ¿qué son los bloques dinámicos de Gutenberg y cuáles son las principales diferencias entre los bloques estáticos y los dinámicos?

¿Qué Son Los Bloques Dinámicos? Un Ejemplo

Mientras que con los bloques estáticos el contenido es añadido manualmente por el usuario mientras edita una entrada o página, con los bloques dinámicos el contenido se carga y procesa sobre la marcha al cargar la página. Con los bloques dinámicos, el contenido del bloque se recoge de la base de datos y se muestra tal cual o como resultado de cualquier tipo de manipulación de datos.

Vamos a explicarlo con un ejemplo. Digamos que quieres crear un grupo de bloques anidados que muestren los detalles del autor de la entrada con una selección de las últimas entradas del mismo autor.

Un bloque de grupo que incluye el autor de la publicación y sus últimas publicaciones
Un bloque de grupo que incluye el autor de la publicación y sus últimas publicaciones

Como usuarios de Gutenberg, podrías utilizar los siguientes bloques:

  • El bloque del core Encabezamiento
  • El bloque del core Autor de la publicación
  • El bloque del core Últimas publicaciones

También podrías crear un grupo que incluya esos bloques y añadir el grupo a los bloques reutilizables para su uso futuro.

Añadiendo un bloque de grupo a bloques reutilizables
Añadiendo un bloque de grupo a bloques reutilizables

Es bastante sencillo, ¿verdad? Puedes crear un bloque dinámico y añadirlo a tus publicaciones y páginas en un abrir y cerrar de ojos.

A partir de WordPress 5.9, el editor de bloques ofrece más de 90 bloques diferentes, y lo más probable es que encuentres el bloque adecuado para ti nada más sacarlo de la caja. Y, si necesitas más, haz una búsqueda rápida en el directorio de plugins de WordPress y encontrarás un montón de plugins gratuitos que proporcionan bloques adicionales.

Pero, ¿qué ocurre si eres un desarrollador de WordPress – o estás planeando una carrera como desarrollador de WordPress? Quizá tengas necesidades muy específicas y no encuentres el bloque que buscas, o simplemente quieras adquirir nuevas habilidades profesionales. En tales situaciones, es posible que quieras aprender a crear tus bloques dinámicos.

Los Bloques Dinámicos de Gutenberg desde la Perspectiva del Desarrollador

Los bloques dinámicos tienen dos casos de uso principales.

El primer caso de uso es cuando necesitas actualizar el contenido de un bloque cuando la página que lo contiene no se ha actualizado. Por ejemplo, esto ocurre cuando el bloque incluye una lista de las últimas publicaciones o comentarios, y en general siempre que el contenido del bloque se genera dinámicamente utilizando datos recuperados de la base de datos.

Añadiendo un bloque de Query Loop
Añadiendo un bloque de Query Loop

El segundo caso de uso es cuando una actualización del código del bloque debe mostrarse inmediatamente en el front-end. Utilizar un bloque dinámico en lugar de un bloque estático hace que los cambios se apliquen inmediatamente a todas las apariciones del bloque.

En cambio, si cambiaras el HTML producido por un bloque estático, el usuario verá un diálogo de invalidación hasta que se eliminen todas las instancias de la versión anterior del bloque y se sustituyan por la nueva versión, o bien marques la versión antigua como obsoleta (consulta también la Deprecación y Validación de Bloques, Deprecación y Experiencia de Migración).

Contenido inesperado o no válido.
Contenido inesperado o no válido.

Dicho esto, hay algunos conceptos que debes entender antes de empezar a construir bloques dinámicos.

Estado de la Aplicación y Almacenamiento de los Datos

Gutenberg es una aplicación React SPA, y todo en Gutenberg es un componente React. El título de la entrada, los encabezados, los párrafos, las imágenes y cualquier bloque de contenido HTML en el editor es un componente React, así como los controles de la barra lateral y de la barra de herramientas del bloque.

En nuestro artículo anterior, sólo utilizamos propiedades para almacenar datos. En este artículo, daremos un paso más introduciendo el concepto de estado.

En pocas palabras, el objeto state es un objeto JavaScript simple que se utiliza para contener información sobre un componente. El state del componente puede cambiar con el tiempo, y cada vez que cambia, el componente se vuelve a renderizar.

Al igual que el objeto state, las propiedades son objetos JavaScript planos que se utilizan para contener información sobre el componente. Pero hay una diferencia clave entre las propiedades y state:

props se pasan al componente (similar a los parámetros de una función) mientras que state se gestiona dentro del componente (similar a las variables declaradas dentro de una función).

Puedes pensar en el estado como una instantánea de datos tomada en un momento dado que una aplicación almacena para controlar el comportamiento de un componente. Por ejemplo, si la barra lateral de ajustes del editor de bloques está abierta, se almacenará una información en algún lugar del objeto state.

Cuando la información se comparte dentro de un solo componente, lo llamamos estado local. Cuando la información se comparte entre los componentes de una aplicación, lo llamamos Estado de la Aplicación.

El Estado de la Aplicación está estrechamente relacionado con el concepto de almacenamiento. Según los documentos de Redux

Un almacén contiene todo el árbol de estado de tu aplicación. La única forma de cambiar el estado dentro de él es enviar una acción sobre él.

Por tanto, Redux almacena el estado de una aplicación en un único árbol de objetos inmutable (es decir, un almacén). El árbol de objetos sólo puede cambiarse creando un nuevo objeto mediante acciones y reductores.

En WordPress, los almacenes son gestionados por el módulo de datos de WordPress.

Modularidad, Paquetes y Almacenes de Datos en Gutenberg

El repositorio de Gutenberg está construido desde cero sobre varios módulos reutilizables e independientes que, combinados entre sí, construyen la interfaz de edición. Estos módulos también se denominan paquetes.

La documentación oficial enumera dos tipos diferentes de paquetes:

  • Los paquetes de producción conforman el código de producción que se ejecuta en el navegador. Hay dos tipos de paquetes de producción en WordPress:
    • Los paquetes con hojas de estilo proporcionan hojas de estilo para que funcionen correctamente.
    • Los paquetes con almacenes de datos definen almacenes de datos para manejar su estado. Los paquetes con almacenes de datos pueden ser utilizados por plugins y temas de terceros para recuperar y manipular datos.
  • Los paquetes de desarrollo se utilizan en el modo de desarrollo. Estos paquetes incluyen herramientas para linting, pruebas, construcción, etc.

Aquí nos interesan sobre todo los paquetes con almacenes de datos, utilizados para recuperar y manipular datos.

El Almacén de Datos de WordPress

El módulo de datos de WordPress está construido sobre Redux y comparte los tres principios básicos de Redux, aunque con algunas diferencias clave.

La documentación oficial ofrece la siguiente definición

El módulo de datos de WordPress sirve como centro para gestionar el estado de la aplicación tanto para los plugins como para el propio WordPress, proporcionando herramientas para gestionar los datos dentro de los distintos módulos y entre ellos. Está diseñado como un patrón modular para organizar y compartir datos: lo suficientemente simple como para satisfacer las necesidades de un pequeño plugin, a la vez que escalable para cumplir los requisitos de una aplicación compleja de una sola página.

Por defecto, Gutenberg registra varios almacenes de datos del estado de la aplicación. Cada uno de estos almacenes tiene un nombre y un propósito específicos:

A través de estos almacenes, podrás acceder a un montón de datos:

  1. Datos relacionados con la entrada actual, como el título de la entrada, el extracto, las categorías y etiquetas, los bloques, etc.
  2. Datos relacionados con la interfaz de usuario, como por ejemplo, si un interruptor está activado o desactivado.
  3. Datos relacionados con toda la instalación de WordPress, como las taxonomías registradas, los tipos de entradas, el título del blog, los autores, etc.

Estos almacenes viven en el objeto global wp. Para acceder al estado de un almacén, utilizarás la función select.

Para ver cómo funciona, crea una nueva entrada o página y lanza el inspector de navegador. Busca la consola y escribe la siguiente línea de código:

wp.data.select("core")

El resultado será un objeto que incluye una lista de funciones que puedes utilizar para obtener datos del almacén de datos core. Estas funciones se llaman selectores y actúan como interfaces para acceder a los valores de estado.

El objeto del almacén de datos del core de WordPress
El objeto del almacén de datos del core de WordPress

El almacén de datos de WordPress incluye información sobre WordPress en general y los selectores son la forma de obtener esa información. Por ejemplo, getCurrentUser() devuelve los detalles del usuario actual:

wp.data.select("core").getCurrentUser()
Inspecting getCurrentUser response
Inspeccionando la respuesta de getCurrentUser

Otro selector que puedes utilizar para recuperar los detalles del usuario del almacén de datos es getUsers() :

wp.data.select("core").getUsers()

La siguiente imagen muestra el objeto de respuesta:

Inspecting getUsers response
Inspeccionando la respuesta de getUsers

Para obtener los detalles de un solo usuario, puedes escribir la siguiente línea

wp.data.select("core").getUsers()[0]

Utilizando el mismo selector también puedes recuperar los usuarios del sitio con el rol author asignado:

wp.data.select( 'core' ).getUsers({ who: 'authors' })

También puedes recuperar las taxonomías registradas:

wp.data.select("core").getTaxonomies()
Inspecting getTaxonomies response.
Inspeccionando la respuesta de getTaxonomies.

Una lista de los tipos de correos registrados:

wp.data.select("core").getPostTypes()

O una lista de plugins:

wp.data.select("core").getPlugins()

Ahora vamos a intentar acceder a un almacén de datos diferente. Para ello, seguirás utilizando la función select, pero proporcionando un espacio de nombres diferente. Intentemos lo siguiente:

wp.data.select("core/edit-post")

Ahora obtendrás el siguiente objeto de respuesta.

Accessing the Editor’s UI Data
Accediendo a los datos de la IU del editor

Si quieres saber si la barra lateral de ajustes está abierta o no, utilizarás el selector isEditorSidebarOpened:

wp.data.select("core/edit-post").isEditorSidebarOpened()

Esta función devuelve true si la barra lateral está abierta:

The sidebar is open.
La barra lateral está abierta.

Cómo acceder a los datos de las publicaciones

Ahora deberías tener una comprensión básica de cómo acceder a los datos. Ahora veremos con más detalle un selector específico, la funcióngetEntityRecords , que es el selector que da acceso a los datos de la entrada.

En el editor de bloques, haz clic con el botón derecho y selecciona Inspeccionar. En la pestaña Consola, copia y pega la siguiente línea:

wp.data.select("core").getEntityRecords('postType', 'post')

Esto envía una petición a la API Rest y devuelve una matriz de registros correspondientes a las últimas entradas del blog publicadas.

getEntityRecords returns a list of posts.
getEntityRecords devuelve una lista de entradas.

getEntityRecords acepta tres parámetros:

  • kind cadena: Tipo de entidad (por ejemplo, postType).
  • name cadena: Nombre de la entidad (por ejemplo, post).
  • query objeto: Consulta de términos opcional (es decir, {author: 0}).

Puedes construir peticiones más específicas utilizando un objeto de argumentos.

Por ejemplo, puedes decidir que la respuesta sólo contenga entradas de una categoría determinada:

wp.data.select("core").getEntityRecords('postType', 'post', {categories: 3})

También puedes solicitar sólo artículos de un autor determinado:

wp.data.select("core").getEntityRecords('postType', 'post', {author: 2})

Si haces clic en cualquiera de los registros devueltos por getEntityRecords, obtendrás una lista de propiedades del registro seleccionado:

An example API request with getEntityRecords.
Un ejemplo de solicitud de la API con getEntityRecords.

Si quieres que la respuesta incluya la imagen destacada, tendrás que añadir un argumento adicional a tu petición anterior:

wp.data.select("core").getEntityRecords('postType', 'post', {author: 2, _embed: true})
Featured image details in getEntityRecords response.
Detalles de la imagen destacada en la respuesta de getEntityRecords.

Ahora deberías entender mejor cómo acceder al almacén de datos de WordPress y recuperar los detalles de las entradas. Para ver más de cerca el selector getEntityRecords, consulta también Solicitud de datos en Gutenberg con getEntityRecords.

Cómo crear un bloque dinámico: Un proyecto de ejemplo

Tras nuestra larga premisa teórica, podemos pasar a la práctica y crear un bloque dinámico utilizando las herramientas que introdujimos en nuestro anterior tutorial de desarrollo de bloques.

En ese artículo, hablamos de:

  1. Cómo configurar un entorno de desarrollo de WordPress
  2. Qué es un andamio de bloques
  3. Cómo construir un bloque estático de Gutenberg

Por eso no trataremos esos temas en profundidad en el presente artículo, pero no dudes en consultar nuestra guía anterior para obtener información adicional, o simplemente para refrescarla.

Configurar un entorno de desarrollo de JavaScript

Empecemos por configurar un entorno de desarrollo de JavaScript.

Instala o actualiza Node.js

Primero, instala o actual iza Node.js. Una vez hecho esto, lanza tu herramienta de línea de comandos y ejecuta el siguiente comando:

node -v

Deberías ver tu versión de Node.

Configura tu entorno de desarrollo

A continuación, necesitarás un entorno de desarrollo para WordPress. Para nuestros ejemplos, hemos utilizado DevKinsta, nuestra herramienta gratuita de desarrollo de WordPress que te permite poner en marcha un sitio web local de WordPress en muy poco tiempo.

Creating a custom site in DevKinsta
Creando un sitio personalizado en DevKinsta

Pero sigues siendo libre de elegir el entorno de desarrollo local de WordPress que quieras, como MAMP o XAMPP, o incluso la solución oficial wp-env.

Si utilizas DevKinsta, haz clic en Nuevo sitio de WordPress o en Sitio personalizado, rellena los campos del formulario y pulsa Crear sitio.

El proceso de instalación dura uno o dos minutos. Cuando se haya completado, lanza tu sitio local de desarrollo de WordPress.

Site Info screen in DevKinsta.
Pantalla de información del sitio en DevKinsta.

Configura tu plugin de bloques

Lo que necesitas ahora es un plugin de bloque inicial. Para evitar toda la molestia de una configuración manual, el equipo de desarrolladores del núcleo de WordPress lanzó la herramienta @wordpress/create-block, que es la herramienta oficial de configuración cero para crear bloques Gutenberg.

Hemos cubierto @wordpress/create-block en profundidad en nuestro artículo anterior, así que aquí podemos empezar la configuración de inmediato.

En tu herramienta de línea de comandos, navega a la carpeta /wp-content/plugins:

New terminal at folder in Mac OS.
Nuevo terminal en la carpeta en Mac OS.

Una vez allí, ejecuta el siguiente comando:

npx @wordpress/create-block

Ahora estás listo para instalar el paquete @wordpress/create-block:

Installing the @wordpress/create-block package.
Instalando el paquete @wordpress/create-block.

Para confirmar, escribe y y pulsa Intro.

Esto genera los archivos PHP, SCSS y JS del plugin en modo interactivo.

A continuación se muestran los detalles que utilizaremos en nuestro ejemplo. Siéntete libre de cambiar estos detalles según tus preferencias:
[aviso]

  • El slug del bloque utilizado para la identificación (también el nombre del plugin y de la carpeta de salida): author-plugin
  • El espacio de nombres interno para el nombre del bloque (algo único para tus productos): author-box
  • El título de visualización de tu bloque: Caja de autor
  • La breve descripción de tu bloque (opcional): Un bloque de ejemplo para los lectores de Kinsta
  • El dashicon para facilitar la identificación de tu bloque (opcional): empresario
  • El nombre de la categoría para ayudar a los usuarios a navegar y descubrir tu bloque: widgets
  • El nombre del autor del plugin (opcional). Se pueden enumerar varios autores utilizando comas: su nombre
  • El nombre corto de la licencia del plugin (opcional):
  • Un enlace al texto completo de la licencia (opcional):
  • El número de versión actual del plugin: 0.1.0

[/notice]
Una vez que pulses enter, descarga y configura el plugin.

Installing the block plugin.
Instalando el plugin de bloqueo.

El proceso puede tardar un par de minutos. Cuando se complete, deberías ver la siguiente pantalla:

Block bootstrapped in the plugin folder.
Bloque arrancado en la carpeta del plugin.

Verás una lista de los comandos que puedes ejecutar desde el directorio del plugin:

  • $ npm start – Inicia la construcción para el desarrollo.
  • $ npm run build – Construye el código para producción.
  • $ npm run format – Formatea los archivos.
  • $ npm run lint:css – Limita los archivos CSS.
  • $ npm run lint:js – Limitar los archivos JavaScript.
  • $ npm run packages-update – Actualiza los paquetes de WordPress a la última versión.

Bien, ahora pasa al directorio de plugins con el siguiente comando:

cd author-plugin

E inicia tu compilación de desarrollo:

npm start

A continuación, ve a la pantalla de plugins de tu panel de control de WordPress y activa el plugin Author box:

The block plugin is listed in the Plugins screen.
El plugin de caja aparece en la pantalla de plugins.

Ahora puedes comprobar si el plugin funciona correctamente. Crea un nuevo post y empieza a escribir / para lanzar el insertador rápido:

The block item in the Quick Inserter.
El elemento de bloque en el insertador rápido.

También encontrarás el bloque de la caja de autor en el Insertador de bloques, en la categoría de Widgets. Selecciona el bloque para añadirlo al lienzo del editor:

The WordPress Block Inserter.
El insertador de bloques de WordPress

Ya has terminado. Ahora guarda el post y previsualiza la página para comprobar si el bloque se muestra correctamente.

El andamiaje de bloques

Ya hemos hablado del andamiaje de bloques en nuestro post anterior. Por lo tanto, aquí sólo daremos una visión rápida de los archivos que vamos a modificar para nuestros ejemplos.

La carpeta raíz
La carpeta raíz es donde encontrarás el archivo PHP principal y varias subcarpetas.

author-plugin.php
Por defecto, el paquete @wordpress/create-block proporciona el siguiente archivo PHP:

/**
 * Plugin Name:       Author box
 * Description:       An example block for Kinsta readers
 * Requires at least: 5.8
 * Requires PHP:      7.0
 * Version:           0.1.0
 * Author:            Carlo
 * License:           GPL-2.0-or-later
 * License URI:       https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain:       author-plugin
 *
 * @package           author-box
 */

/**
 * Registers the block using the metadata loaded from the `block.json` file.
 * Behind the scenes, it registers also all assets so they can be enqueued
 * through the block editor in the corresponding context.
 *
 * @see https://developer.wordpress.org/reference/functions/register_block_type/
 */
function author_box_author_plugin_block_init() {
	register_block_type( __DIR__ . '/build' );
}
add_action( 'init', 'author_box_author_plugin_block_init' );

En el encabezamiento, verás los datos que hemos introducido en la configuración.

Con los bloques estáticos, la mayor parte del tiempo trabajarás en los archivos JavaScript situados en la carpeta src. Con los bloques dinámicos, escribirás código PHP para mostrar el contenido del bloque en el front end.

La carpeta src
La carpeta src es tu carpeta de desarrollo. Aquí encontrarás los siguientes archivos:

  • bloque.json
  • index.js
  • editar.js
  • guardar.js
  • editor.scss
  • estilo.scss

block.json
El block. json es tu archivo de metadatos. @wordpress/create-block genera el siguiente archivo block.json:

{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 2,
	"name": "author-box/author-plugin",
	"version": "0.1.0",
	"title": "Author box",
	"category": "widgets",
	"icon": "businessperson",
	"description": "An example block for Kinsta readers",
	"supports": {
		"html": false
	},
	"textdomain": "author-plugin",
	"editorScript": "file:./index.js",
	"editorStyle": "file:./index.css",
	"style": "file:./style-index.css"
}

Para ver más de cerca el archivo block. json en general, consulta nuestra anterior entrada del blog.

index.js
El archivo index . js es donde se registra el tipo de bloque en el cliente:

import { registerBlockType } from '@wordpress/blocks';

import './style.scss';

import Edit from './edit';
import save from './save';

registerBlockType('author-box/author-plugin', {
	edit: Edit,
	save,
});

edit.js
El archivo edit . js es donde construirás la interfaz del bloque que se muestra en el editor:

import { __ } from '@wordpress/i18n';

import { useBlockProps } from '@wordpress/block-editor';

import './editor.scss';

export default function Edit() {
	return (
		<p {...useBlockProps()}>
			{__('Author box – hello from the editor!', 'author-plugin')}
		</p>
	);
}

save.js
El archivo save . js contiene el script que construye el contenido del bloque que se guardará en la base de datos. No utilizaremos este archivo en este tutorial:

import { __ } from '@wordpress/i18n';

import { useBlockProps } from '@wordpress/block-editor';

export default function save() {
	return (
		<p {...useBlockProps.save()}>
			{__('Author box – hello from the saved content!', 'author-plugin')}
		</p>
	);
}

Construir el bloque para renderizarlo en el editor

Abre tu proyecto en Visual Studio Code o en cualquier editor de código que desees.

Si estás utilizando Visual Studio Code, ve a Terminal -> Nueva Terminal. Esto lanzará una ventana de terminal en la carpeta raíz de tu proyecto.

En el terminal (o en tu herramienta de línea de comandos favorita), escribe el siguiente comando:

npm start

Ahora estás ejecutando el entorno de Node en modo de desarrollo.

The block plugin project in Visual Studio Code.
El proyecto del plugin de bloques en Visual Studio Code.

A partir de aquí, seguirás dos rutas diferentes. Para renderizar el bloque en el editor, trabajarás en el archivo edit.js. Para representar el bloque en el front-end, tendrás que escribir código PHP en el archivo principal del plugin.

Ahora súbete las mangas porque empieza la codificación:

Registrar el bloque en el servidor

En primer lugar, tienes que registrar el bloque en el servidor y escribir el código PHP para recuperar los datos de la base de datos.

En el archivo author-plugin.php, tendrás que pasar un segundo argumento a la funciónregister_block_type:

function author_box_author_plugin_block_init() {
	register_block_type( __DIR__ . '/build', array(
		'render_callback' => 'author_box_author_plugin_render_author_content'
	) );
}
add_action( 'init', 'author_box_author_plugin_block_init' );

El segundo argumento es una matriz de argumentos para registrar un tipo de bloque (ver la lista completa de argumentos disponibles aquí). En el código anterior sólo hemos proporcionado render_callback, que determina la función de devolución de llamada que renderiza el bloque en la pantalla.

A continuación, declara la función:

function author_box_author_plugin_render_author_content() {
	return 'Hello World!';
}

Guarda el archivo, crea una nueva entrada o página y añade el bloque Author Box al lienzo del editor.

The WordPress Block Inserter.
El insertador de bloques de WordPress.

El editor de bloques sigue mostrando el bloque de inicio, ya que aún no hemos cambiado el archivo edit.js.

Pero si previsualizas la entrada en el front-end, verás que el contenido del bloque original ha sido sustituido por la cadena «Hola Mundo».

Ahora, como el HTML que se muestra en el front-end es generado por el archivo PHP, no será necesario que la función save devuelva nada. Así que vayamos directamente al archivo save.js y cambiemos el código como se muestra a continuación:

export default function save() {
	return null;
}

Definir los atributos del bloque

Ahora necesitas un lugar para almacenar los ajustes del usuario. Por ejemplo, el número de elementos de la entrada que se deben recuperar de la base de datos, si se debe mostrar o no un campo específico, etc. Para ello, definirás una serie de attributes en el archivo block.json.

Por ejemplo, podrías dar al usuario la posibilidad de determinar el número de publicaciones que se incluirán en el bloque, la opción de mostrar la imagen destacada, la fecha, el extracto, y/o ocultar/mostrar la foto de perfil del autor.

Aquí está la lista completa de atributos que utilizaremos para construir nuestro bloque de ejemplo:

{
	...
	"attributes": {
		"numberOfItems": {
			"type": "number",
			"default": 3
		},
		"columns": {
			"type": "number",
			"default": 1
		},
		"displayDate": {
			"type": "boolean",
			"default": true
		},
		"displayExcerpt": {
			"type": "boolean",
			"default": true
		},
		"displayThumbnail": {
			"type": "boolean",
			"default": true
		},
		"displayAuthorInfo": {
			"type": "boolean",
			"default": true
		},
		"showAvatar": {
			"type": "boolean",
			"default": true
		}, 
		"avatarSize": {
			"type": "number",
			"default": 48
		},
		"showBio": {
			"type": "boolean",
			"default": true
		}
	}
}

Construye el bloque que se mostrará en el editor

El selector getEntityRecords está incluido en el paquete @wordpress/data. Para utilizarlo, tendrás que importar el gancho useSelect de ese paquete en tu archivo edit.js:

import { useSelect } from '@wordpress/data';

A continuación, añade el siguiente código a la función Edit():

const posts = useSelect( ( select ) => {
	return select( 'core' ).getEntityRecords( 'postType', 'post', {
		'per_page': 3
	});
});

En el código anterior, hemos codificado el número de publicaciones. Pero es posible que quieras dar a los usuarios la posibilidad de establecer un número diferente de publicaciones. Puedes utilizar un atributo para ello.

En tu block.json deberías haber definido un atributo numberOfItems. Puedes utilizarlo en tu función Edit como se muestra a continuación:

export default function Edit( { attributes } ) {

	const { numberOfItems } = attributes;

	const posts = useSelect( ( select ) => {
		return select( 'core' ).getEntityRecords( 'postType', 'post', {
			'per_page': numberOfItems
		});
	});

	console.log( posts );

	return (
		...
	);
}

Todavía no verás los mensajes en la pantalla, pero ejecuta un console.log y observa lo que ocurre en la consola del inspector de tu navegador:

The result in the browser's console.
El resultado en la consola del navegador.

useSelect puede tomar dos argumentos: una llamada de retorno en línea y una matriz de dependencias. Ambos devuelven una versión memoizada de la llamada de retorno que sólo cambia cuando cambia una de las dependencias.

Así que, para volver a obtener las entradas en cada cambio de atributo de numberOfItems, tienes que cambiar la función Edit como se muestra a continuación:

export default function Edit( { attributes } ) {

	const { numberOfItems } = attributes;

	const posts = useSelect(
		( select ) => {
			return select( 'core' ).getEntityRecords( 'postType', 'post', {
				'per_page': numberOfItems
			});
		}, 
		[ numberOfItems ]
	);

	console.log(posts);

	return (
		...
	);
}

A continuación, tienes que renderizar tu lista de entradas. Para ello puedes utilizar el método incorporado de JavaScript map:

export default function Edit( { attributes } ) {

	const { numberOfItems } = attributes;

	const posts = useSelect(
		( select ) => {
			return select( 'core' ).getEntityRecords( 'postType', 'post', {
				'per_page': numberOfItems
			});
		},
		[ numberOfItems ]
	);

	console.log(posts);
	
	return (
		<div { ...useBlockProps() }>
			<ul>
				{ posts && posts.map( ( post ) => {
					return (
						<li key={ post.id }>
							<h5>
								<a href={ post.link }>
									{ 
										post.title.rendered ? 
										post.title.rendered :
										__( 'Default title', 'author-plugin' )
									}
								</a>
							</h5>
						</li>
					)
				})}
			</ul>
		</div>
	);
}

En primer lugar, comprueba si tienes al menos una entrada en el array, y luego ejecuta el bucle.

Ten en cuenta que, como estamos utilizando el método map con un componente React, también estamos utilizando un atributo key para asignar el ID de la entrada al elemento actual de la lista.

post.link y post.title.rendered muestran la URL y el título de la entrada, respectivamente.

La imagen siguiente muestra la lista completa de las propiedades del objeto post.

The Post object.
El objeto Post.

El código anterior es sólo un ejemplo básico del uso de getEntityRecords. Ahora es el momento de poner en práctica nuestros conocimientos.

Supongamos que quieres evitar que tu bloque muestre las etiquetas HTML que el usuario pueda haber añadido al título de la entrada. WordPress proporciona un componenteRawHTML para ello.

Primero, importarás el componente del paquete @wordpress/elemento:

import { RawHTML } from '@wordpress/element';

A continuación, envolverás el título de la entrada dentro de un elemento RawHTML:

<div { ...useBlockProps() }>
	<ul>
		{ posts && posts.map((post) => {
			return (
				<li key={ post.id }>
					<h5>
						<a href={ post.link }>
							{ post.title.rendered ? (
								<RawHTML>
									{ post.title.rendered }
								</RawHTML>
							) : (
								__( 'Default title', 'author-plugin' )
							)}
						</a>
					</h5>
				</li>
			)
		})}
	</ul>
</div>

Y eso es todo. Ahora añade una etiqueta HTML al título de tu entrada y guarda la entrada. A continuación, prueba tu código con y sin RawHTML y observa cómo cambia el contenido de tu bloque en la pantalla.

Añade la fecha

WordPress proporciona una serie de funciones de JavaScript para gestionar y dar formato a las fechas. Para utilizar esas funciones, primero tendrás que importarlas del paquete@wordpress/date en tu archivo edit.js:

import { dateI18n, format, __experimentalGetSettings } from '@wordpress/date';
  • dateI18n: Formatea una fecha, traduciéndola a la configuración regional del sitio.
  • format: Formatear una fecha.
  • __experimentalGetSettings: Mostrar la fecha en el formato establecido en los ajustes generales de WordPress.

Estas funciones no están documentadas, pero encontrarás ejemplos útiles en el código fuente de varios bloques. Consulta, por ejemplo, los archivos latest-posts y post-date edit.js.

Ahora añade el atributo displayDate:

const { numberOfItems, displayDate } = attributes;

A continuación, añade el siguiente código dentro del elemento <li>:

{ 
	displayDate && (
		<time
			className='wp-block-author-box-author-plugin__post-date'
			dateTime={ format( 'c', post.date_gmt ) }
		>
			{ dateI18n(
				__experimentalGetSettings().formats.date, 
				post.date_gmt
			)}
		</time>
	) 
}

¿Qué ocurre aquí?

Añadir el extracto

Ahora debería ser fácil añadir el extracto del post. Primero, echa un vistazo a la propiedad excerpt en el inspector del navegador. Verás que el contenido real se almacena en excerpt.rendered.

Inspecting the post excerpt in Chrome DevTools.
Inspeccionando el extracto del post en Chrome DevTools.

A continuación, añade el atributo displayExcerpt al objeto attributes:

const { numberOfItems, displayDate, displayExcerpt } = attributes;

A continuación, añade el siguiente código antes de la etiqueta de cierre </li> en la función Edit:

{
	displayExcerpt &&
	post.excerpt.rendered && (
		<p>
			<RawHTML>
				{ post.excerpt.rendered }
			</RawHTML>
		</p>
	)
}

Si no estás familiarizado con JavaScript, aquí y arriba utilizamos la evaluación de circuito corto, por la que, si todas las condiciones son verdaderas, se devuelve el valor del último operando (lee más en Inline If con el operador lógico && y el AND lógico (&&)).

Por último, puedes volver a probar tu código. Cambia el valor del atributo en el archivo block.json y observa lo que ocurre en el editor.

Añade la imagen destacada

Ahora tienes que añadir el código que muestra las imágenes destacadas. Comienza añadiendo el atributo displayThumbnail a attributes:

const { 
	numberOfItems, 
	displayDate, 
	displayExcerpt, 
	displayThumbnail 
} = attributes;

Ahora tienes que averiguar dónde se almacena la imagen destacada. Como hemos mencionado anteriormente, para obtener la imagen destacada necesitas añadir un nuevo argumento _embed a tu consulta. De vuelta a tu código, cambia los argumentos de la consulta de la siguiente manera

const posts = useSelect(
	( select ) => {
		return select( 'core' ).getEntityRecords( 'postType', 'post', {
			'per_page': numberOfItems,
			'_embed': true
		});
	},
	[ numberOfItems ]
);

Aquí simplemente añadimos '_embed': true a la matriz de argumentos. Esto proporciona un objeto post que contiene la propiedad _embedded, la cual proporciona los detalles de la imagen que necesitas para disponer de las imágenes destacadas.

Ahora deberías saber dónde encontrar los detalles de la imagen.

Featured image details in getEntityRecords response.
Detalles de las imágenes destacadas en la respuesta getEntityRecords.

Sólo tienes que añadir el código que muestra la imagen en la pantalla:

{
	displayThumbnail && 
	post._embedded && 
	post._embedded['wp:featuredmedia'] &&
	post._embedded['wp:featuredmedia'][0] &&
	<img 
	className='wp-block-author-box-author-plugin__post-thumbnail'
		src={ post._embedded['wp:featuredmedia'][0].media_details.sizes.medium.source_url }
		alt={ post._embedded['wp:featuredmedia'][0].alt_text }
	/>
}

Guarda el archivo, pasa al editor de bloques y comprueba si la imagen se muestra correctamente cuando el atributo displayThumbnail se establece en true.

A list of posts with featured image, date and excerpt.
Una lista de publicaciones con imagen destacada, fecha y extracto.

Añadir controles a la barra lateral

Hasta ahora hemos estado utilizando los valores por defecto de los atributos establecidos en el block.json. Pero por nuestro artículo anterior sabemos que podemos definir manejadores de eventos para dar a los usuarios la posibilidad de asignar valores personalizados a cada atributo.

Para ello, añadirás un conjunto de controles a la barra lateral de configuración del bloque. En edit.js, importa los siguientes componentes de los paquetes correspondientes:

import { 
	useBlockProps,
	InspectorControls
} from '@wordpress/block-editor';

import {
	PanelBody,
	PanelRow,
	QueryControls,
	ToggleControl,
	RangeControl
} from '@wordpress/components';
  • InspectorControls: Contiene ajustes de la barra lateral que afectan a todo el bloque (ver en GitHub)
  • PanelBody: Añade un contenedor plegable a la barra lateral de ajustes (ver en GitHub)
  • PanelRow: Produce un contenedor genérico para los controles de la barra lateral (ver en GitHub)
  • QueryControls: Proporciona controles de configuración para construir una consulta (ver en GitHub)
  • ToggleControl: Proporciona un botón de alternancia para que los usuarios activen/desactiven una opción específica (ver en GitHub)
  • RangeControl: Se utiliza para hacer selecciones de un rango de valores incrementales (ver en GitHub)

A continuación, tienes que actualizar la función Edit para utilizar los controles ahora disponibles. En primer lugar, modifica la función Edit como sigue:

export default function Edit( { attributes, setAttributes } ) {

	const { 
		numberOfItems, 
		columns, 
		displayExcerpt, 
		displayDate, 
		displayThumbnail
	} = attributes;

	const posts = useSelect(
		( select ) => {
			return select( 'core' ).getEntityRecords( 'postType', 'post', {
				'per_page': numberOfItems,
				'_embed': true
			});
		},
		[ numberOfItems ]
	);
	...
}

Observa la propiedad setAttributes que se pasa a la función Edit.

Ahora puedes añadir los elementos correspondientes a tu código JSX:

return (
	<>
		<InspectorControls>
			<PanelBody title={ __( 'Content Settings', 'author-plugin' ) }>
				<PanelRow>
					<QueryControls 
						numberOfItems={ numberOfItems }
						onNumberOfItemsChange={ ( value ) =>
							setAttributes( { numberOfItems: value } )
						}
						minItems={ 1 }
						maxItems={ 10 }
					/>
				</PanelRow>
				<PanelRow>
					<RangeControl
						label={ __( 'Number of Columns', 'author-plugin' ) }
						value={ columns }
						onChange={ ( value ) =>
							setAttributes( { columns: value } )
						}
						min={ 1 }
						max={ 4 }
						required
					/>
				</PanelRow>
				<PanelRow>
					<ToggleControl
						label={ __( 'Show Featured Image', 'author-plugin' ) }
						checked={ displayThumbnail }
						onChange={ () =>
							setAttributes( { displayThumbnail: ! displayThumbnail } )
						}
					/>
				</PanelRow>
				<PanelRow>
					<ToggleControl
						label={ __( 'Show Date', 'author-plugin' ) }
						checked={ displayDate }
						onChange={ () =>
							setAttributes( { displayDate: ! displayDate } )
						}
					/>
				</PanelRow>
				<PanelRow>
					<ToggleControl
						label={ __( 'Display Excerpt', 'author-plugin' ) }
						checked={ displayExcerpt }
						onChange={ () =>
							setAttributes( { displayExcerpt: ! displayExcerpt } )
						}
					/>
				</PanelRow>
			</PanelBody>
		</InspectorControls>
		<div { ...useBlockProps() }>
			...
		</div>
	</>
);

Vaya, es mucho código, ¿verdad? Pero es bastante fácil de entender.

Los atributos del elemento que más merecen tu atención aquí son onNumberOfItemsChange en QueryControls y onChange en RangeControl y ToggleControl. Esos atributos establecen los manejadores de eventos necesarios para que el usuario pueda personalizar la apariencia y/o el comportamiento de un bloque.

También te darás cuenta de que hemos utilizado las etiquetas <> y </>, que son la sintaxis corta para declarar fragmentos de React.

Ahora, guarda tu archivo, entra en el editor y actualiza la página:

Block settings.
Configuración del bloque.

¿Está todo ahí? Entonces sigamos adelante y añadamos los datos del autor del post.

Encuentra el autor del post

Como hemos mencionado anteriormente, nuestro bloque mostrará una lista de artículos escritos por el mismo autor que el post actual.

Para obtener el ID del autor del post, importarás el selectorgetCurrentPostAttribute del almacén de datos core/editor:

wp.data.select( 'core/editor' ).getCurrentPostAttribute( 'author' )

getCurrentPostAttribute devuelve un valor de atributo para el post guardado.

Una vez que obtengas el ID del autor, puedes cambiar la consulta como se muestra a continuación:

const posts = useSelect(
	( select ) => {

		const _authorId = select( 'core/editor' ).getCurrentPostAttribute( 'author' );
	
		return select( 'core' ).getEntityRecords( 'postType', 'post', {
			'author': _authorId,
			'per_page': numberOfItems,
			'_embed': true
		});
	},
	[ numberOfItems ]
);

Con este código, obtendrás una lista de artículos de n del mismo autor que el post actual.

Ahora que tienes el ID de autor, también puedes utilizarlo para obtener datos adicionales de la base de datos.

Mostrar los detalles del autor

Como no tenemos ninguna documentación disponible, utilizamos el código del bloque central Post Author como referencia.

Para mostrar los detalles del autor, primero tienes que importar una nueva dependencia:

import { forEach } from 'lodash';

A continuación, en la función Edit, actualiza el objeto attributes como sigue:

const { 
	numberOfItems, 
	columns, 
	displayExcerpt, 
	displayDate, 
	displayThumbnail, 
	displayAuthorInfo, 
	showAvatar, 
	avatarSize, 
	showBio 
} = attributes;

Una vez hecho esto, editarás el código visto en el apartado anterior para recuperar los datos del autor:

const { authorDetails, posts } = useSelect(
	( select ) => {

		const _authorId = select( 'core/editor' ).getCurrentPostAttribute( 'author' );

		const authorDetails = _authorId ? select( 'core' ).getUser( _authorId ) : null;
	
		const posts = select( 'core' ).getEntityRecords( 'postType', 'post', {
			'author': _authorId,
			'per_page': numberOfItems,
			'_embed': true
		});

		return { 
			authorDetails: authorDetails,
			posts: posts
		};
	},
	[ numberOfItems ]
);

Ten en cuenta que hemos utilizado el selectorgetUser para obtener los detalles del autor.

A continuación, es posible que quieras obtener el avatar del autor. El código siguiente construye una matriz de elementos que almacenan las URLs y los tamaños de los avatares:

const avatarSizes = [];
if ( authorDetails ) {
	forEach( authorDetails.avatar_urls, ( url, size ) => {
		avatarSizes.push( {
			value: size,
			label: `${ size } x ${ size }`,
		} );
	} );
}

A continuación, añadirás los paneles y controles de la barra lateral para que los usuarios puedan personalizar el área del autor en el bloque:

return (
	<>
		<InspectorControls>
			<PanelBody title={ __( 'Author Info', 'author-plugin' ) }>
				<PanelRow>
					<ToggleControl
						label={ __( 'Display Author Info', 'author-plugin' ) }
						checked={ displayAuthorInfo }
						onChange={ () =>
							setAttributes( { displayAuthorInfo: ! displayAuthorInfo } )
						}
					/>
				</PanelRow>
				{ displayAuthorInfo && (
					<>
						<PanelRow>
							<ToggleControl
								label={ __( 'Show avatar' ) }
								checked={ showAvatar }
								onChange={ () =>
									setAttributes( { showAvatar: ! showAvatar } )
								}
							/>
							{ showAvatar && (
								<SelectControl
									label={ __( 'Avatar size' ) }
									value={ avatarSize }
									options={ avatarSizes }
									onChange={ ( size ) => {
										setAttributes( {
											avatarSize: Number( size ),
										} );
									} }
								/>
							) }
						</PanelRow>
						<PanelRow>
							<ToggleControl
								label={ __( 'Show Bio', 'author-plugin' ) }
								checked={ showBio }
								onChange={ () =>
									setAttributes( { showBio: ! showBio } )
								}
							/>
						</PanelRow>
					</>
				) }
			</PanelBody>
			...
		</InspectorControls>
		...
	</>
);

La imagen siguiente muestra la barra lateral de configuración actualizada:

The Author Info settings panel.
El panel de configuración de la información del autor.

Por último, puedes añadir la sección del autor a tu bloque:

return (
	<>
		<InspectorControls>
		...
		</InspectorControls>

		<div { ...useBlockProps() }>
			{ displayAuthorInfo  && authorDetails && (
				<div className="wp-block-author-box-author-plugin__author">
					{ showAvatar && (
						<div className="wp-block-author-box-author-plugin__avatar">
							<img
								width={ avatarSize }
								src={
									authorDetails.avatar_urls[
										avatarSize
									]
								}
								alt={ authorDetails.name }
							/>
						</div>
					) }
					<div className='wp-block-author-box-author-plugin__author-content'>
						<p className='wp-block-author-box-author-plugin__name'>
							{ authorDetails.name }
						</p>
						{ showBio &&
							// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining
							authorDetails?.description &&
							authorDetails.description.length > 0 && (
							<p className='wp-block-author-box-author-plugin__description'>{ authorDetails.description }</p>
						) }
					</div>
				</div>
			)}
			<ul>
			...
			</ul>
		</div>
	</>
);

La siguiente imagen muestra cómo se visualiza en la pantalla.

Author details section and Info settings.
Sección de detalles del autor y configuración de la información.

Ahora guarda tu archivo edit.js y ejecuta tus pruebas. Tu bloque debería incluir diferentes elementos en función de la configuración del bloque.

Author details not showing author's bio.
Los detalles del autor no muestran la biografía del autor.

Falta una última cosa: el número de columnas para mostrar los artículos.

Cambiar el número de columnas

Para dar al usuario la posibilidad de mostrar las vistas previas de los artículos en columnas, definimos el atributo columns en el archivo block.json. También incluimos un atributo columns en el script y creamos un control de configuración para permitir a los usuarios cambiar el número de columnas, aunque este cambio no tiene efecto por el momento.

En el código JSX anterior habrás observado que hemos añadido clases CSS a varios elementos:

Clases asignadas a los elementos de la sección Autor:

  • wp-block-author-box-author-plugin__author
  • wp-block-author-box-author-plugin__avatar
  • wp-block-author-box-author-plugin__author-content
  • wp-block-author-box-author-plugin__name
  • wp-block-author-box-author-plugin__description

Clases asignadas a elementos de la sección de contenido:

  • wp-block-author-box-author-plugin__post-items
  • wp-block-author-box-author-plugin__post-thumbnail
  • wp-block-author-box-author-plugin__post-title
  • wp-block-author-box-author-plugin__post-date
  • wp-block-author-box-author-plugin__post-excerpt

Todavía falta una clase. El nombre de esta clase se generará dinámicamente para reflejar el número de columnas establecido por el usuario.

Vuelve al archivo Edit.js y modifica el elemento ul como sigue:

<ul className={ `wp-block-author-box-author-plugin__post-items columns-${ columns }` }>
	...
</ul>

Añadimos una nueva clase columns-${ columns } de acuerdo con la sintaxis de los literales de la plantilla para insertar una expresión dentro de una cadena. De este modo, el atributo que se adjunte al elemento ul dependerá de la configuración del usuario (por ejemplo, columns-1, columns-2, etc.).

Ahora abre el archivo style.scss y sustituye el código existente por el siguiente:

.wp-block-author-box-author-plugin {
	background-color: #21759b;
	color: #fff;
	padding: .6em;
	ul.wp-block-author-box-author-plugin__post-items {
		padding: 0;
		list-style-type: none;
		display: grid;
		gap: .5em;
		@for $i from 2 through 4 {
			&.columns-#{ $i } {
				grid-template-columns: repeat(#{ $i }, 1fr);
			}
		}
		li {
			list-style: none;
			img.wp-block-author-box-author-plugin__post-thumbnail {
				height: auto;
				max-width: 100%;
			}
		}
		
	}
}
.wp-block-author-box-author-plugin__author {
	display: flex;
    flex-wrap: wrap;
}

.wp-block-author-box-author-plugin__avatar {
	margin-right: 1em;
}

.wp-block-author-box-author-plugin__author-content {
	flex-basis: 0;
    flex-grow: 1;
}

No profundizaremos en ese código, ya que está fuera del alcance de este artículo. Pero si quieres profundizar, puedes consultar los siguientes recursos:

The Author block in the editor.
El bloque Autor en el editor.

Y eso es todo para la renderización del bloque en el editor.

Construyendo el bloque para renderizarlo en la página

Ahora que el código que renderiza el bloque en el editor está completo, podemos pasar a construir el bloque para renderizarlo en el front end.

Como hemos mencionado antes, cuando se trata de bloques dinámicos, el archivo del plugin es el responsable de generar el HTML que se renderizará en el front-end.

Así que abre el archivo principal de tu plugin(author-plugin.php en nuestro ejemplo).

Lo primero que hay que hacer es poner los atributos del bloque a disposición de la función PHP de WordPress. En tu archivo PHP, cambia la definición de la función como sigue

function author_box_author_plugin_render_author_content( $attr ) {
	...
}

Ahora puedes utilizar las funciones de WordPress para recuperar y manipular datos. Por ejemplo, puedes utilizar get_posts para recuperar las últimas entradas del blog (lee más en nuestro artículo en profundidad sobre la funciónget_posts ):

function author_box_author_plugin_render_author_content( $attr ) {
	$args = array(
		'numberposts'	=> $attr['numberOfItems'],
	);
	$my_posts = get_posts( $args );
	
	if( ! empty( $my_posts ) ){
		$output = '<ul>';
		foreach ( $my_posts as $p ){
			$output .= '<li><a href="' . esc_url( get_permalink( $p->ID ) ) . '">' 
			. $p->post_title . '</a></li>';
		}
		$output .= '</ul>';
	}
	return $output ?? '<strong>Sorry. No posts matching your criteria!</strong>';
}

La función anterior recupera las últimas entradas del blog numberOfItems de tu base de datos de WordPress (por defecto post_type está configurado como post) y devuelve una matriz de objetos $post. Luego itera sobre la matriz para construir los elementos de la lista.

Si inspeccionas la salida HTML, verás que es una simple lista de entradas, como la que se muestra en la siguiente imagen:

A simple list of posts.
Una simple lista de entradas.

En nuestro artículo anterior mencionamos que utilizarías el gancho React useBlockProps para marcar el elemento envolvente del bloque en tu código JSX. Tendrás que hacer lo mismo en tu función PHP.

WordPress proporciona la funciónget_block_wrapper_attributes para ello.

Por tanto, cambia tu código PHP de la siguiente manera:

function author_box_author_plugin_render_author_content( $attr ) {
	$args = array(
		'numberposts'	=> $attr['numberOfItems']
	);
	$my_posts = get_posts( $args );
	
	if( ! empty( $my_posts ) ){
		$output = '<div ' . get_block_wrapper_attributes() . '>';
		$output .= '<ul>';
		foreach ( $my_posts as $p ){
			
			$title = $p->post_title ? $p->post_title : 'Default title';
			$url = esc_url( get_permalink( $p->ID ) );

			$output .= '<li>';
			$output .= '<a href="' . $url . '">' . $title . '</a>';
			$output .= '</li>';
		}
		$output .= '</ul>';
		$output .= '</div>';
	}
	return $output ?? '<strong>Sorry. No posts matching your criteria!</strong>';
}

Ahora se ha asignado una clasewp-block-author-box-author-plugin al elemento contenedor y el bloque tiene un color de fondo diferente.

Entonces la función get_posts obtiene los datos de WP_Posts y el ciclo foreach construye los elementos de la lista (ver también Cómo mostrar los datos devueltos por get_posts).

A list of posts with a CSS class assigned.
Una lista de posts con una clase CSS asignada.

Añade la imagen destacada, la fecha y el extracto

A continuación, tendrás que añadir las miniaturas de las entradas, las fechas y los extractos. En el mismo archivo, cambia tu código PHP como sigue:

function author_box_author_plugin_render_author_content( $attr ) {
	$args = array(
		'numberposts'	=> $attr['numberOfItems']
	);
	$my_posts = get_posts( $args );
	
	if( ! empty( $my_posts ) ){
		$output = '<div ' . get_block_wrapper_attributes() . '>';
		$output .= '<ul class="wp-block-author-box-author-plugin__post-items columns-">';

		foreach ( $my_posts as $p ){
			
			$title = $p->post_title ? $p->post_title : 'Default title';
			$url = esc_url( get_permalink( $p->ID ) );
			$thumbnail = has_post_thumbnail( $p->ID ) ? get_the_post_thumbnail( $p->ID, 'medium' ) : '';

			$output .= '<li>';
			if( ! empty( $thumbnail ) && $attr['displayThumbnail'] ){
				$output .= $thumbnail;
			}
			$output .= '<h5><a href="' . $url . '">' . $title . '</a></h5>';
			if( $attr['displayDate'] ){
				$output .= '<time datetime="' . esc_attr( get_the_date( 'c', $p ) ) . '">' . esc_html( get_the_date( '', $p ) ) . '</time>';
			}
			if( get_the_excerpt( $p ) && $attr['displayExcerpt'] ){
				$output .= '<p>' . get_the_excerpt( $p ) . '</p>';
			}
			$output .= '</li>';
		}
		$output .= '</ul>';
		$output .= '</div>';
	}
	return $output ?? '<strong>Sorry. No posts matching your criteria!</strong>';
}

El bucle foreach itera sobre la matriz $my_posts. En cada iteración, varias condiciones comprueban los valores de los atributos y construyen la salida en consecuencia.

Ahora echa un vistazo a la salida en la pantalla:

A list of posts with featured images, dates, and excerpts.
Una lista de publicaciones con imágenes destacadas, fechas y extractos.

Ahora puedes hacer tus pruebas. Cambia la configuración de la fecha, el extracto y la miniatura y comprueba cómo cambia el contenido del bloque en el front-end.

Mostrar publicaciones en columnas

En nuestro código JavaScript, hemos utilizado una clase columns-${ columns } para mostrar las vistas previas de las entradas en columnas. Ahora tenemos que hacer lo mismo en PHP.

Para ello, sólo tienes que añadir estas dos líneas de código:

$num_cols = $attr['columns'] > 1 ? strval( $attr['columns'] ) : '1';

$output .= '<ul class="wp-block-author-box-author-plugin__post-items columns-' . $num_cols . '">';

Esto añadirá una clase columns-n al elemento ul que contiene las vistas previas de las entradas. Ahora el número de columnas mostradas en la página debería coincidir con el número de columnas establecido en la configuración del bloque.

Construir la caja de autor

Por último, tienes que construir la caja que contiene los detalles del autor, incluyendo el avatar, el nombre y la descripción.

Dentro de la función de devolución de llamada, tendrás que añadir un conjunto de condiciones para comprobar el valor actual de cada atributo:

if( $attr['displayAuthorInfo'] ){
	$output .= '<div class="wp-block-author-box-author-plugin__author">';
	
	if( $attr['showAvatar'] ){
		$output .= '<div class="wp-block-author-box-author-plugin__avatar">' 
			. get_avatar( get_the_author_meta( 'ID' ), $attr['avatarSize'] ) 
			. '</div>';
	}

	$output .= '<div class="wp-block-author-box-author-plugin__author-content">';
	
	$output .= '<div class="wp-block-author-box-author-plugin__name">' 
		. get_the_author_meta( 'display_name' ) 
		. '</div>';

	if( $attr['showBio'] ){
		$output .= '<div class="wp-block-author-box-author-plugin__description">' 
			. get_the_author_meta( 'description' ) 
			. '</div>';
	}

	$output .= '</div>';
	$output .= '</div>';
}

El código es bastante sencillo. Comprueba el valor actual de cada atributo, y si es true, entonces genera el HTML necesario.

Ahora guarda tu archivo PHP y compara el bloque en el editor con el mismo bloque en el front end.

Our custom block in the block editor.
Nuestro bloque personalizado en el editor de bloques.

Encontrarás el código completo del bloque de ejemplo en este Gist público.

Recursos recomendados para el desarrollo de bloques dinámicos

Si has agudizado el oído al leer este artículo y has empezado a reconocer las oportunidades de desarrollo profesional que conlleva aprender a crear bloques Gutenberg, nuestro consejo es que sigas explorando y adquiriendo nuevas habilidades en las tecnologías que hay detrás del desarrollo de bloques.

Aunque todavía falta documentación oficial fiable, sin embargo hay excelentes recursos por ahí, tanto gratuitos como de pago, que hemos consultado mientras escribíamos este artículo. Entre los muchos recursos disponibles, recomendamos los siguientes:

Recursos oficiales

Tutoriales recomendados de los colaboradores del núcleo de WordPress

Recursos de JavaScript, React y Redux

Recursos relacionados de Kinsta

Resumen

Hemos llegado al final de este (segundo) largo viaje por el desarrollo del bloque Gutenberg.

En este artículo, hemos cubierto algunos temas avanzados, como el estado de la aplicación y los almacenes Redux. Pero esperamos que ahora tengas una mejor comprensión del desarrollo de bloques en general.

Sí, los conocimientos de Node.js, Webpack, Babel, React y Redux son esenciales cuando se trata de construir bloques avanzados de Gutenberg, pero no necesitas ser un ninja de React para empezar. Aprender a desarrollar bloques Gutenberg no tiene que ser necesariamente complicado. Sólo tienes que hacerlo con la motivación adecuada y siguiendo el camino de aprendizaje apropiado.

Y esperamos que este artículo -y el anterior– te proporcionen el mapa adecuado para encontrar tu camino y empezar a desarrollar Gutenberg de inmediato.

¡Ahora depende de ti! ¿Has creado ya bloques dinámicos? ¿Tienes algún ejemplo que compartir con nosotros? ¿Y cuáles fueron los mayores obstáculos en tu experiencia? No dudes en dejar un comentario a continuación.

Carlo Daniele Kinsta

Carlo es un diseñador y desarrollador de front-end freelance. Cuando escribe artículos y tutoriales, Carlo se ocupa principalmente de los estándares web, pero cuando juega con sitios web, su mejor compañero de trabajo es WordPress.