Non è necessario dover gestire tutti gli 800 milioni di siti WordPress presenti sul web prima di cercare un modo per lanciare nuovi siti in modo efficiente.

Clonare una configurazione WordPress esistente è un modo per essere rapidamente operativi e i clienti del servizio di Hosting WordPress gestito di Kinsta sanno che è facile farlo all’interno della nostra dashboard MyKinsta.

Inoltre, è possibile clonare siti WordPress in scala utilizzando le tecnologie di sviluppo delle applicazioni che preferite e le API di Kinsta. In questo tutorial utilizzeremo l’API e React, una delle tante librerie JavaScript più diffuse, per mostrarvi come funziona.

Cosa costruiremo

Ecco lo scenario: siete un’agenzia di sviluppo WordPress con uno o più siti che possono essere utilizzati come modelli di partenza. L’applicazione React per clonare siti WordPress che stiamo costruendo ha questo aspetto:

Applicazione React per clonare siti con Kinsta API
Applicazione React per clonare siti con Kinsta API.

Prerequisiti

Per seguire questo tutorial, è necessario avere una conoscenza di base di HTML, CSS e JavaScript e una certa familiarità con React. Inoltre, dovrete avere installato sul computer Node.js e npm (il gestore di pacchetti Node) o yarn. L’obiettivo di questo progetto è la creazione di un’applicazione per la clonazione di WordPress utilizzando React e l’API Kinsta piuttosto che i dettagli della creazione e dello stile dell’interfaccia utente.

Impostazione dell’ambiente di sviluppo

Potete creare un’applicazione React da zero e sviluppare la vostra interfaccia, oppure usare il template di partenza Git di cui sopra seguendo questi passaggi:

  1. Visitate il repository GitHub di questo progetto.
  2. Selezionate Use this template > Create a new repository per copiare il codice di partenza in un repository all’interno del vostro account GitHub. (Selezionate la casella per includere tutti i branch.)
  3. Estraete il repository sul vostro computer locale e passate al branch starter-files usando il comando: git checkout starter-files
  1. Installate le dipendenze necessarie eseguendo il comando npm install

Una volta completata l’installazione, potete lanciare il progetto sul vostro computer locale con npm run start. In questo modo si apre il progetto all’indirizzo http://localhost:3000/.

Capire i file del progetto

La cartella src è il cuore di un’applicazione React, poiché contiene il JavaScript necessario a webpack. Nella cartella c’è App.js, dove sono configurati i due percorsi di questo progetto.

All’interno della cartella src ci sono le sottocartelle components e pages. La cartella components contiene componenti riutilizzabili, come Header.jsx e Footer.jsx, utilizzati nelle pagine Home.jsx e Operations.jsx .

Il vostro obiettivo qui è implementare la logica in Home.jsx e Operations.jsx, poiché lo stile e il routing si trovano nei nostri file di partenza su GitHub.

Home.jsx ha un modulo con due campi: il nome del sito che state creando e un campo di selezione che elenca i siti WordPress presenti nel vostro account MyKinsta (questo elenco viene recuperato tramite l’API di Kinsta).

Quando il pulsante di invio del modulo (Clone site) viene cliccato, viene restituito un oggetto che contiene la proprietà operation_id. L’ID e il nome visualizzato saranno passati come parametri di percorso a Operations.jsx, dove viene riportato lo stato dell’operazione di clonazione. L’interfaccia includerà anche dei link per accedere al login dell’area di amministrazione di WordPress e alla home page del sito.

Pagina delle operazioni che mostra i link all'area di amministrazione di WP e al sito
Pagina delle operazioni che mostra i link all’area di amministrazione di WP e al sito.

Utilizzare l’API di Kinsta per clonare un sito WordPress

All’interno di Home.jsx, verranno effettuate tre richieste API all’API di Kinsta. La prima richiesta è quella di ottenere un elenco di siti sul vostro account Kinsta. Questo verrà memorizzato in uno stato e poi iterato nel campo select. Questa richiesta verrà effettuata subito dopo il rendering della pagina utilizzando l’hook useEffect.

La seconda e la terza richiesta vengono effettuate una volta cliccato il pulsante Clone site. La seconda richiesta ottiene l’ID dell’ambiente del sito che si desidera clonare. La terza richiesta utilizza l’ID dell’ambiente e il nome visualizzato del sito per avviare la clonazione del sito.

Interagire con l’API di Kinsta in React

In questa esercitazione interagiamo con due endpoint dell’API di Kinsta:

  • /sites: Questo può restituire un elenco di tutti i siti, richiedere l’ID di un ambiente del sito e infine clonare un sito esistente.
  • /operations: Viene utilizzato per ottenere lo stato dell’operazione. Ad esempio, quando l’operazione di clonazione del sito è in corso, possiamo utilizzare questo endpoint per monitorare programmaticamente lo stato dell’operazione e determinare quando è terminata.

Per interagire con l’API di Kinsta, avrete bisogno del vostro ID azienda (che si trova in MyKinsta alla voce Azienda > Dettagli di fatturazione > ID azienda) e di una chiave API. Ecco come creare una chiave API Kinsta.

Una volta ottenute queste credenziali, è meglio memorizzarle in modo sicuro come variabili d’ambiente nella vostra applicazione React. Per impostare le variabili d’ambiente, create un file .env nella cartella principale del progetto. All’interno di questo file, aggiungete le seguenti righe:

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, potete utilizzare la sintassi process.env.THE_VARIABLE. Ad esempio, per accedere a REACT_APP_KINSTA_COMPANY_ID, dovete usare process.env.REACT_APP_KINSTA_COMPANY_ID.

Clonare un sito esistente con Kinsta API

Iniziamo recuperando l’elenco di tutti i siti quando Home.jsx viene renderizzato utilizzando l’hook useEffect e memorizzandoli in uno stato. A tal fine, importiamo gli hook useEffect e useState e creiamo uno stato per memorizzare l’array di siti che verranno recuperati:

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

Quindi, utilizziamo l’hook useEffect per interrogare l’API di Kinsta utilizzando l’API JavaScript Fetch. Per prima cosa, creiamo due variabili costanti per memorizzare gli header e l’URL dell’API Kinsta. Questo per evitare ripetizioni dato che invieremo più di una richiesta all’API di Kinsta in questa pagina:

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

Nel codice qui sopra, l’hook useMemo memorizza l’oggetto headers in modo che non debba essere rivalutato a ogni rendering poiché il suo valore è costante. Ora possiamo creare la richiesta 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]);

Nel codice precedente, viene creata una funzione asincrona fetchAllSites. All’interno di questa funzione, definiamo innanzitutto il parametro query (l’ID dell’azienda) recuperato dal file .env. Poi facciamo una richiesta GET all’endpoint /sites dell’API Kinsta utilizzando il parametro query. La risposta viene memorizzata nello stato sites creato in precedenza. Infine, chiamiamo fetchAllSites per avviare il processo di recupero.

Ora incorporiamo i valori memorizzati nello stato sites eseguendo un loop per popolare il campo select. Il nome visualizzato verrà mostrato all’utente, mentre l’ID del sito verrà utilizzato come valore dell’opzione. In questo modo, quando il modulo viene inviato, l’ID del sito selezionato può essere utilizzato per ottenere i dettagli dell’ambiente:

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

Procediamo a gestire l’invio del modulo e a recuperare i valori dal modulo. Per farlo, dobbiamo creare delle variabili di stato per ogni campo di input:

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

Quindi, leghiamo i campi del modulo ai rispettivi valori di stato aggiungendo gli attributi value e onChange a ogni elemento di input. Ecco come apparirà il modulo:

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

Nel codice precedente, ogni elemento di input ha l’attributo value impostato sulla variabile di stato corrispondente e l’attributo onChange viene utilizzato per aggiornare il valore dello stato quando l’utente interagisce con i campi di input.

Per gestire l’invio del modulo, colleghiamo un metodo onSubmit all’elemento del modulo. Ad esempio:

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

Definiamo il metodo handleSubmission che prevede due richieste API all’API di Kinsta. La prima richiesta recupera l’ID dell’ambiente del sito da clonare e la seconda esegue l’operazione di clonazione.

Iniziamo con il recuperare l’ID dell’ambiente. All’interno del metodo handleSubmission, creiamo una funzione asincrona per gestire questa richiesta. La funzione invierà una richiesta GET all’endpoint /sites, aggiungendo l’ID del sito selezionato, seguito dall’endpoint /environments:

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

Qui sopra, fetchEnvironmentId è una funzione asincrona che invia una richiesta GET all’API di Kinsta. Recupera gli ambienti del sito selezionato ed estrae l’ID dell’ambiente dalla risposta. L’ID dell’ambiente viene memorizzato nella variabile envId e poi restituito. Quando chiamiamo la funzione, assegniamo il suo valore di ritorno alla variabile envId.

A questo punto, possiamo clonare un sito esistente con l’API di Kinsta perché disponiamo delle informazioni essenziali sul sito di origine: ID azienda, nome visualizzato e ID ambiente.

All’interno del metodo handleSubmission, creiamo una funzione chiamata cloneExistingSite per gestire questa richiesta API. Questa richiesta sarà indirizzata all’endpoint /sites/clone. A differenza delle richieste precedenti, le intestazioni di questa richiesta sono diverse perché dobbiamo specificare Content-Type come application/json. Inoltre, si tratta di una richiesta POST, quindi dobbiamo includere un corpo di richiesta contenente il payload che vogliamo inviare all’API. Ecco come sarà strutturata la richiesta:

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

In questo codice, la richiesta body viene costruita utilizzando JSON.stringify() per convertire l’oggetto payload in una stringa JSON. La risposta viene poi memorizzata nella variabile data. Utilizzando il metodo useNavigate della libreria react-router-dom, i parametri displayName e operation_id vengono passati come parametri del percorso. Assicuratevi di importare il metodo useNaviagte e di istanziarlo:

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

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

Ora, quando compiliamo il modulo e clicchiamo sul pulsante Clone site, inizierà il processo di clonazione di un nuovo sito, che sarà visibile nella dashboard MyKinsta. Tuttavia, vogliamo seguire l’operazione di clonazione del sito in modo programmatico all’interno dell’interfaccia utente personalizzata. Questo viene gestito in Operations.jsx utilizzando i dati inviati tramite la route.

Implementare la verifica dello stato dell’operazione con l’API di Kinsta

In Operations.jsx, recuperiamo l’ID dell’operazione dalla route utilizzando il metodo useParams di react-router-dom. Questo ID sarà utilizzato per effettuare una richiesta API ogni volta che si clicca sul pulsante Check Site Status.

Per prima cosa, importiamo il metodo useParams e usiamolo per istanziare le variabili displayName e operationId:

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

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

Quindi, creiamo uno stato per memorizzare lo stato dell’operazione quando viene effettuata la richiesta:

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

Nel codice precedente, lo stato viene inizializzato con un messaggio predefinito che verrà visualizzato fino a quando non verrà cliccato il pulsante Check Site Status. Aggiungiamo un evento onClick al pulsante Check Site Status e chiamiamo il metodo checkOperation quando il pulsante viene cliccato:

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

Ora, creiamo la funzione checkOperation per effettuare la richiesta di operazione all’API di Kinsta. Memorizziamo le costanti headers e KinstaAPIUrl nelle variabili e poi usiamole nella richiesta 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);
};

Nel codice qui sopra, viene inviata una richiesta GET all’endpoint /operations con l’ID dell’operazione e la risposta viene memorizzata nello stato operationData. Ora possiamo utilizzare i dati nel markup:

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

Infine, i dati di displayName passati attraverso la route saranno utilizzati per costruire l’URL del nuovo sito e l’URL dell’area di amministrazione di WordPress. Entrambi i link si apriranno in una nuova scheda.

<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 queste modifiche, Operations.jsx recupererà l’ID dell’operazione dalla route, effettuerà una richiesta API quando viene cliccato il pulsante, visualizzerà lo stato dell’operazione e fornirà i link all’URL dell’area di amministrazione di WordPress e del sito in base ai dati di displayName.

Distribuire l’applicazione su Kinsta

Per distribuire l’applicazione sulla piattaforma di Hosting di Applicazioni di Kinsta, dovrete inviare il progetto al vostro provider Git preferito. Una volta che il progetto sarà ospitato su GitHub, GitLab o Bitbucket, potrete procedere al deploy su Kinsta.

Per distribuire il repository su Kinsta, seguire i seguenti passaggi:

  1. Accedere o creare un account Kinsta nella dashboard MyKinsta.
  2. Nella barra laterale di sinistra, cliccare su Applicazioni e poi su Aggiungi servizio.
  3. Selezionare Applicazione dal menu a tendina per distribuire un’applicazione React su Kinsta.
  4. Nella finestra di dialogo che appare, scegliere il repository che si desidera distribuire. Se si hanno più branch, è possibile selezionare il branch desiderato e dare un nome all’applicazione.
  5. Selezionare uno dei data center disponibili nell’elenco delle opzioni di 25.
  6. Kinsta rileva automaticamente il comando Start dell’applicazione.

Infine, non è sicuro inviare le chiavi API a host pubblici come un provider Git. Durante l’hosting, si possono aggiungere come variabili d’ambiente utilizzando lo stesso nome e valore della variabile specificata nel file .env.

variabili d'ambiente
Impostare le variabili d’ambiente su MyKinsta durante la distribuzione.

Una volta avviata la distribuzione dell’applicazione, il processo inizia e in genere si conclude in pochi minuti. Una distribuzione riuscita genera un link all’applicazione, come https://clone-wp-site-12teh.kinsta.app/.

Riepilogo

L’API di Kinsta offre la flessibilità necessaria per creare interfacce utente personalizzate per la gestione dei siti WordPress, compresa la possibilità di clonare siti esistenti e gestire vari aspetti del proprio ambiente WordPress.

In questo articolo abbiamo imparato a sviluppare un’applicazione che permette di clonare un sito al di fuori di MyKinsta.

Come utilizzate le API di Kinsta? Quali funzioni ed endpoint vorreste vedere aggiunti alle API? Condividiteli nella sezione commenti!

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.