Skip to main content

Crear una página de opciones en WordPress con React – Parte 2

Publicado hace
Actualizado hace
15 minutos de lectura

En la primera parte de este tutorial, mostré los principios básicos para crear una página de opciones en WordPress, en esta segunda parte, mostraré como utilizar los componentes incluidos en WordPress para agregar campos de texto, y guardar las opciones.

Tabla de Contenido

Advertencia

Es posible que necesites instalar algunos paquetes para este tutorial. Aunque gracias a nuestro compilador en @wordpress/scripts que automáticamente los agrega a las dependencias del script podría no ser necesario, yo prefiero instalarlos simplemente para tener un registro de ellos.

Si llegas a tener algún error simplemente ejecuta npm install --save-dev {paquete} con los siguientes paquetes:

@wordpress/components@wordpress/element@wordpress/i18n

Paso 1: Creando nuestra aplicación

Para crear una página de opciones, necesitamos agregar algunos campos. Para comenzar, debemos abrir el archivo settings.js que es donde iniciaremos nuestra aplicación, y creamos una sencilla:

settings.js

1/**
2 * WordPress dependencies
3 */
4import { createRoot } from '@wordpress/element';
5/**
6 * Internal dependencies
7 */
8import Settings from './components/settings';
9const rootElement = document.querySelector('#mah-settings');
10if (rootElement) {
11 createRoot(rootElement).render(<Settings />);
12}
13

components/settings.js

1/**
2 * WordPress dependencies
3 */
4import { __ } from '@wordpress/i18n';
5const Settings = () => {
6 return <h1>{__('Selecciona las opciones deseadas', 'mah-settings')}</h1>;
7};
8export default Settings;
9

Entre las cosas que ponemos observar en este pedazo de código están:

  1. El uso de createRoot con el que iniciamos nuestras aplicaciones en React, pero a diferencia de como normalmente se usa, ésta vez lo tomamos de @wordpress/element. Esto es porque WordPress ya viene con su propia copia de React que nos asegura que sus componentes funcionarán.
  2. Así mismo, viene con una versión en javascript de la función __ para traducciones, a diferencia de PHP no hay versión de esc_html__ así que utilizamos la versión normal.
Precaución

Uso de React

Como te puedes dar cuenta por este pequeño código (y el título del post…). Éste tutorial asume que tienes al menos un conocimiento básico de ReactJS, si no es así; te invito a estudiarlo un poco para que no pierdas el hilo de este tema.

Paso 2: Agrega algunas opciones

Ahora que tenemos nuestra aplicación corriendo podemos comenzar a agregar opciones a nuestra página, una de las más comunes que me encuentro es la de campos de texto, tal vez para algún API, por ejemplo:

1/**
2 * WordPress dependencies
3 */
4import { Card, CardBody, TextControl } from '@wordpress/components';
5import { useState } from '@wordpress/element';
6import { __ } from '@wordpress/i18n';
7const Settings = () => {
8 const [apiKey, setApiKey] = useState('');
9 return (
10 <>
11 <h1>{__('Selecciona las opciones deseadas', 'mah-settings')}</h1>
12 <Card>
13 <CardBody>
14 <TextControl
15 help={__('Ingresa tu API key', 'mah-settings')}
16 label={__('API Key', 'mah-settings')}
17 onChange={setApiKey}
18 value={apiKey}
19 />
20 </CardBody>
21 </Card>
22 </>
23 );
24};
25export default Settings;
26

Al volver a recargar la página, podremos ver que ¡nuestra página de opciones toma forma! aunque podemos agregar algo de sabor, pero eso lo haremos más adelante, ahora que tenemos nuestro campo, expliquemos que pasa aquí:

  1. Se agregan algunos componentes más de WordPress, esta vez son Card, CardBody, y TextControl. En realidad el importante es TextControl ya que es el que utilizaremos para ingresar nuestras opciones
  2. Importamos useState de @wordpress/element (una vez más, React viene incluido)
  3. Agregamos un estado vacío que se actualizará cuando cambiemos algo en TextControl
  4. El uso de fragmentos de React, solo que utilizamos su versión recortada, en lugar de import { Fragment } from '@wordpress/element' simplemente utilizamos <></>
Página de opciones con campo de texto
Consejo

@wordpress/components viene con muchos componentes disponibles, sugiero revisar el Storybook para ver una demostración que los que tenemos a nuestra disposición

Como bonus, agreguemos un toggle simplemente porque me gusta como funcionan:

1/**
2 * WordPress dependencies
3 */
4import {
5 Card,
6 CardBody,
7 CardDivider,
8 TextControl,
9 ToggleControl,
10} from '@wordpress/components';
11import { useState } from '@wordpress/element';
12import { __ } from '@wordpress/i18n';
13const Settings = () => {
14 const [apiKey, setApiKey] = useState('');
15 const [toggled, setToggled] = useState(false);
16 return (
17 <>
18 <h1>{__('Selecciona las opciones deseadas', 'mah-settings')}</h1>
19 <Card>
20 <CardBody>
21 <TextControl
22 help={__('Ingresa tu API key', 'mah-settings')}
23 label={__('API Key', 'mah-settings')}
24 onChange={setApiKey}
25 value={apiKey}
26 />
27 </CardBody>
28
29 <CardDivider />
30
31 <CardBody>
32 <ToggleControl
33 label={__('Activar funcionalidad', 'mah-settings')}
34 onChange={setToggled}
35 checked={toggled}
36 />
37 </CardBody>
38 </Card>
39 </>
40 );
41};
42export default Settings;
43

¿Qué pasó?

Si recargamos la página, nos damos cuenta de que nuestro toggle se ve más bien como un checkbox, ¿qué pasó?

Toggle como checkbox

Lo que sucede es que a pesar de que nuestras dependencias de javascript se agregan automáticamente a nuestro script, no sucede lo mismo con nuestras dependencias de estilos. Por lo que puede ser necesario que las agreguemos nosotros mismos al archivo class-mah-settings.php de una forma similar a lo que hicimos con el script de javascript:

class-mah-settings.php

1/**
2 * Registra los scripts y estilos.
3 *
4 * @return void
5 */
6public function enqueue_scripts(): void {
7 $screen = get_current_screen();
8 if ( $screen->id !== $this->menu_slug ) {
9 return;
10 }
11 $asset = include $this->plugin_path . '/build/settings.asset.php';
12 wp_enqueue_script(
13 'mah-settings',
14 plugins_url() . '/mah-settings-react/build/settings.js',
15 $asset['dependencies'],
16 $asset['version'],
17 true
18 );
19 wp_enqueue_style( 'wp-components' );
20}
21

Al volver a recargar la página veremos el resultado deseado, y si nos fijamos bien, también nuestro campo de texto mejoró en apariencia:

Página de opciones con campo de texto y toggle

Paso 3: Registrar las opciones en el backend

Para poder guardar nuestras opciones, necesitamos tener valores en la base de datos a donde guardarlos, WordPress se maneja básicamente con los siguientes tipos:

  • Theme mods1
  • Post meta22
  • Site Options33

En nuestro caso utilizaremos las opciones globales, debido a la naturaleza de nuestra página de opciones.

En php, podemos registrarlas de esta forma:

php/class-mah-settings.php

1/**
2 * Registra los hooks.
3 *
4 * @return void
5 */
6public function init(): void {
7 add_action( 'admin_menu', [ $this, 'add_menu_page' ] );
8 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_scripts' ] );
9 add_action( 'admin_init', [ $this, 'register_settings' ] );
10 add_action( 'rest_api_init', [ $this, 'register_settings' ] );
11}
12

php/class-mah-settings.php

1/**
2 * Registra las opciones.
3 *
4 * @return void
5 */
6public function register_settings(): void {
7 register_setting(
8 'mah_settings',
9 'mah_api_key',
10 [
11 'description' => __( 'API Key', 'mah-settings' ),
12 'sanitize_callback' => 'sanitize_text_field',
13 'show_in_rest' => true,
14 'type' => 'string',
15 ]
16 );
17 register_setting(
18 'mah_settings',
19 'mah_function',
20 [
21 'description' => __( 'Funcion X', 'mah-settings' ),
22 'show_in_rest' => true,
23 'type' => 'boolean',
24 ]
25 );
26}
27
Advertencia

El segundo hook rest_api_init es necesario para poder utilizar nuestras opciones en React, de lo contrario show_in_rest no tendría ningún efecto

Paso 4: Agregar botón de guardado con React

Ahora sólo necesitamos guardar nuestras opciones desde el lado de React, para lo cual necesitamos agregar un botón de guardado a nuestra aplicación, y agregar un evento cuando éste sea presionado:

1/**
2 * WordPress dependencies
3 */
4import {
5 Button,
6 Card,
7 CardBody,
8 CardDivider,
9 CardFooter,
10 TextControl,
11 ToggleControl,
12} from '@wordpress/components';
13import { useState } from '@wordpress/element';
14import { __ } from '@wordpress/i18n';
15const Settings = () => {
16 const [apiKey, setApiKey] = useState('');
17 const [toggled, setToggled] = useState(false);
18 const saveSettings = () => {
19 console.log('Guardar');
20 };
21 return (
22 <>
23 <h1>{__('Selecciona las opciones deseadas', 'mah-settings')}</h1>
24 <Card>
25 <CardBody>
26 <TextControl
27 help={__('Ingresa tu API key', 'mah-settings')}
28 label={__('API Key', 'mah-settings')}
29 onChange={setApiKey}
30 value={apiKey}
31 />
32 </CardBody>
33
34 <CardDivider />
35
36 <CardBody>
37 <ToggleControl
38 label={__('Activar funcionalidad', 'mah-settings')}
39 onChange={setToggled}
40 checked={toggled}
41 />
42 </CardBody>
43
44 <CardFooter>
45 <Button disabled={!apiKey} onClick={saveSettings} variant='primary'>
46 {__('Guardar', 'mah-settings')}
47 </Button>
48 </CardFooter>
49 </Card>
50 </>
51 );
52};
53export default Settings;
54

Una breve explicación de lo que acabamos de agregar:

  1. Traemos un nuevo componente CardFooter, que nos ayudará a mantener el estilo de nuestra tarjeta
  2. Traemos el componente Button que viene con WordPress, esto nos brinda unas ventajas más sobre utilizar botones regulares, como el que ya viene con estilos por ejemplo, en esta ocasión utilizamos la variante primary. Y nos aseguramos de que se mantenga deshabilitado si el campo de API key no ha sido llenado
  3. Agregamos la función saveSettings que se encargará de guardar nuestras opciones

Así al dar click al botón veremos como en la consola se registra nuestra acción, ahora sólo debemos reemplazarla por la verdadera función de guardado.

Página de opciones con campo de texto, toggle y botón de guardado

Próximamente…

Mi idea original era terminar el tutorial en esta parte, pero me di cuenta de lo largo que se está volviendo el post y aún quedan bastantes conceptos que quiero tocar, así que he decidido que éste es un buen momento para terminar este post y regresar la próxima semana con una tercera parte en donde guardaremos nuestras opciones, terminaremos de crear una página de opciones; y veremos conceptos como:

  • El uso de useDispatch, useEntityProp, y saveEditedEntityRecord
  • Mejoras de UX para nuestra página
  • Introducción general al paquete @wordpress/data y el uso de stores.

Mientras tanto puedes revisar el código de ésta segunda parte en mi repositorio.

Como siempre son bienvenidos tus comentarios y sugerencias sobre que cosas te gustaría ver explicadas en este humilde blog. ¡Hasta la próxima!

Leer más

Notas al pie

  1. Muy populares en los días de auje de customizer, los theme mods están ligados al tema que se usa en nuestro sitio, en caso de que el tema cambie, los mods también desaparecen, pero regresan cuando el tema al que están ligados vuelva a seleccionarse. Pero con la llegada de FSE, estos comienzan a ser irrelevantes en mi opinión ↩︎

  2. Los post meta, son básicamente los attributos que están ligados a un post en específico, estos pueden cambiar de post a post ↩︎

  3. Utilizados para opciones globales que pueden ser utilizadas ya sea por un tema o por un plugin, sin importar que post o tema esté seleccionado en el sitio ↩︎