No hace falta que gestiones muchos de los 800 millones de sitios de WordPress que hay en la red para que busques formas de lanzar nuevos sitios de forma eficaz.

Clonar una configuración de WordPress existente es una forma de ponerse en marcha rápidamente, y los clientes del servicio de alojamiento administrado de WordPress de Kinsta saben que eso se hace fácilmente desde nuestro panel de control MyKinsta.

Es más, puedes clonar sitios WordPress a escala utilizando tus tecnologías de desarrollo de aplicaciones favoritas y la API de Kinsta. En este tutorial, utilizaremos esa API y React, una de las muchas bibliotecas de JavaScript populares, para mostrar cómo funciona.

Lo Que Construirás

Este es el escenario: Eres una agencia de desarrollo de WordPress con uno o más sitios que pueden utilizarse como plantillas de inicio. La aplicación React para clonar sitios de WordPress que estamos construyendo tiene este aspecto:

React application for cloning site with Kinsta API
Aplicación React para clonar sitios con la API de Kinsta.

Requisitos previos

Para seguir este tutorial, necesitarás conocimientos básicos de HTML, CSS y JavaScript y cierta familiaridad con React. Además, necesitarás Node.js y npm (el Gestor de Paquetes de Node) o yarn instalados en tu ordenador. Este proyecto se centra en la creación de una aplicación de clonación de WordPress utilizando React y la API Kinsta, más que en los detalles de la creación y el estilo de la interfaz de usuario.

Configurar el Entorno de Desarrollo

Puedes crear una aplicación React desde cero y desarrollar tu propia interfaz, o puedes coger la plantilla de inicio Git mencionada anteriormente siguiendo estos pasos:

  1. Visita el repositorio GitHub de este proyecto.
  2. Selecciona Usar esta plantilla > Crear un nuevo repositorio para copiar el código de inicio en un repositorio dentro de tu cuenta de GitHub. (Marca la casilla incluir todas las ramas)
  3. Extrae el repositorio a tu ordenador local y cambia a la rama starter-files utilizando el comando: git checkout starter-files
  1. Instala las dependencias necesarias ejecutando el comando npm install

Una vez completada la instalación, puedes lanzar el proyecto en tu ordenador local con npm run start. Esto abre el proyecto en http://localhost:3000/.

Comprender los archivos del proyecto

La carpeta src es el corazón de una aplicación React, ya que contiene el JavaScript que necesita webpack. En la carpeta se encuentra App.js, donde se configuran las dos rutas de este proyecto.

Dentro de la carpeta src están las subcarpetas components y pages. La carpeta components contiene componentes reutilizables, como Header.jsx y Footer.jsx, utilizados en las páginas Home.jsx y Operations.jsx .

Tu objetivo aquí es implementar la lógica en Home.jsx y Operations.jsx, ya que el estilo y el enrutamiento se pueden encontrar en nuestros archivos de inicio de GitHub.

Home.jsx tiene un formulario con dos campos: el nombre del sitio que estás creando y un campo de selección que enumera los sitios de WordPress que se encuentran en tu cuenta MyKinsta (esta lista se obtiene a través de la API de Kinsta).

Cuando se pulsa el botón de envío del formulario (Clonar sitio), se devuelve un objeto que contiene una propiedad operation_id. Este ID y el nombre para mostrar se pasarán como parámetros de ruta a Operations.jsx, donde se informa del estado de la operación de clonación. La interfaz también incluirá enlaces para acceder al inicio de sesión del administrador de WordPress y a la página de inicio del sitio.

Operations page showing links to WP admin and site
Página de operaciones mostrando enlaces al admin de WP y al sitio.

Utilización de la API de Kinsta para Clonar un Sitio de WordPress

En Home.jsx, se realizarán tres peticiones a la API de Kinsta. La primera petición es para obtener una lista de sitios en tu cuenta Kinsta. Esto se almacenará en un estado y luego se iterará al campo de selección. Esta petición se realizará inmediatamente después de que la página se ejecute utilizando el gancho useEffect.

La segunda y tercera petición se realizan cuando se pulsa el botón Clonar sitio. La segunda petición obtiene el ID de entorno del sitio que quieres clonar. La tercera petición utiliza ese ID de entorno y el nombre para mostrar del sitio para iniciar la clonación del sitio.

Interactuar con la API de Kinsta en React

En este tutorial, interactúas con dos puntos finales de la API Kinsta:

  • /sites: Este puede devolver una lista de todos los sitios, solicitar un ID de entorno del sitio y, por último, clonar un sitio existente.
  • /operations: Se utiliza para obtener el estado de la operación. Por ejemplo, cuando la operación de clonación de un sitio está en curso, puedes utilizar este punto final para rastrear mediante programación el estado de la operación y determinar cuándo ha finalizado.

Para interactuar con la API de Kinsta, necesitas el ID de tu empresa (se puede encontrar en MyKinsta en Empresa > Detalles de facturación > ID de la empresa) y una clave API. Aquí te explicamos cómo crear una clave API de Kinsta.

Una vez que tengas estas credenciales, lo mejor es almacenarlas de forma segura como variables de entorno en tu aplicación React. Para configurar las variables de entorno, crea un archivo .env en la carpeta raíz de tu proyecto. Dentro de este archivo, añade las siguientes líneas:

REACT_APP_KINSTA_COMPANY_ID = 'YOUR_COMPANY_ID' 
REACT_APP_KINSTA_API_KEY = 'YOUR_API_KEY'

Para acceder a estas variables de entorno dentro de tu proyecto, puedes utilizar la sintaxis process.env.THE_VARIABLE. Por ejemplo, para acceder a la REACT_APP_KINSTA_COMPANY_ID, utilizarías process.env.REACT_APP_KINSTA_COMPANY_ID.

Clonar un sitio existente con la API de Kinsta

Empecemos por obtener la lista de todos los sitios cuando Home.jsx se ejecuta utilizando el Gancho useEffect y almacenándolos en un estado. Para ello, importa los Ganchos useEffect y useState y crea un estado para almacenar la matriz de sitios que se obtendrán:

import { useState, useEffect } from 'react';
const [sites, setSites] = useState([]);

A continuación, utiliza el gancho useEffect para consultar la API Kinsta mediante la API JavaScript Fetch. En primer lugar, crea dos variables constantes para almacenar las cabeceras y la URL de la API Kinsta. Esto se hace para evitar repeticiones, ya que enviarás más de una solicitud a la API Kinsta en esta página:

const KinstaAPIUrl = 'https://api.kinsta.com/v2';
const headers = useMemo(() => {
    return {
        Authorization: `Bearer ${process.env.REACT_APP_KINSTA_API_KEY}`
    };
}, []);

En el código anterior, el Gancho useMemo memoriza el objeto headers para que no sea necesario reevaluarlo en cada renderización, ya que su valor es constante. Ahora puedes crear la solicitud a la API:

useEffect(() => {
    const fetchAllSites = async () => {
        const query = new URLSearchParams({
            company: process.env.REACT_APP_KINSTA_COMPANY_ID,
        }).toString();
        const resp = await fetch(
            `${KinstaAPIUrl}/sites?${query}`,
            {
                method: 'GET',
                headers
            }
        );
        const data = await resp.json();
        setSites(data.company.sites);
    };
    fetchAllSites();
}, [headers]);

En el código anterior, se crea una función asíncrona fetchAllSites. Dentro de esta función, primero defines el parámetro query (el ID de tu empresa) obtenido de tu archivo .env. A continuación, realizas una solicitud GET al punto final /sites de la API Kinsta utilizando el parámetro query. La respuesta se almacena entonces en el estado sites que creaste anteriormente. Por último, llamas a fetchAllSites para iniciar el proceso de obtención.

Ahora vamos a incorporar los valores almacenados en el estado sites haciendo un bucle a través de ellos para rellenar el campo de selección. El nombre para mostrar se mostrará al usuario, mientras que el ID del sitio se utilizará como valor de la opción. De esta forma, cuando se envíe el formulario, el ID del sitio seleccionado podrá utilizarse para consultar los detalles del entorno:

<div className="input-div">
    <label>Select a site</label>
    <span>Select the site you want to clone</span>
    <select className="form-control">
        <option> value=""></option>
        {sites && (
            sites.map((site) => {
                return (
                    <option> key={site.id} value={site.id}>{site.display_name}</option>
                )
            })
        )}
    </select>
</div>

Procedamos a gestionar el envío del formulario y a recuperar valores del mismo. Para ello, necesitas crear variables de estado para cada campo de entrada:

const [selectedSiteId, setSelectedSiteId] = useState('');
const [displayName, setDisplayName] = useState('');

A continuación, vincula los campos del formulario a sus respectivos valores de estado añadiendo los atributos value y onChange a cada elemento de entrada. Este es el aspecto que tendrá el formulario:

<form>
    <div className="form-container">
        <div className="input-div">
            <label>Display name</label>
            <span>Helps you identify your site. Only used in MyKinsta and temporary domain</span>
            <input type="text" className="form-control" value={displayName} onChange={(e) => setDisplayName(e.target.value)} />
        </div>
        <div className="input-div">
            <label>Select a site</label>
            <span>Select the site you want to clone</span>
            <select className="form-control" value={selectedSiteId} onChange={(e) => setSelectedSiteId(e.target.value)}>
                <option value=""></option>
                {sites && (
                    sites.map((site) => {
                        return (
                            <option key={site.id} value={site.id}>{site.display_name}</option>
                        )
                    })
                )}
            </select>
        </div>
        <button className='btn'>Clone Site</button>
    </div>
</form>

En el código anterior, cada elemento de entrada tiene el atributo value establecido en la variable de estado correspondiente, y el atributo onChange se utiliza para actualizar el valor de estado cuando el usuario interactúa con los campos de entrada.

Para gestionar el envío del formulario, adjunta un método onSubmit al elemento formulario. Por ejemplo

<form> onSubmit={handleSubmission}>
    {/* form details */}
</form>

Define el método handleSubmission, que consiste en realizar dos peticiones a la API de Kinsta. La primera petición recupera el ID de entorno del sitio que se va a clonar, y la segunda petición realiza la operación de clonación.

Empecemos por recuperar el ID del entorno. Dentro del método handleSubmission, crea una función asíncrona para gestionar esta petición. La función enviará una petición GET al endpoint /sites, añadiendo el ID del sitio seleccionado, seguido del campo /environments punto final:

const handleSubmission = async (e) => {
    e.preventDefault();
    const fetchEnvironmentId = async (siteId) => {
        const resp = await fetch(
            `${KinstaAPIUrl}/sites/${siteId}/environments`,
            {
                method: 'GET',
                headers
            }
        );
        const data = await resp.json();
        let envId = data.site.environments[0].id;
        return envId;
    }
    let environmentId = await fetchEnvironmentId(selectedSiteId);
}

Arriba, fetchEnvironmentId es una función asíncrona que envía una solicitud GET a la API de Kinsta. Obtiene los entornos del sitio seleccionado y extrae el ID del entorno de la respuesta. El ID del entorno se almacena en la variable envId y luego se devuelve. Al llamar a la función, asignamos su valor de retorno a la variable envId.

Llegados a este punto, puedes clonar un sitio existente con la API de Kinsta porque tienes la información esencial sobre el sitio de origen: el ID de la empresa, el nombre para mostrar y el ID del entorno.

Dentro del método handleSubmission, crea una función llamada cloneExistingSite para gestionar esta petición a la API. Esta solicitud se dirigirá al /sites/clone punto final. A diferencia de las peticiones anteriores, las cabeceras de esta petición son diferentes porque necesitas especificar el Content-Type como application/json. Además, se trata de una solicitud POST, por lo que debes incluir un cuerpo de solicitud que contenga la carga útil que deseas enviar a la API. Así es como se estructurará la solicitud:

const handleSubmission = async (e) => {
    e.preventDefault();

    // fetch environment Id

    const cloneExistingSite = async (env_Id) => {
        const resp = await fetch(
            `${KinstaAPIUrl}/sites/clone`,
            {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    Authorization: `Bearer ${process.env.REACT_APP_KINSTA_API_KEY}`
                },
                body: JSON.stringify({
                    company: `${process.env.REACT_APP_KINSTA_COMPANY_ID}`,
                    display_name: displayName,
                    source_env_id: env_Id,
                })
            }
        );
        const data = await resp.json();
        navigate(`/operations/${displayName}/${data.operation_id}`)
        console.log(data);
    }
    cloneExistingSite(environmentId);
}

En este código, la solicitud body se construye utilizando JSON.stringify() para convertir el objeto de carga útil en una cadena JSON. A continuación, la respuesta se almacena en la variable de datos. Utilizando el método useNavigate de la biblioteca react-router-dom se pasa displayName y operation_id como parámetros de la ruta. Asegúrate de importar el método useNaviagte e instanciarlo:

// Import the required method 
import { useNavigate } from 'react-router-dom'; 

// Instantiate the useNavigate method 
const navigate = useNavigate();

Ahora, cuando rellenes el formulario y hagas clic en el botón Clonar sitio, un nuevo sitio iniciará el proceso de clonación, que será visible en tu panel de MyKinsta. Sin embargo, queremos seguir la operación de clonación del sitio programáticamente dentro de la IU personalizada. Maneja esto en Operations.jsx utilizando los datos enviados a través de la ruta.

Implementación de la comprobación del estado de la operación con la API de Kinsta

En Operations.jsx, recupera el ID de la operación de la ruta utilizando el método useParams de react-router-dom. Este ID se utilizará para realizar una solicitud a la API cada vez que se haga clic en el botón Comprobar Estado del Sitio.

Primero, importa el método useParams y utilízalo para instanciar las variables displayName y operationId:

// Import the useParams library
import { useParams } from 'react-router-dom';

// Instantiate the paramters
const { displayName, operationId } = useParams();

A continuación, crea un estado para almacenar el estado de la operación cuando se realice la solicitud:

const [operationData, setOperationData] = useState({ message: "Operation in progress." });

En el código anterior, el estado se inicializa con un mensaje por defecto, que se mostrará hasta que se pulse el botón Comprobar Estado del Sitio. Añade un evento onClick al botón Comprobar Estado del Sitio y llama al método checkOperation cuando se haga clic en el botón:

<button> className='sm-btn' onClick={() => checkOperation()}>Check Site Status</button>

Ahora, crea la función checkOperation para realizar la solicitud de operación a la API de Kinsta. Almacena las constantes headers y KinstaAPIUrl en variables, y luego utilízalas en la solicitud a la API:

const KinstaAPIUrl = 'https://api.kinsta.com/v2';
const headers = useMemo(() => {
    return {
        Authorization: `Bearer ${process.env.REACT_APP_KINSTA_API_KEY}`
    };
}, []);

const checkOperation = async () => {
    const resp = await fetch(
        `${KinstaAPIUrl}/operations/${operationId}`,
        {
            method: 'GET',
            headers
        }
    );
    const data = await resp.json();
    setOperationData(data);
};

En el código anterior, se envía una solicitud GET al punto final /operations con el ID de la operación, y la respuesta se almacena en el estado operationData. Ahora, puedes utilizar los datos dentro del marcado:

<div className="services">
    <div className="details">
        <p>{operationData.message}..</p>
        <button> className='sm-btn' onClick={() => checkOperation()}>Check Site Status</button>
    </div>
</div>

Por último, los datos de displayName pasados a través de la ruta se utilizarán para construir la URL del nuevo sitio y la URL de administración de WordPress. Ambos enlaces se abrirán en una nueva pestaña.

<div className="details">
    <a href={`http://${displayName}.kinsta.cloud/wp-admin/`} target="_blank" rel="noreferrer" className='detail-link'>
        <p>Open WordPress admin</p>
        <FiExternalLink />
    </a>
    <a href={`http://${displayName}.kinsta.cloud/`} target="_blank" rel="noreferrer" className='detail-link'>
        <p>Open URL</p>
        <FiExternalLink />
    </a>
</div>

Con estos cambios, Operations.jsx recuperará el ID de la operación de la ruta, realizará una solicitud a la API cuando se pulse el botón, mostrará el estado de la operación y proporcionará enlaces a la URL del sitio y del administrador de WordPress basándose en los datos de displayName.

Despliega Tu Aplicación en Kinsta

Para desplegar tu aplicación en la plataforma de alojamiento de aplicaciones de Kinsta, tienes que enviar el proyecto a tu proveedor Git preferido. Cuando tu proyecto esté alojado en GitHub, GitLab o Bitbucket, puedes proceder a desplegarlo en Kinsta.

Para desplegar tu repositorio en Kinsta, sigue estos pasos:

  1. Inicia sesión o crea tu cuenta Kinsta en el panel MyKinsta.
  2. En la barra lateral izquierda, haz clic en Aplicaciones y luego en Añadir servicio.
  3. Selecciona Aplicación en el menú desplegable para desplegar una aplicación React en Kinsta.
  4. En el modal que aparece, elige el repositorio que quieres desplegar. Si tienes varias ramas, puedes seleccionar la rama deseada y dar un nombre a tu aplicación.
  5. Selecciona una de las ubicaciones de centros de datos disponibles en la lista de opciones de 25.
  6. Kinsta detecta automáticamente el comando de inicio de tu aplicación.

Por último, no es seguro enviar claves API a hosts públicos como tu proveedor de Git. Cuando alojes, puedes añadirlas como variables de entorno utilizando el mismo nombre de variable y valor especificados en el archivo .env.

environment variables
Establece variables de entorno en MyKinsta al desplegar.

Una vez que inicias el despliegue de tu aplicación, comienza el proceso y normalmente se completa en unos minutos. Un despliegue con éxito genera un enlace a tu aplicación, como https://clone-wp-site-12teh.kinsta.app/.

Resumen

La API de Kinsta ofrece flexibilidad para crear interfaces de usuario personalizadas para administrar sitios WordPress, incluyendo la posibilidad de clonar sitios existentes y gestionar varios aspectos de tu entorno WordPress.

En este artículo, has aprendido a desarrollar una aplicación que permite clonar sitios fuera de MyKinsta.

¿Cómo utilizas la API de Kinsta? ¿Qué funciones y puntos finales te gustaría que se añadieran a la API? ¡Compártelos en la sección de comentarios!

Joel Olawanle Kinsta

Joel is a Frontend developer working at Kinsta as a Technical Editor. He is a passionate teacher with love for open source and has written over 200 technical articles majorly around JavaScript and it's frameworks.