I plugin svolgono un ruolo fondamentale nella personalizzazione e nel miglioramento dei siti WordPress. Vengono utilizzati per aggiungere funzionalità come moduli di contatto, e-commerce e analisi ai siti senza dover ricorrere al codice.

Come WordPress, che viene aggiornato regolarmente, anche i plugin ricevono aggiornamenti regolari per aggiungere nuove funzionalità, correggere falle di sicurezza, aumentare la compatibilità e altro ancora. Ecco perché Kinsta ha incluso la gestione dei plugin e dei temi tra gli strumenti disponibili all’interno di MyKinsta per ciascuno dei vostri siti.

Tuttavia, aggiornare i plugin per molti siti può essere scoraggiante per i clienti più impegnati come le agenzie. Questo articolo mostra una soluzione che utilizza l’API di Kinsta per gestire simultaneamente i plugin su più siti.

Cosa costruiremo

Questa guida si concentra sulla costruzione di una soluzione avanzata utilizzando l’API di Kinsta, che ora offre endpoint per il recupero e l’aggiornamento dei plugin.

In questa guida creeremo un’applicazione React personalizzata che recupererà tutti i plugin da un account aziendale Kinsta. Questo strumento permette di identificare e aggiornare un plugin specifico su più siti, semplificando notevolmente l’intero processo di aggiornamento.

Strumento costruito con React e Kinsta API per aggiornare in blocco i plugin di WordPress su più siti
Strumento costruito con React e Kinsta API per aggiornare in blocco i plugin di WordPress su più siti.

Prerequisiti dell’applicazione

Per seguire questo progetto, è necessario avere i seguenti requisiti:

L’API di Kinsta

L’API di Kinsta è un potente strumento che permette di interagire in modo programmatico con i servizi Kinsta come i siti WordPress ospitati. Può aiutare ad automatizzare diverse attività legate alla gestione di WordPress, tra cui la creazione di un sito, il recupero di informazioni sul sito, lo stato di un sito, la consultazione e il ripristino dei backup e altro ancora.

Per utilizzare l’API di Kinsta, è necessario avere un account con almeno un sito, un’applicazione o un database WordPress in MyKinsta. Bisogna inoltre generare una chiave API per autenticarsi e accedere all’account.

Per generare una chiave API:

  1. Andiamo alla dashboard di MyKinsta.
  2. Andiamo alla pagina delle chiavi API (Nome > Impostazioni dell’azienda > Chiavi API).
  3. Clicchiamo su Crea chiave API.
  4. Scegliamo una scadenza o impostiamo una data di inizio personalizzata e un numero di ore di scadenza della chiave.
  5. Assegniamo alla chiave un nome univoco.
  6. Clicchiamo su Genera.

Dopo aver creato una chiave API, copiamola e conserviamola in un luogo sicuro (noi consigliamo di utilizzare un gestore di password ). Possiamo generare più chiavi API, che saranno elencate nella pagina delle chiavi API. Per revocare una chiave API, basta cliccare sul pulsante Revoca.

Configurare l’ambiente di sviluppo React

React è una popolare libreria JavaScript per la creazione di interfacce utente. Permette agli sviluppatori di creare componenti dichiarativi che rappresentano diverse parti dell’interfaccia utente. Questi componenti sono definiti utilizzando la sintassi JSX, una combinazione di JavaScript e HTML.

Per iniziare, seguiamo questi passaggi:

  1. Navighiamo nella cartella in cui desideriamo creare il progetto e usiamo create-react-app per creare un progetto React:
    npx create-react-app <project-name>

    Cambiamo <project-name> con il nome che preferiamo per il progetto.

  2. Una volta completata l’operazione, navighiamo nella cartella del progetto e avviamo il server di sviluppo:
    cd <project-name>
    npm run start

    L’applicazione React si apre nel browser web predefinito su http://localhost:3000.

La creazione di un progetto React tramite create-react-app crea una struttura di cartelle. La cartella fondamentale è src, dove avviene lo sviluppo. I file chiave in questa cartella sono:

  • App.js: è il componente principale, che esegue il rendering di tutti gli altri nell’applicazione React. È qui che verrà aggiunto tutto il codice per questo strumento.
  • index.js: è il punto di ingresso, viene caricato per primo ed è responsabile del rendering di App.js.
  • index.css: questo file definisce lo stile e il layout generale dell’applicazione. Tutti gli stili saranno aggiunti qui.

Creazione e stile dell’interfaccia utente

Concentriamoci sulla creazione e sullo stile dell’interfaccia di un’applicazione di base contenuta nel file App.js senza coinvolgere il routing. La nostra interfaccia utente principale è un modulo con un campo select per elencare i plugin unici dei nostri siti Kinsta e un pulsante submit per recuperare i siti con il plugin selezionato.

Interfaccia utente per lo strumento di gestione dei plugin per accedere a un elenco di plugin e caricare i siti
Interfaccia utente per lo strumento di gestione dei plugin per accedere a un elenco di plugin e caricare i siti.

Inoltre, una sezione mostra i dettagli del sito come il nome, lo stato del plugin e la versione. Include un pulsante per aggiornare ogni sito se necessario e un pulsante generale per aggiornare in blocco tutti i siti che richiedono l’aggiornamento del plugin.

Nel file App.js, aggiungiamo il seguente codice:

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;

Per creare lo stile di questo progetto, visitiamo il file CSS nel repository GitHub completo di Kinsta e copiamo il suo codice nel file index.css.

Interagire con l’API di Kinsta

L’API di Kinsta offre una serie di endpoint essenziali per accedere a vari parametri necessari per interagire con il plugin di un sito. Ad esempio, se volessimo recuperare o aggiornare un plugin, dovremmo prima acquisire l’ID ambiente del sito.

Ottenere questo ID ambiente è un processo sequenziale. Inizialmente, è necessario determinare l’ID del sito. Per ottenere l’ID del sito, è a sua volta necessario disporre dell’ID dell’azienda Kinsta. L’ID dell’azienda è disponibile nel cruscotto MyKinsta (Impostazioni dell’azienda > Dettagli di fatturazione) ed è un’informazione sensibile che non va condivisa con nessuno, come la chiave API.

È possibile memorizzarle in modo sicuro come variabili d’ambiente nell’applicazione React creando un file .env nella cartella principale del progetto. In questo file, aggiungiamo il seguente valore corretto:

REACT_APP_KINSTA_COMPANY_ID = 'YOUR_COMPANY_ID' 
REACT_APP_KINSTA_API_KEY = 'YOUR_API_KEY'

Per accedere a queste variabili d’ambiente all’interno del progetto, possiamo utilizzare la sintassi process.env.THE_VARIABLE. Ad esempio, per accedere a REACT_APP_KINSTA_COMPANY_ID, dovremo usare process.env.REACT_APP_KINSTA_COMPANY_ID.

Aggiungere il file .env al file .gitignore è importante per evitare che venga inviato a GitHub. In questo modo le informazioni sensibili rimarranno private e sicure.

Recuperare tutti i siti e i plugin utilizzando l’API di Kinsta

Per recuperare i dati dei plugin per tutti i siti gestiti dall’account Kinsta dell’azienda, possiamo utilizzare l’API Kinsta eseguendo tre richieste API. Ecco una spiegazione semplificata:

Iniziamo memorizzando l’URL dell’API Kinsta in una variabile per poterla consultare facilmente.

const KinstaAPIUrl = 'https://api.kinsta.com/v2';
  1. Recuperare l’elenco dei siti aziendali: dobbiamo ottenere un elenco di tutti i siti WordPress associati all’azienda. A tal fine, costruiamo una query utilizzando l’ID dell’azienda, effettuiamo una richiesta GET con l’autorizzazione appropriata, elaboriamo la risposta in formato JSON ed estraiamo i dettagli del sito dalla risposta.
    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. Recuperare l’ID dell’ambiente del sito: il passaggio precedente restituisce un array di siti WordPress. Per ogni sito, eseguiamo un ciclo e facciamo un’altra richiesta GET per recuperare gli ambienti associati.
    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. Recuperare l’elenco dei plugin del sito WordPress: dopo aver ottenuto l’ID del sito, il nome e l’ambiente, ora possiamo utilizzare l’ID dell’ambiente per recuperare un elenco di tutti i plugin di ogni sito. Per prima cosa dobbiamo risolvere le promesse del passo precedente e poi effettuare le richieste GET per i plugin:
    // 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. Consolidare il processo: per semplificare il processo, possiamo incapsulare queste richieste API in un’unica funzione asincrona getSitesWithPluginData, che può essere riutilizzata. Questa funzione eseguirà i passaggi descritti in precedenza e restituirà un array contenente le informazioni essenziali su ogni sito, tra cui l’ID dell’ambiente, il nome del sito e un array di plugin.
    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;
    };

Recuperare i plugin unici di tutti i siti

Nell’applicazione, vogliamo visualizzare l’elenco dei plugin di tutti i siti in un menu a tendina select. Per ottenere questo risultato, la funzione getSitesWithPluginData recupera l’ID dell’ambiente, il nome e i plugin di ogni sito. Questi dati costituiscono la base per estrarre un elenco di plugin.

Definiamo una nuova funzione, fetchAllSitesPlugins, che chiama getSitesWithPluginData ed elabora il suo output per ottenere un elenco di tutti i plugin:

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

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

   // …
};

Questo codice itera i dati di ogni sito e compila un elenco di plugin. Per garantire che ogni plugin sia elencato una sola volta, utilizza l’oggetto JavaScript Set, che memorizza valori unici:

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

Il metodo .flat() appiattisce la struttura dell’array e .map() esegue un loop per estrarre solo i nomi dei plugin. L’oggetto Set filtra i duplicati.

Per caricare e visualizzare questi dati nell’applicazione React, utilizza gli hook useState() e 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
    //...
};

L’hook useEffect() assicura che i dati vengano recuperati e impostati quando il componente viene montato. L’hook useState() gestisce l’elenco dei plugin unici.

Infine, visualizza questi plugin in un campo select. Se i plugin sono ancora in fase di caricamento, mostra un messaggio placeholder:

<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>

In questo codice:

  • L’elemento select è collegato a una variabile di stato pluginName per memorizzare il valore selezionato.
  • Il gestore onChange aggiorna questo stato ogni volta che viene selezionato un nuovo plugin.
  • La funzione plugins.map() crea dinamicamente gli elementi di opzione per ogni plugin.

Seguendo questi passaggi, l’applicazione mostrerà effettivamente un elenco unico di plugin recuperati da tutti i siti, fornendo un’interfaccia pulita e facile da usare per la selezione.

Campo di selezione che mostra l'elenco dei plugin unici di tutti i siti nell'account Kinsta dell'azienda.
Campo di selezione che mostra l’elenco dei plugin unici di tutti i siti dell’account Kinsta dell’azienda.

Recuperare i siti con un plugin specifico

Finora siamo riusciti a recuperare i plugin dall’account Kinsta dell’azienda, ma vogliamo scorrere tutti i siti per recuperare i siti con un determinato plugin, memorizzarli in uno stato e quindi visualizzarli.

Per farlo, creiamo due stati: uno per memorizzare i siti (sites) e un altro per indicare lo stato di caricamento (isLoading).

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

Quindi, creiamo una funzione fetchSites per filtrare ogni sito e verificare se contiene il plugin selezionato. In caso affermativo, i dettagli relativi al sito vengono memorizzati

Questa funzione inizia impostando isLoading su true e cancellando l’array sites. Poi chiama getSitesWithPluginData per recuperare tutti i dati del sito.

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);
};

Nella funzione sitesWithPluginDataFiltered:

  • Il metodo .filter() isola i siti che contengono il plugin selezionato.
  • Il metodo .map() estrae quindi i dettagli necessari da ogni sito.
  • Infine, i ganci setSites e setIsLoading aggiornano lo stato con i nuovi dati e lo stato di caricamento.

Successivamente, creiamo una funzione handleSubmit e aggiungiamola al pulsante Fetch sites with this plugin del modulo per richiamare la funzione quando l’utente seleziona un plugin e invia il modulo. Questa funzione impedisce l’azione predefinita del modulo e richiama fetchSites:

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

In questo modo, quando l’utente seleziona un particolare plugin e clicca sul pulsante di invio, recupera tutti i siti con quel plugin e li memorizza nello stato sites.

Visualizzare i siti con il plugin selezionato

Dopo aver memorizzato con successo i siti rilevanti nello stato sites, vogliamo visualizzare questi dati nell’interfaccia utente del progetto. L’obiettivo è quello di presentare ogni sito come un elenco con i dettagli principali e un pulsante condizionale per l’aggiornamento del 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>

Nel codice qui sopra, l’array sites viene iterato con il metodo .map(), creando un elenco (<ul>) di siti (elementi<li> ). Ogni elemento dell’elenco contiene dettagli sul sito e un pulsante per l’aggiornamento del plugin.

Il pulsante nell’interfaccia utente cambia stile e funzione in base allo stato di aggiornamento del plugin: è attivo per gli aggiornamenti disponibili, altrimenti è disattivato e riporta la dicitura “Updated”, controllata da CSS condizionali e dall’attributo disabled.

Inoltre, per migliorare l’esperienza dell’utente, aggiungiamo un testo di caricamento condizionato dallo stato di isLoading quando i siti vengono recuperati.

{isLoading && (
    <div className="loading">
        <p>Loading...</p>
    </div>
)}
Un elenco di siti che utilizzano un determinato plugin dall'account Kinsta dell'azienda con i pulsanti per aggiornarli singolarmente o in una volta sola
Un elenco di siti che utilizzano un determinato plugin dall’account Kinsta dell’azienda con i pulsanti per aggiornarli singolarmente o in una volta sola.

Aggiornare i plugin con l’API di Kinsta

Finora siamo riusciti a recuperare siti con dettagli importanti e ad accedere ai loro plugin. L’obiettivo di questo strumento è quello di facilitare l’aggiornamento dei plugin su più siti utilizzando l’API di Kinsta. Il processo prevede l’avvio degli aggiornamenti e il monitoraggio del loro avanzamento.

Attivare gli aggiornamenti dei plugin

Per ogni sito elencato viene fornito un pulsante. Il suo stile riflette la disponibilità di un aggiornamento. Se è disponibile un aggiornamento, cliccando sul pulsante si attiva la funzione 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>

Il gestore onClick chiama updatePlugin con l’ID ambiente del sito e l’ultima versione del plugin (updateVersion). Questa funzione invia una richiesta PUT all’API di Kinsta per aggiornare il 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
};

Seguire l’avanzamento dell’aggiornamento

Dopo aver avviato l’aggiornamento, è necessario monitorarne l’avanzamento. L’API di Kinsta fornisce una risposta come questa quando si avvia un aggiornamento:

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

Il sito operation_id tiene traccia dello stato dell’aggiornamento tramite l’endpoint delle operazioni. Creiamo una funzione che effettui questa richiesta API e che abbia come argomento operation_id:

// 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;
};

All’interno di updatePlugin, utilizziamo un’istruzione if per verificare se le richieste di aggiornamento iniziali status sono 202. In caso affermativo, impostiamo un intervallo per chiamare checkPluginUpdateStatus ogni cinque secondi (5000 millisecondi).

L’intervallo controlla ripetutamente lo stato di aggiornamento e, in caso di successo, cancella l’intervallo e chiama fetchSites per aggiornare l’elenco dei siti. Se durante questi controlli si verifica un errore, questo viene registrato nella console.

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);
}

Feedback dell’utente durante il funzionamento

A questo punto tutto funziona bene, ma è bene che l’utente sia al corrente dell’andamento dell’operazione invece di lasciarlo indovinare. Possiamo farlo mostrando una notifica che appare quando l’operazione è in corso e che si cancella quando l’operazione è terminata. Creiamo uno stato showStatusBar per controllare questo aspetto:

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

Quando showStatusBar è true, nella parte superiore dello schermo appare una barra di stato che indica che è in corso un aggiornamento. Questa barra è stata progettata in modo da essere fissa nella parte superiore dello schermo.

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

Ora possiamo modificare l’istruzione if nella funzione updatePlugin per impostare showStatusBar su true o false in base allo stato di aggiornamento:

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);
}

Questo approccio garantisce che gli utenti siano informati sullo stato degli aggiornamenti dei plugin, migliorando l’usabilità complessiva dello strumento.

Aggiornamento dei plugin su più siti con Kinsta API

La caratteristica principale di questo strumento è la possibilità di aggiornare un determinato plugin con un solo clic su più siti all’interno dell’account Kinsta. Si tratta di una funzionalità simile a quella implementata per l’aggiornamento dei plugin su un singolo sito.

Il processo prevede il passaggio attraverso lo stato sites, che contiene i siti con il particolare plugin da aggiornare. Per ogni sito che necessita di un aggiornamento, viene effettuata una richiesta API per aggiornare il plugin e successivamente viene monitorato lo stato dell’operazione:

// 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);
            }
        }
    });
};

Questa funzione è collegata a un pulsante Aggiorna tutto. Per migliorare l’esperienza dell’utente, il pulsante mostra il numero di versione a cui il plugin viene aggiornato:

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

Inoltre, rendiamo condizionale questo pulsante in modo che appaia solo quando più di un sito richiede l’aggiornamento del plugin. Se tutti i siti sono aggiornati, viene visualizzato un messaggio:

<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>

Grazie a queste implementazioni, ora possiamo aggiornare senza problemi i plugin su più siti dell’account Kinsta, migliorando l’efficienza e garantendo che tutti i siti siano aggiornati con le ultime versioni dei plugin.

Distribuire il sito statico React su Kinsta gratuitamente

Per la dimostrazione dell’applicazione utilizzeremo l’Hosting di Siti Statici di Kinsta. In pratica, potremmo eseguire questa applicazione React dalla nostra rete o distribuirla solo dopo aver aggiunto un mezzo di autenticazione a questo strumento per la sicurezza.

È possibile ospitare le applicazioni React create con create-react-app come sito statico utilizzando l’hosting statico gratuito di Kinsta e inviando il codice al provider Git di nostra preferenza (Bitbucket, GitHub o GitLab).

Quando il repo sarà pronto, seguiamo questi passaggi per distribuire il sito statico su Kinsta:

  1. Accediamo o creiamo un account per visualizzare la dashboard MyKinsta.
  2. Autorizziamo Kinsta con il provider Git.
  3. Clicchiamo su Siti statici nella barra laterale di sinistra e poi su Aggiungi sito.
  4. Selezioniamo il repository e il branch da cui desideriamo effettuare il deploy.
  5. Assegniamo un nome unico al sito.
  6. Aggiungiamo le impostazioni di build nel seguente formato:
    • Comando di build: npm run build
    • Versione Node: 18.16.0
    • Directory di pubblicazione: build
  7. Infine, clicchiamo su Crea sito.

E il gioco è fatto! In pochi secondi avremo un sito distribuito. Viene fornito un link per accedere alla versione distribuita del sito. In seguito potremo aggiungere un dominio personale e un certificato SSL, a seconda delle nostre esigenze.

In alternativa all’Hosting di Siti Statici, possiamo distribuire il sito statico con l’Hosting di Applicazioni di Kinsta, che offre una maggiore flessibilità di hosting, una gamma più ampia di vantaggi e l’accesso a funzioni più robuste. Ad esempio, scalabilità, distribuzione personalizzata tramite un file Docker e l’analisi completa dei dati storici e in tempo reale.

Riepilogo

L’API di Kinsta apre possibilità che vanno al di là di quanto abbiamo discusso. Un’applicazione interessante potrebbe essere la creazione di uno Slackbot che invii una notifica su Slack ogni volta che un plugin è obsoleto. Questa integrazione può snellire notevolmente il vostro flusso di lavoro, mantenendovi informati e proattivi.

Potrete anche sviluppare uno strumento simile, come spiegato in questa guida, per aggiornare i vostri temi, dato che l’API di Kinsta ha già degli endpoint per farlo.

Il team di Kinsta lavora costantemente all’aggiunta di nuove funzionalità seguendo e ascoltando attentamente i feedback, come ci spiega Kristof Siket, Development Team Lead di Kinsta API:

Il feedback degli utenti guida la definizione delle priorità di esposizione delle funzionalità. Il piano attuale non copre completamente la pagina degli strumenti; le funzionalità si basano invece sulle richieste degli utenti e sui feedback raccolti. Se ritienete che uno strumento o un endpoint specifico debba essere incluso nell’API di Kinsta, sentitevi liberi di inviare il vostro feedback.

Come utilizzate attualmente l’API di Kinsta? Quali funzioni o miglioramenti vorreste vedere nei prossimi aggiornamenti?

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.