Los plugins desempeñan un papel vital en la personalización y mejora de tus sitios de WordPress. Se utilizan para añadir funcionalidades como formularios de contacto, comercio electrónico y analíticas a tus sitios sin necesidad de programación.

Al igual que WordPress, que recibe actualizaciones periódicas, los plugins también reciben actualizaciones periódicas para añadir nuevas funciones, parchear un agujero de seguridad, aumentar la compatibilidad, etc. Por eso Kinsta incluyó la Administración de Plugins y Temas entre las herramientas disponibles en MyKinsta para cada uno de tus sitios.

Sin embargo, la actualización de plugins en muchos sitios aún puede ser desalentadora para clientes ocupados como las agencias. Este artículo muestra una solución que utiliza la API de Kinsta para gestionar simultáneamente los plugins de varios sitios.

Qué Estás Construyendo

Esta guía se centra en la construcción de una solución avanzada utilizando la API de Kinsta, que ahora ofrece endpoints para recuperar y actualizar plugins.

En ella, creamos una aplicación React personalizada que obtiene todos los plugins de tu cuenta de empresa Kinsta. Esta herramienta te permite identificar y actualizar un plugin específico en múltiples sitios, agilizando el proceso significativamente.

Herramienta creada con React y la API de Kinsta para actualizar de forma masiva plugins de WordPress en múltiples sitios.
Herramienta creada con React y la API de Kinsta para actualizar de forma masiva plugins de WordPress en múltiples sitios.

Requisitos previos de la aplicación

Para seguir este proyecto, debes tener lo siguiente:

Comprender la API de Kinsta

La API de Kinsta es una potente herramienta que te permite interactuar mediante programación con los servicios de Kinsta, como los sitios alojados de WordPress. Puede ayudarte a automatizar varias tareas relacionadas con la gestión de WordPress, como la creación de sitios, la recuperación de información sobre sitios, la obtención del estado de un sitio, la exploración y restauración de copias de seguridad, etc.

Para utilizar la API de Kinsta, debes tener una cuenta con al menos un sitio, aplicación o base de datos de WordPress en MyKinsta. También debes generar una clave API para autenticarte y acceder a tu cuenta.

Para generar una clave API:

  1. Ve a tu panel de MyKinsta.
  2. Ve a la página Claves API (Tu nombre > Configuración de la empresa > Claves API).
  3. Haz clic en Crear Clave API.
  4. Elige una fecha de caducidad o establece una fecha de inicio personalizada y un número de horas para que caduque la clave.
  5. Dale a la clave un nombre único.
  6. Haz clic en Generar.

Después de crear una clave API, cópiala y guárdala en un lugar seguro (se recomienda utilizar un gestor de contraseñas). Puedes generar varias claves API, que aparecerán en la página Claves API. Si necesitas revocar una clave API, haz clic en el botón Revocar.

Configura tu entorno de desarrollo React

React es una popular biblioteca JavaScript para crear interfaces de usuario. Permite a los desarrolladores crear componentes declarativos que representan diferentes partes de la interfaz de usuario. Estos componentes se definen utilizando la sintaxis JSX, una combinación de JavaScript y HTML.

Para empezar, sigue estos pasos:

  1. Navega hasta la carpeta en la que desees crear tu proyecto y utiliza create-react-app para crear un proyecto React:
    npx create-react-app <project-name>

    Cambia <project-name> por el nombre que prefieras para tu proyecto.

  2. Una vez hecho esto, navega hasta la carpeta del proyecto e inicia el servidor de desarrollo:
    cd <project-name>
    npm run start

    Tu aplicación React se abrirá en tu navegador web predeterminado en http://localhost:3000.

La creación de un proyecto React mediante create-react-app establece una estructura de carpetas. La carpeta crucial es src, donde tiene lugar el desarrollo. Los archivos clave de esta carpeta son:

  • App.js: Este es el componente principal, que renderiza todos los demás en tu aplicación React. Aquí es donde se añadirá todo tu código para esta herramienta.
  • index.js: Es el punto de entrada, se carga primero y es responsable de renderizar App.js.
  • index.css: Este archivo define el estilo y el diseño general de tu aplicación. Todos los estilos se añadirán aquí.

Crear y estilizar la interfaz de usuario

Vamos a centrarnos en crear y estilizar la interfaz de una aplicación básica alojada en el archivo App.js sin implicar enrutamiento. Nuestra interfaz de usuario principal es un formulario con un campo select para listar los plugins únicos de tus sitios Kinsta junto a un botón submit para buscar sitios con el plugin seleccionado.

Interfaz de usuario de la herramienta de gestión de plugins para acceder a una lista de plugins y cargar sitios.
Interfaz de usuario de la herramienta de gestión de plugins para acceder a una lista de plugins y cargar sitios.

Además, una sección de visualización muestra detalles del sitio como el nombre, el estado del plugin y la versión. Incluye un botón para actualizar cada sitio si es necesario y un botón general para actualizar en bloque todos los sitios que requieran la actualización del plugin.

En tu archivo App.js, añade el siguiente código:

import KinstaLogo from './images/kinsta_logo.png';

const App = () => {
    return (
        <div className="container">
            <div className="title-section">
                <img src={KinstaLogo} className="logo" alt="" />
                <h2>Manage your site's plugins</h2>
                <p>
                    Easily update plugins across all sites hosted with Kinsta using the
                    Kinsta API.
                </p>
            </div>
            <div> className="info-section">
                <p>
                    This application allows you to retrieve a list of all sites within
                    your company that uses a specific plugin. You can then choose to update
                    the plugin across all these sites simultaneously or individually.
                </p>
            </div>
            <div className="form-section">
                <form>
                    <div className="form-control">
                        <label> htmlFor="plugin-name">Plugin name</label>
                        <select name="plugin-name" id="plugin-name">
                            <option> value="">Select a plugin</option>
                        </select>
                    </div>
                    <button> className="btn">Fetch sites with this plugin</button>
                </form>
            </div>
            <div className="display_container">
                <div className="site-list">
                    <div className="list-title">
                        <h3>Sites with WooCommerce plugin</h3>

                        <button> className="sm-btn">Update all sites to v.3.6</button>
                    </div>
                    <ul>
                        <li>
                            <div className="info">
                                <p>
                                    <b>Site Name:</b> WooCommerce
                                </p>
                                <p>
                                    <b>Plugin Status:</b> active
                                </p>
                                <p>
                                    <b>Plugin Version:</b> 3.5.1
                                </p>
                            </div>
                            <button> className="sm-btn">Update to v.5.6</button>
                        </li>
                    </ul>
                </div>
            </div>
        </div>
    );
};

export default App;

Para dar estilo a este proyecto, visita el archivo CSS en nuestro repositorio completo de GitHub y copia su código en tu archivo index.css.

Interactuar con la API de Kinsta

La API de Kinsta ofrece una serie de endpoints esenciales para acceder a diversos parámetros necesarios para interactuar con el plugin de un sitio. Por ejemplo, si deseas recuperar o actualizar un plugin, primero debes obtener el ID de entorno del sitio.

Obtener este ID de entorno es un proceso secuencial. Inicialmente, debes determinar el ID del sitio. Para obtener el ID del sitio, debes tener el ID de tu empresa Kinsta. Este ID de empresa está disponible en tu panel de MyKinsta (Configuración de la empresa > Detalles de facturación), y es información sensible que no querrás compartir con nadie, como tu clave API.

Puedes almacenarlos de forma segura como variables de entorno en tu aplicación React creando un archivo .env en la carpeta raíz de tu proyecto. En este archivo, añade lo siguiente con el valor correcto:

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.

Si añades el archivo .env a tu archivo .gitignore es importante para evitar que se envíe a GitHub. Esto garantiza que tu información sensible permanezca privada y segura.

Recuperar todos los sitios y plugins utilizando la API de Kinsta

Para recuperar los datos de los plugins de todos los sitios gestionados por tu cuenta de empresa Kinsta, puedes utilizar la API Kinsta ejecutando tres peticiones API. Aquí tienes una explicación simplificada:

Comienza almacenando la URL de la API Kinsta en una variable para facilitar la consulta.

const KinstaAPIUrl = 'https://api.kinsta.com/v2';
  1. Obtener la lista de sitios de la empresa: Necesitas obtener una lista de todos los sitios de WordPress asociados a tu empresa. Para ello, construye una consulta utilizando el ID de la empresa, realiza una solicitud GET con la autorización adecuada, procesa la respuesta en formato JSON y extrae los detalles del sitio de la respuesta.
    const query = new URLSearchParams({
        company: process.env.REACT_APP_KINSTA_COMPANY_ID,
    }).toString();
    const response = await fetch(`${KinstaAPIUrl}/sites?${query}`, {
        method: 'GET',
        headers: { Authorization: `Bearer ${process.env.REACT_APP_KINSTA_API_KEY}` },
    });
    
    const data = await response.json();
    const companySites = data.company.sites;
  2. Recuperar el ID del entorno del sitio: El paso anterior devuelve un array de sitios de WordPress. Para cada sitio, haz un bucle y otra petición GET para obtener los entornos asociados.
    const sitesEnvironmentData = companySites.map(async (site) => {
        const siteId = site.id;
        const resp = await fetch(`${KinstaAPIUrl}/sites/${siteId}/environments`, {
            method: 'GET',
            headers: {
                Authorization: `Bearer ${process.env.REACT_APP_KINSTA_API_KEY}`,
            },
        });
        const data = await resp.json();
        const environments = data.site.environments;
        return {
            id: siteId,
            name: site.display_name,
            environments: environments,
        };
    });
  3. Obtener la lista de plugins de sitios de WordPress: Tras obtener el ID del sitio, el nombre y el entorno, ahora puedes utilizar el ID del entorno para obtener una lista de todos los plugins de cada sitio. Primero tienes que resolver las promesas del paso anterior y luego hacer las peticiones GET para los plugins:
    // Wait for all the promises to resolve
    const sitesData = await Promise.all(sitesEnvironmentData);
    
    // Get all plugins for each environment
    const sitesWithPlugin = sitesData.map(async (site) => {
        const environmentId = site.environments[0].id;
        const resp = await fetch(
            `${KinstaAPIUrl}/sites/environments/${environmentId}/plugins`,
            {
                method: 'GET',
                headers: {
                    Authorization: `Bearer ${process.env.REACT_APP_KINSTA_API_KEY}`,
                },
            }
        );
        const data = await resp.json();
        const plugins = data.environment.container_info;
        return {
            env_id: environmentId,
            name: site.name,
            plugins: plugins,
        };
    });
    
    const sitesWithPluginData = await Promise.all(sitesWithPlugin);
    return sitesWithPluginData;
  4. Consolidando el proceso: Para agilizar el proceso, puedes encapsular estas peticiones a la API en una única función asíncrona getSitesWithPluginData, que puede reutilizarse. Esta función ejecutará los pasos descritos anteriormente y devolverá un array con la información esencial sobre cada sitio, incluyendo el ID del entorno, el nombre del sitio y un array de plugins.
    const getSitesWithPluginData = async () => {
        const query = new URLSearchParams({
            company: process.env.REACT_APP_KINSTA_COMPANY_ID,
        }).toString();
        const resp = await fetch(`${KinstaAPIUrl}/sites?${query}`, {
            method: 'GET',
            headers: {
                Authorization: `Bearer ${process.env.REACT_APP_KINSTA_API_KEY}`,
            },
        });
    
        const data = await resp.json();
        const companySites = data.company.sites;
    
        // Get all environments for each site
        const sitesEnvironmentData = companySites.map(async (site) => {
            const siteId = site.id;
            const resp = await fetch(`${KinstaAPIUrl}/sites/${siteId}/environments`, {
                method: 'GET',
                headers: {
                    Authorization: `Bearer ${process.env.REACT_APP_KINSTA_API_KEY}`,
                },
            });
            const data = await resp.json();
            const environments = data.site.environments;
            return {
                id: siteId,
                name: site.display_name,
                environments: environments,
            };
        });
    
        // Wait for all the promises to resolve
        const sitesData = await Promise.all(sitesEnvironmentData);
    
        // Get all plugins for each environment
        const sitesWithPlugin = sitesData.map(async (site) => {
            const environmentId = site.environments[0].id;
            const resp = await fetch(
                `${KinstaAPIUrl}/sites/environments/${environmentId}/plugins`,
                {
                    method: 'GET',
                    headers: {
                        Authorization: `Bearer ${process.env.REACT_APP_KINSTA_API_KEY}`,
                    },
                }
            );
            const data = await resp.json();
            const plugins = data.environment.container_info;
            return {
                env_id: environmentId,
                name: site.name,
                plugins: plugins,
            };
        });
    
        // Wait for all the promises to resolve
        const sitesWithPluginData = await Promise.all(sitesWithPlugin);
        return sitesWithPluginData;
    };

Recuperar plugins únicos de todos los sitios

En tu aplicación, quieres mostrar la lista de plugins de todos los sitios en un menú desplegable select. Para conseguirlo, la función getSitesWithPluginData recupera el ID de entorno, el nombre y los plugins de cada sitio. Estos datos constituyen la base para extraer una lista de plugins.

Define una nueva función, fetchAllSitesPluginsque llame a getSitesWithPluginData y procese su salida para obtener una lista de todos los plugins:

const fetchAllSitesPlugins = async () => {
    const sitesWithPluginData = await getSitesWithPluginData();

    // get all plugins
    const allPlugins = sitesWithPluginData.map((site) => {
        const { plugins } = site;
        return plugins.wp_plugins.data;
    });

   // …
};

Este código itera sobre los datos de cada sitio y compila una lista de plugins. Para asegurarte de que cada plugin se enumera sólo una vez, utiliza el objeto JavaScript Set, que almacena valores únicos:

// get unique plugins
    const uniquePlugins = [
        ...new Set(allPlugins.flat().map((plugin) => plugin.name)),
    ];

El método .flat() aplana la estructura del array y .map() la recorre para extraer sólo los nombres de los plugins. El objeto Set filtra los duplicados.

Para cargar y mostrar estos datos en tu aplicación React, utiliza los hooks useState() y useEffect():

import { useState, useEffect } from 'react';

const App = () => {
    const [pluginName, setPluginName] = useState('');
    const [plugins, setPlugins] = useState([]);

    //Get sites with plugin data
    const getSitesWithPluginData = async () => {
        // perform requests
    };

    useEffect(() => {
        const fetchAllSitesPlugins = async () => {
            const sitesWithPluginData = await getSitesWithPluginData();
            // get all plugins
            const allPlugins = sitesWithPluginData.map((site) => {
                const { plugins } = site;
                return plugins.wp_plugins.data;
            });
            // get unique plugins
            const uniquePlugins = [
                ...new Set(allPlugins.flat().map((plugin) => plugin.name)),
            ];
            setPlugins(uniquePlugins);
        };

        fetchAllSitesPlugins();
    }, []);

     // JSX render code follows
    //...
};

El hook useEffect() garantiza que los datos se obtienen y se establecen cuando se monta el componente. El hook useState() mantiene la lista de plugins únicos.

Por último, muestra estos plugins en un campo select. Si los plugins aún se están cargando, muestra un mensaje de marcador de posición:

<select>
    name="plugin-name"
    id="plugin-name"
    value={pluginName}
    onChange={(e) => setPluginName(e.target.value)}
>
    {plugins.length > 0 ? (
        <>
            <option value="">Select a plugin</option>
            {plugins.map((plugin) => (
                <option key={plugin} value={plugin.toLowerCase()}>
                    {plugin}
                </option>
            ))}
        </>
    ) : (
        <option> value="">Loading plugins...</option>
    )}
</select>

En este código:

  • El elemento select está vinculado a una variable de estado pluginName para almacenar el valor seleccionado.
  • El manejador onChange actualiza este estado cada vez que se selecciona un nuevo plugin.
  • La función plugins.map() crea dinámicamente elementos de opción para cada plugin.

Siguiendo estos pasos, tu aplicación mostrará efectivamente una lista única de plugins obtenidos de todos los sitios, proporcionando una interfaz limpia y fácil de usar para la selección.

Selecciona el campo que muestra la lista de plugins únicos de todos los sitios de la cuenta de empresa Kinsta.
Selecciona el campo que muestra la lista de plugins únicos de todos los sitios de la cuenta de empresa Kinsta.

Obtener sitios con un plugin específico

Hasta ahora, has podido recuperar plugins de tu cuenta de empresa Kinsta, pero quieres hacer un bucle por todos los sitios para recuperar sitios con un plugin concreto, almacenarlos en un estado y luego mostrarlos.

Para ello, crea dos estados: uno para almacenar los sitios (sites) y otro para indicar el estado de carga (isLoading).

const [sites, setSites] = useState([]);
const [isLoading, setIsLoading] = useState(false);

A continuación, crea una función fetchSites para filtrar cada sitio y comprobar si contiene el plugin seleccionado. Si lo contiene, se almacenan los detalles relevantes del sitio.

Esta función comienza estableciendo isLoading en true y borrando el array sites. A continuación, llama a getSitesWithPluginData para obtener todos los datos del sitio.

const fetchSites = async () => {
    setIsLoading(true);
    setSites([]);
    const sitesWithPluginData = await getSitesWithPluginData();

    // Filter out sites that don't have the plugin
    const sitesWithPluginDataFiltered = sitesWithPluginData
        .filter((site) => {
            const sitePlugins = site.plugins.wp_plugins.data;
            return sitePlugins.some((plugin) => {
                return plugin.name === pluginName;
            });
        })
        .map((site) => {
            const { env_id, name } = site;
            const { version, status, update, update_version } =
                site.plugins.wp_plugins.data.find(
                    (plugin) => plugin.name === pluginName
                );
            return {
                env_id,
                name,
                version,
                status,
                updateAvailable: update,
                updateVersion: update_version,
            };
        });
    setSites(sitesWithPluginDataFiltered);
    setIsLoading(false);
};

En la función sitesWithPluginDataFiltered:

  • El método .filter() aísla los sitios que contienen el plugin seleccionado.
  • A continuación, el método .map() extrae los datos necesarios de cada sitio.
  • Por último, los hooks setSites y setIsLoading actualizan el estado con los nuevos datos y el estado de carga.

A continuación, crea una función handleSubmit y añádela al botón Obtener sitios con este plugin del formulario para invocar la función cuando un usuario seleccione un plugin y envíe el formulario. Esta función evita la acción por defecto del formulario y llama a fetchSites:

const handleSubmit = (e) => {
    e.preventDefault();
    fetchSites();
};

De este modo, cuando un usuario selecciona un plugin concreto y pulsa el botón de envío, obtiene todos los sitios con ese plugin y los almacena en el estado sites.

Mostrar los sitios con el plugin seleccionado

Una vez almacenados con éxito los sitios relevantes en tu estado sites, el siguiente paso es mostrar estos datos en la interfaz de usuario de tu proyecto. El objetivo es presentar cada sitio como un elemento de la lista con detalles clave y un botón condicional para actualizar el plugin.

<ul>
    {sites.map((site) => (
        <li key={site.env_id}>
            <div className="info">
                <p>
                    <b>Site Name:</b> {site.name}
                </p>
                <p>
                    <b>Plugin Status:</b> {site.status}
                </p>
                <p>
                    <b>Plugin Version:</b> {site.version}
                </p>
            </div>
            <button>
                className={`sm-btn ${
                    site.updateAvailable !== 'available' ? 'disabled-btn' : ''
                }`}
                disabled={site.updateAvailable !== 'available'}
            >
                {site.updateAvailable === 'available'
                    ? `Update to v.${site.updateVersion}`
                    : 'Up to date'}
            </button>
        </li>
    ))}
</ul>

En el código anterior, se itera sobre la array sites utilizando el método .map(), creando una lista (<ul>) de sitios (<li> elementos). Cada elemento de la lista contiene detalles sobre el sitio y un botón para actualizar el plugin.

El botón de la Interfaz de Usuario cambia de estilo y función en función del estado de actualización del plugin: está activo para las actualizaciones disponibles, de lo contrario está desactivado y etiquetado como «Up to date» (Actualizado), controlado por CSS condicional y el atributo disabled (desactivado).

Además, para mejorar la experiencia del usuario, vamos a añadir un texto de carga de forma condicional utilizando el estado isLoading cuando se están obteniendo los sitios.

{isLoading && (
    <div className="loading">
        <p>Loading...</p>
    </div>
)}
Una lista de sitios que utilizan un determinado plugin de la cuenta de empresa de Kinsta con botones para actualizarlos individualmente o a la vez.
Una lista de sitios que utilizan un determinado plugin de la cuenta de empresa de Kinsta con botones para actualizarlos individualmente o a la vez.

Actualizar plugins con la API de Kinsta

Hasta ahora, hemos podido obtener sitios con detalles importantes y acceder a sus plugins. El objetivo de esta herramienta es facilitar la actualización de plugins en varios sitios utilizando la API de Kinsta. El proceso implica iniciar actualizaciones y seguir su progreso.

Activación de actualizaciones de plugins

Se proporciona un botón para cada sitio de la lista. Está diseñado para reflejar si hay una actualización disponible. Si hay una actualización disponible, al hacer clic en el botón se activa la función updatePlugin.

<button>
    className={`sm-btn ${
        site.updateAvailable !== 'available' ? 'disabled-btn' : ''
    }`}
    disabled={site.updateAvailable !== 'available'}
    onClick={() =>
        updatePlugin(site.env_id, site.updateVersion)
    }
>
    {site.updateAvailable === 'available'
        ? `Update to v.${site.updateVersion}`
        : 'Up to date'}
</button>

El manejador onClick llama a updatePlugin con el ID de entorno del sitio y la última versión del plugin (updateVersion). Esta función envía una solicitud PUT a la API de Kinsta para actualizar el plugin.

const updatePlugin = async (envId, pluginVersion) => {
    const resp = await fetch(`${KinstaAPIUrl}/sites/environments/${envId}/plugins`, {
        method: 'PUT',
        headers: {
            'Content-Type': 'application/json',
            Authorization: `Bearer ${process.env.REACT_APP_KINSTA_API_KEY}`,
        },
        body: JSON.stringify({
            name: pluginName,
            update_version: pluginVersion,
        }),
    });

    const data = await resp.json();
    // Further processing
};

Seguir el progreso de la actualización

Después de iniciar la actualización, tienes que controlar su progreso. La API Kinsta proporciona una respuesta como ésta al iniciar una actualización:

{
  "operation_id": "wp-plugin:update-54fb80af-576c-4fdc-ba4f-b596c83f15a1",
  "message": "Updating WordPress plugin in progress",
  "status": 202
}

operation_id realiza un seguimiento del estado de la actualización a través del endpoint de operaciones. Crea una función para hacer esta petición a la API, esperando el operation_id como argumento:

// Check plugin update status
const checkPluginUpdateStatus = async (operationId) => {
    const resp = await fetch(`${KinstaAPIUrl}/operations/${operationId}`, {
        method: 'GET',
        headers: {
            Authorization: `Bearer ${process.env.REACT_APP_KINSTA_API_KEY}`,
        },
    });
    const data = await resp.json();
    return data.status;
};

Dentro de updatePlugin, utiliza una sentencia if para comprobar si la solicitud de actualización inicial status es 202. Si es así, establece un intervalo para llamar a checkPluginUpdateStatus cada cinco segundos (5000 milisegundos).

El intervalo comprueba repetidamente el estado de la actualización y, si tiene éxito, borra el intervalo y llama a fetchSites para actualizar la lista de sitios. Si se produce un error durante estas comprobaciones, se registra en la consola.

if (data.status === 202) {
    const interval = setInterval(() => {
        checkPluginUpdateStatus(data.operation_id)
            .then((status) => {
                console.log(status);
                if (status === 200) {
                    clearInterval(interval);
                    fetchSites();
                }
            })
            .catch((error) => {
                // Handle any errors that occur during the promise resolution
                console.error('Error:', error);
            });
    }, 5000);
}

Respuesta del usuario durante el funcionamiento

En este punto todo funciona bien, pero es bueno hacer que el usuario sea consciente del progreso de la operación en lugar de dejar que lo adivine. Puedes hacerlo mostrando una notificación que aparezca cuando la operación esté en curso y se borre cuando haya terminado. Crea un estado showStatusBar para controlar esto:

const [showStatusBar, setShowStatusBar] = useState(false);

Cuando showStatusBar es true, aparece una barra de estado en la parte superior de la pantalla, indicando que hay una actualización en curso. Su estilo es fijo en la parte superior de la pantalla.

{showStatusBar && (
    <div className="status-bar">
        <p>Updating WordPress plugin in progress...</p>
    </div>
)}

Ahora puedes ajustar la sentencia if en la función updatePlugin para establecer showStatusBar en true o false en función del estado de actualización:

if (data.status === 202) {
    setShowStatusBar(true);
    const interval = setInterval(() => {
        checkPluginUpdateStatus(data.operation_id)
            .then((status) => {
                console.log(status);
                if (status === 200) {
                    setShowStatusBar(false);
                    clearInterval(interval);
                    fetchSites();
                }
            })
            .catch((error) => {
                // Handle any errors that occur during the promise resolution
                console.error('Error:', error);
            });
    }, 5000);
}

Este enfoque garantiza que los usuarios estén informados sobre el estado de las actualizaciones de los plugins, mejorando la usabilidad general de la herramienta.

Actualizar plugins en varios sitios con la API de Kinsta

La principal característica de esta herramienta es la posibilidad de actualizar un plugin concreto con un solo clic en varios sitios dentro de tu cuenta Kinsta. Esto es similar a la funcionalidad implementada para actualizar plugins en un solo sitio.

El proceso implica un bucle a través del estado sites, que contiene los sitios con el plugin concreto que necesita una actualización. Para cada sitio que requiera una actualización, se realiza una solicitud a la API para actualizar el plugin y, posteriormente, se realiza un seguimiento del estado de la operación:

// Update all plugins
const updateAllPlugins = async () => {
    sites.map(async (site) => {
        if (site.updateAvailable === 'available') {
            const environmentId = site.env_id;
            const resp = await fetch(
                `${KinstaAPIUrl}/sites/environments/${environmentId}/plugins`,
                {
                    method: 'PUT',
                    headers: {
                        'Content-Type': 'application/json',
                        Authorization: `Bearer ${process.env.REACT_APP_KINSTA_API_KEY}`,
                    },
                    body: JSON.stringify({
                        name: pluginName,
                        update_version: site.updateVersion,
                    }),
                }
            );
            const data = await resp.json();
            if (data.status === 202) {
                setShowStatusBar(true);
                const interval = setInterval(() => {
                    checkPluginUpdateStatus(data.operation_id)
                        .then((status) => {
                            console.log(status);
                            if (status === 200) {
                                setShowStatusBar(false);
                                clearInterval(interval);
                                fetchSites();
                            }
                        })
                        .catch((error) => {
                            // Handle any errors that occur during the promise resolution
                            console.error('Error:', error);
                        });
                }, 5000);
            }
        }
    });
};

Esta función está conectada a un botón Actualizar Todo. Para mejorar la experiencia del usuario, el botón muestra el número de versión al que se están actualizando los plugins:

<button> className="sm-btn" onClick={updateAllPlugins}>
    Update all sites to v.
    {
        sites.find((site) => site.updateVersion !== null)
            ?.updateVersion
    }
</button>

Además, renderizamos condicionalmente este botón para que sólo aparezca cuando más de un sitio requiera una actualización del plugin. Si todos los sitios están actualizados, en su lugar se muestra un mensaje:

<div className="list-title">
    <h3>Sites with {pluginName} plugin</h3>
    {sites.filter((site) => site.updateAvailable === 'available')
        .length > 1 && (
        <button className="sm-btn" onClick={updateAllPlugins}>
            Update all sites to v.
            {
                sites.find((site) => site.updateVersion !== null)
                    ?.updateVersion
            }
        </button>
    )}
    {sites.every((site) => site.updateAvailable !== 'available') && (
        <p>All sites are up to date</p>
    )}
</div>

Con estas implementaciones, ahora puedes actualizar plugins sin esfuerzo en múltiples sitios de tu cuenta Kinsta, mejorando la eficiencia y asegurándote de que todos tus sitios están actualizados con las últimas versiones de plugins.

Despliega gratis tu sitio estático React en Kinsta

Estamos utilizando el alojamiento de sitios estáticos de Kinsta para mostrar la aplicación. En la práctica, podrías ejecutar esta aplicación React desde tu propia red o desplegarla sólo después de añadir un medio de autenticación a esta herramienta por seguridad.

Puedes alojar tus aplicaciones React creadas con create-react-app como un sitio estático utilizando nuestro alojamiento de sitios estáticos de forma gratuita enviando tu código a un proveedor Git preferido (Bitbucket, GitHub o GitLab).

Una vez que tu repositorio esté listo, sigue estos pasos para desplegar tu sitio estático en Kinsta:

  1. Inicia sesión o crea una cuenta para ver tu panel MyKinsta.
  2. Autoriza a Kinsta con tu proveedor de Git.
  3. Haz clic en Sitios Estáticos en la barra lateral izquierda, y luego en Añadir sitio.
  4. Selecciona el repositorio y la rama desde la que deseas desplegar.
  5. Asigna un nombre único a tu sitio.
  6. Añade la configuración de construcción en el siguiente formato:
    • Comando de construcción: npm run build
    • Versión de Node: 18.16.0
    • Directorio de publicación: build
  7. Por último, haz clic en Crear sitio.

¡Y ya está! En pocos segundos tendrás un sitio desplegado. Se proporciona un enlace para acceder a la versión desplegada de tu sitio. Si lo deseas, puedes añadir más adelante tu dominio personalizado y tu certificado SSL.

Como alternativa al alojamiento de sitios estáticos, puedes desplegar tu sitio estático con el alojamiento de aplicaciones de Kinsta, que proporciona una mayor flexibilidad de alojamiento, una gama más amplia de ventajas y acceso a funciones más robustas. Por ejemplo, escalabilidad, despliegue personalizado mediante un Dockerfile, y analíticas completas que abarcan datos históricos y en tiempo real.

Resumen

La API de Kinsta abre posibilidades más allá de lo que hemos comentado. Una aplicación interesante podría ser la creación de un Slackbot que te notifique en Slack cada vez que algún plugin esté desactualizado. Esta integración puede agilizar significativamente tu flujo de trabajo, manteniéndote informado y proactivo.

También puedes desarrollar una herramienta similar, como se explica en esta guía, para actualizar tus temas, ya que la API de Kinsta ya dispone de endpoints para ello.

El equipo de Kinsta trabaja constantemente para añadir las próximas funciones siguiendo de cerca y escuchando los comentarios, como comparte Kristof Siket, jefe del equipo de desarrollo de la API de Kinsta:

Los comentarios de los usuarios impulsan la priorización de las funciones expuestas. El plan actual no cubre completamente la página de Herramientas; en su lugar, las características se basan en las peticiones de los usuarios y en los comentarios recogidos. Si crees que una herramienta o endpoint específico debería incluirse en la API Kinsta, no dudes en enviar tus comentarios.

¿Cómo utilizas actualmente la API Kinsta? ¿Qué funciones o mejoras te gustaría ver en futuras actualizaciones?

Joel Olawanle Kinsta

Joel es un desarrollador Frontend que trabaja en Kinsta como Editor Técnico. Es un formador apasionado enamorado del código abierto y ha escrito más de 200 artículos técnicos, principalmente sobre JavaScript y sus frameworks.