logo

Cómo parsear contenido de WordPress en un entorno headless y reemplazar los bloques Gutenberg con componentes React

09 julio 2023

Índice de contenidos

Introducción

Esta es la última parte de una serie de entradas donde he utilizado el bloque de Código de WordPress como ejemplo donde hemos visto como añadir nuevos ajustes a bloques existentes en WordPress core y cómo preparar los mismos para poder ser utilizados en un entorno headless en React.

Aquí dejo los enlaces a los anteriores artículos:

Cómo personalizar los bloques existentes de Gutenberg con campos adicionales
Cómo preparar bloques Gutenberg para utilizarlos en un entorno Headless con React

Instalar dependencias

Necesitamos instalar las dependencias necesarias en nuestra aplicación en React.

La principal para abordar el objetivo de este post será html-react-parser
Nos ayudará a parsear el contenido proveniente de WordPress y reemplazar elementos por componentes en React.

Y para este ejemplo en concreto con el bloque de código necesitaremos instalar react-syntax-highlighter, que como bien indica su nombre, será el componente React que usaremos para el resaltado de código en el Front End.
Ejecuta en el terminal:

npm install html-react-parser react-syntax-highlighter

Si usas TypeScript necesitarás instalar también en los dev-dependencies @types/react-syntax-highlighter

npm install --save-dev @types/react-syntax-highlighter

Crear nuestro componente React

Crearemos nuestro propio componente CodeInput, que será un contenedor para el componente SyntaxHighlighter, para poder aplicar nuestros propios estilos, validar props y agregar cualquier otra lógica que necesitemos.

react-syntax-highlighter puede ser bastante pesado ya que añade soporte para un gran número de lenguajes de programación. Si tenemos claro los lenguajes que necesitamos, podemos importar una versión más ligera del paquete y registrar únicamente los lenguajes que queremos.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
'use client'

import { Suspense } from 'react';
import { LightAsync as SyntaxHighlighter } from 'react-syntax-highlighter';
import php from 'react-syntax-highlighter/dist/esm/languages/hljs/php';
import js from 'react-syntax-highlighter/dist/esm/languages/hljs/javascript';
import json from 'react-syntax-highlighter/dist/esm/languages/hljs/json';
import { atomOneDark } from 'react-syntax-highlighter/dist/esm/styles/hljs';
import { CodeInputProps } from './types';
import Loading from '../Loading';

import styles from './style.module.scss';

SyntaxHighlighter.registerLanguage('javascript', js);
SyntaxHighlighter.registerLanguage('php', php);
SyntaxHighlighter.registerLanguage('json', json);

const CodeInput: React.FC<CodeInputProps> = (props) => {
	const { code, language, startLine = 1 } = props;
	return (
		<div className={styles.wrapper}>
                    <Suspense fallback={<Loading />}>
			<SyntaxHighlighter
				language={language}
				style={atomOneDark}
				startingLineNumber={startLine}
				showLineNumbers
				showInlineLineNumbers
			>
				{code}
			</SyntaxHighlighter>
                    </Suspense>
		</div>
	);
};

export default CodeInput;

Notas:

Fíjate en el uso de Suspense, te permite renderizar un Loading hasta que el componente este listo.

atomOneDark es el tema que he elegido para el resaltado de código, puedes encontrar y ver todos los estilos disponibles en la página de demostración del paquete npm.

Importamos la versión async light para optimizar el tamaño final de nuestro «bundle». Para saber más puedes visitar la documentación.

use client‘ es especifico a React 18 que hace una diferencia entre componentes del lado servidor y del lado cliente.

Usando TypeScript declaramos CodeInputProps en types.ts

1
2
3
4
5
export interface CodeInputProps {
    code: string
    language: string
    startLine?: number
}

Parsear el contenido de WordPress y reemplazar el bloque de código con el componente CodeInput

Finalmente, crearemos una función que nos facilitará el reemplazo del bloque Gutenberg con el componente CodeInput.
Puedes crear por ejemplo un archivo util/parseHtml.js con el siguiente contenido:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import parse from "html-react-parser";
import CodeInput from '@/components/CodeInput';

export default function parseHtml(html) {
	const options = {
	  replace: ({ attribs, children }) => {
                // Aplica el reemplazo solo para el bloque core/code y si el bloque contiene el atributo data-wp-block.
              const isCodeBlock = attribs?.['data-wp-block-name'] === 'core/code';
              if (isCodeBlock && attribs?.['data-wp-block']) {
                 const { 
                    language,
                    showLineNumbers,
                    startingLineNumber
                 } = JSON.parse(attribs?.['data-wp-block']);
			return (
				<CodeInput
					code={children[0].children[0].data}
					showLineNumbers={showLineNumbers}
					startingLineNumber={startingLineNumber}
					language={language}
				/>
			);
		}

	  },
	};

	return parse(html, options);
}

Y en nuestro archivo donde renderizamos en contenido, en el caso de este blog en NextJS src/app/articulo/[slug]/page,tsx

import parseHtml from '@/util/parseHtml';

// resto de código, saltamos directo al renderizado del post.content

<div>{parseHtml(post.content)}</div>

¡Y eso es todo!

Este ejemplo esta enfocado únicamente al reemplazo del bloque Gutenberg core/code pero si quieres aplicar este método de una manera más genérica te recomiendo que explores el código en headstartwp, concretamente el componente BlocksRenderer