Come utenti di Google Chrome, probabilmente avrete utilizzato alcune estensioni del browser. Vi siete mai chiesti come sono costruite o come crearne una?
Questo articolo vi guida attraverso il processo di creazione di un’estensione per Chrome, in particolare una che utilizza React e l’API di Kinsta per gestire i plugin sui siti WordPress ospitati con Kinsta.
Cos’è un’estensione di Chrome?
Un’estensione di Chrome è un programma che viene installato nel browser Chrome e ne migliora le funzionalità. Le estensioni possono variare da semplici pulsanti a icona nella barra degli strumenti a funzioni completamente integrate che interagiscono profondamente con la propria esperienza di navigazione.
Come creare un’estensione di Chrome
Creare un’estensione di Chrome è come sviluppare un’applicazione web, ma richiede un file in formato JSON chiamato manifest.json. Questo file costituisce la struttura portante dell’estensione, dettando le impostazioni, i permessi e le funzionalità che si desidera includere.
Per iniziare, creiamo una cartella che conterrà tutti i file dell’estensione. Successivamente, creiamo un file manifest.json nella cartella.
Un file manifest.json di base per un’estensione di Chrome include proprietà chiave che definiscono le impostazioni di base dell’estensione. Di seguito è riportato un esempio di file manifest.json che include i campi necessari per il suo funzionamento:
{
"manifest_version": 3,
"name": "My Chrome extension",
"version": "1.0",
"description": "Here is a description for my Chrome extension."
}
Possiamo caricarlo e testarlo come estensione scompattata in Chrome. Andiamo su chrome://extensions
nel browser e attiviamo la modalità sviluppatore, quindi clicchiamo sul pulsante Load Unpacked. Si aprirà un browser di file e potremo selezionare la directory creata per la nostra estensione.
Cliccando sull’icona dell’estensione, non succederà nulla perché non abbiamo ancora creato un’interfaccia utente.
Creare un’interfaccia utente (popup) per l’estensione Chrome
Come per ogni applicazione web, l’interfaccia utente (UI) dell’estensione utilizza l’HTML per strutturare il contenuto, il CSS per lo stile e il JavaScript per aggiungere interattività.
Creiamo un’interfaccia utente di base utilizzando tutti questi file. Iniziamo creando un file HTML (popup.html). Questo file definisce la struttura degli elementi dell’interfaccia utente, come testo, titoli, immagini e pulsanti. Aggiungiamo il seguente codice:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Hello World</title>
<link rel="stylesheet" href="popup.css" />
</head>
<body>
<h1>Hello World!</h1>
<p>My first Chrome Extension</p>
<button> id="sayHello">Say Hello</button>
<script> src="popup.js"></script>
</body>
</html>
Il codice qui sopra crea un titolo, un paragrafo e un pulsante. Anche i file CSS e JavaScript sono collegati. Ora aggiungiamo alcuni stili nel file popup.css:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: Arial, sans-serif;
background-color: aliceblue;
padding: 20px;
}
Poi, nel file popup.js, aggiungiamo un ascoltatore di eventi al pulsante in modo che quando viene cliccato, venga visualizzato un avviso:
const sayHelloBtn = document.getElementById('sayHello');
sayHelloBtn.addEventListener('click', async () => {
let tab = await chrome.tabs.query({ active: true });
chrome.scripting.executeScript({
target: { tabId: tab[0].id },
function: () => alert('Hello from the extension!'),
});
});
Questo codice JavaScript recupera la scheda attiva corrente e utilizza la Chrome Scripting API per eseguire uno script che visualizza un avviso con un messaggio di saluto quando viene cliccato il pulsante Say Hello. In questo modo si introduce un’interattività di base nell’estensione di Chrome.
Grazie a questi passaggi, abbiamo creato una semplice interfaccia utente popup per la nostra estensione Chrome che include testo, stile e funzionalità di base.
Infine, dobbiamo abilitare il file popup nel file manifest.json aggiungendo alcuni permessi:
{
. . . ,
"action": {
"default_popup": "popup.html"
},
"permissions": [
"scripting",
"tabs"
],
"host_permissions": [
"http://*/*",
"https://*/*"
]
}
Nella configurazione qui sopra, la chiave default_popup
specifica che popup.html sarà l’interfaccia utente predefinita quando l’utente interagisce con l’estensione. L’array permissions
include i permessi scripting
e tabs
, che sono fondamentali affinché l’estensione possa interagire con le schede e utilizzare le funzioni di scripting del browser.
L’array host_permissions
specifica con quali siti l’estensione può interagire. I modelli http://*/*
e https://*/*
indicano che l’estensione può interagire con tutti i siti web accessibili tramite i protocolli HTTP e HTTPS.
Con queste impostazioni nel file manifest.json, l’estensione Chrome è correttamente configurata per visualizzare un popup ed eseguire script.
Aggiornare l’estensione di Chrome
Dopo aver apportato queste modifiche nella cartella locale, dobbiamo aggiornare la cartella scompattata caricata su Chrome. Per farlo, apriamo la pagina delle estensioni di Chrome, individuiamo l’estensione e clicchiamo sull’icona refresh.
A questo punto, possiamo cliccare sull’icona dell’estensione e apparirà un popup. Cliccando sul pulsante Say Hello, apparirà un avviso.
Ora abbiamo una conoscenza di base su come iniziare a creare un’estensione per Chrome. Ma possiamo fare molto di più. Possiamo manipolare l’interfaccia utente del sito, fare richieste API, recuperare dati da URL per eseguire operazioni specifiche e altro ancora.
Come creare un’estensione per Chrome con React
Come abbiamo detto in precedenza, la creazione di un’estensione di Chrome è simile alla creazione di un’applicazione web. Possiamo utilizzare framework web popolari come React.
Per React, il file manifest.json viene creato nella cartella public. Questa cartella viene utilizzata per le risorse statiche che non si desidera vengano elaborate da Webpack (o da altri bundler simili che React potrebbe utilizzare in strumenti come Create React App).
Quando costruiamo la nostra applicazione React, il processo di build copia tutti i contenuti della cartella public nella cartella dist. Ecco come creare un’estensione di Chrome con React:
- Creiamo una nuova applicazione React. Possiamo utilizzare l’ambiente di sviluppo locale Vite eseguendo questo comando nel terminale:
npm create vite@latest
Quindi, diamo un nome al progetto e selezioniamo React come framework. Una volta fatto questo, navighiamo nella cartella del progetto e installiamo le dipendenze:
cd <project-name>
npm install
- Nella cartella public del progetto React, creiamo un file manifest.json. Aggiungiamo le seguenti configurazioni:
{
"manifest_version": 3,
"name": "React Chrome extension",
"description": "Chrome extension built with React",
"version": "0.1.0",
"action": {
"default_popup": "index.html"
},
"permissions": [
"tabs"
],
"host_permissions": [
"http://*/*",
"https://*/*"
]
}
La configurazione di un’estensione Chrome include un oggetto action
che imposta index.html come popup predefinito quando si clicca sull’icona dell’estensione. Questo è il file HTML statico generato quando costruiamo un’applicazione React.
- È il momento di sviluppare l’applicazione React. Qui possiamo sctenare la nostra fantasia e fare richieste API, stilizzarle come vogliamo, usare React Hooks e altro ancora.
- Una volta finito di costruire l’interfaccia utente dell’estensione, eseguiamo il comando di build in React (
npm run build
). Tutte le risorse, compresi il file manifest.json, l’index.html generato da React e altri, vengono spostate nella cartella dist o build. - Infine, carichiamo l’estensione in Chrome. Andiamo su
chrome://extensions/
ed eseguiamo il refresh dell’estensione.
Creare un’estensione Chrome per gestire i plugin di un sito con l’API di Kinsta
Ecco come apparirà l’estensione Chrome che creeremo:
Facendo clic, l’estensione mostra un elenco di siti con plugin obsoleti sul nostro account MyKinsta. Possiamo vedere l’elenco dei plugin e cliccare sul pulsante Visualizza in MyKinsta per accedere alla pagina Temi e plugin del sito, dove potremo aggiornare ogni plugin.
Vediamo come creare l’estensione per Chrome.
L’API di Kinsta
L’API di Kinsta è un potente strumento che permette di interagire in modo programmatico con i servizi di 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 del 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 WordPress, un’applicazione o un database in MyKinsta. Inoltre, dovremo generare una chiave API per autenticarci e accedere al nostro account.
Per generare una chiave API:
- Andiamo alla dashboard di MyKinsta.
- Andiamo alla pagina delle chiavi API (Nome > Impostazioni dell’azienda > Chiavi API).
- Clicchiamo su Crea chiave API.
- Scegliamo una scadenza o impostiamo una data di inizio personalizzata e un numero di ore di scadenza della chiave.
- Assegniamo alla chiave un nome univoco.
- Clicchiamo su Genera.
Dopo aver creato una chiave API, copiamola e conserviamola in un luogo sicuro (utilizzando ad esempio 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.
Gestire i plugin del sito con Kinsta API e React
Iniziamo a sviluppare un’interfaccia utente in React, che verrà poi trasformata in un’estensione per Chrome. Questa guida presuppone una familiarità di base con React e l’interazione con le API.
Impostazione dell’ambiente
Innanzitutto, nel file App.jsx, definiamo una costante per l’URL dell’API di Kinsta per evitare ridondanze nel codice:
const KinstaAPIUrl = 'https://api.kinsta.com/v2';
Per sicurezza, memorizziamo i dati sensibili come la chiave API e l’ID dell’azienda Kinsta in un file .env.local per tenerli al sicuro e fuori dal codice sorgente:
VITE_KINSTA_COMPANY_ID=YOUR_COMPANY_ID
VITE_KINSTA_API_KEY=YOUR_API_KEY
Recuperare i dati con l’API di Kinsta
Nel file App.jsx, dobbiamo effettuare diverse richieste all’API di Kinsta per recuperare informazioni sui siti e sui loro plugin.
- Recuperare i siti dell’azienda: iniziamo recuperando l’elenco dei siti associati al nostro account azienda su Kinsta. Utilizziamo l’ID dell’azienda in una richiesta GET, che restituisce un array di dettagli del sito.
const getListOfCompanySites = async () => { const query = new URLSearchParams({ company: import.meta.env.VITE_KINSTA_COMPANY_ID, }).toString(); const resp = await fetch(`${KinstaAPIUrl}/sites?${query}`, { method: 'GET', headers: { Authorization: `Bearer ${import.meta.env.VITE_KINSTA_API_KEY}`, }, }); const data = await resp.json(); const companySites = data.company.sites; return companySites; }
- Recuperare i dati dell’ambiente per ogni sito: per ogni sito, recuperiamo gli ambienti, che includono l’ID dell’ambiente necessario per ulteriori richieste. Questo comporta la mappatura di ogni sito e una chiamata API all’endpoint
/sites/${siteId}/environments
.const companySites = await getListOfCompanySites(); // 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 ${import.meta.env.VITE_KINSTA_API_KEY}`, }, }); const data = await resp.json(); const environments = data.site.environments; return { id: siteId, name: site.display_name, environments: environments, }; });
- Recuperare i plugin per ogni ambiente del sito: infine, utilizziamo l’ID dell’ambiente per recuperare i plugin per ogni sito. Questo passaggio prevede una funzione di mappatura e una chiamata API all’endpoint
/sites/environments/${environmentId}/plugins
per ogni ambiente.// 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 ${import.meta.env.VITE_KINSTA_API_KEY}`, }, } ); const data = await resp.json(); const plugins = data.environment.container_info; return { env_id: environmentId, name: site.name, site_id: site.id, plugins: plugins, }; });
Ora possiamo riunire tutte queste richieste in una funzione che viene utilizzata per restituire l’array finale di siti con i dettagli di base di ogni sito e dei suoi plugin:
const getSitesWithPluginData = async () => { const getListOfCompanySites = async () => { const query = new URLSearchParams({ company: import.meta.env.VITE_KINSTA_COMPANY_ID, }).toString(); const resp = await fetch(`${KinstaAPIUrl}/sites?${query}`, { method: 'GET', headers: { Authorization: `Bearer ${import.meta.env.VITE_KINSTA_API_KEY}`, }, }); const data = await resp.json(); const companySites = data.company.sites; return companySites; } const companySites = await getListOfCompanySites(); // 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 ${import.meta.env.VITE_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 ${import.meta.env.VITE_KINSTA_API_KEY}`, }, } ); const data = await resp.json(); const plugins = data.environment.container_info; return { env_id: environmentId, name: site.name, site_id: site.id, plugins: plugins, }; }); // Wait for all the promises to resolve const sitesWithPluginData = await Promise.all(sitesWithPlugin); return sitesWithPluginData; }
Visualizzare i dati dei siti
Creiamo uno stato con l’hook useState
per memorizzare i siti con i plugin obsoleti. L’hook useEffect
chiamerà anche il metodo getSitesWithPluginData()
per estrarre i dettagli del sito quando il componente viene montato.
Nell’hook useEffect
, creiamo una funzione che esegua un ciclo su ogni sito per filtrare i siti con plugin obsoleti e poi memorizzarli nello stato:
const [sitesWithOutdatedPlugin, setSitesWithOutdatedPlugin] = useState([]);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
const checkSitesWithPluginUpdate = async () => {
const sitesWithPluginData = await getSitesWithPluginData();
const sitesWithOutdatedPlugin = sitesWithPluginData.map((site) => {
const plugins = site.plugins.wp_plugins.data;
const outdatedPlugins = plugins.filter((plugin) => plugin.update === "available");
if (outdatedPlugins.length > 0) {
const kinstaDashboardPluginPageURL = `https://my.kinsta.com/sites/plugins/${site.site_id}/${site.env_id}?idCompany=${import.meta.env.VITE_KINSTA_COMPANY_ID}`;
return {
name: site.name,
plugins: outdatedPlugins,
url: kinstaDashboardPluginPageURL,
};
}
});
setSitesWithOutdatedPlugin(sitesWithOutdatedPlugin);
checkSitesWithPluginUpdate();
setIsLoading(false);
}, []);
Nel codice qui sopra, si nota che anche lo stato di caricamento è stato creato e impostato su true
per impostazione predefinita. Questo verrà utilizzato per controllare la visualizzazione dei dati. Quando tutti i dati sono stati caricati, lo impostiamo su false
.
Di seguito è riportato un markup per rendere i dati del sito e i plugin all’interno dell’interfaccia utente.
import { useEffect, useState } from "react"
import KinstaLogo from './assets/kinsta-logo.png'
import PluginPage from './components/PluginsPage'
function App() {
// load the data from the API
return (
<div className="container">
<div>
<div> className="title-section">
<img src={KinstaLogo} className="logo" alt="" />
</div>
<p> className="info-box">
Get quick information about your site plugins that need update.
</p>
{isLoading ? (
<p>Loading...</p>
) : (
<>
<div className="content">
<p>The following sites have plugins that need to be updated.</p>
{sitesWithOutdatedPlugin.map((site, index) => {
return (
<PluginPage key={index} {...site} />
);
})}
</div>
</>
)}
</div>
</div>
)
}
export default App
Il codice include un’intestazione con un logo e un paragrafo informativo. Il contenuto dell’interfaccia utente viene renderizzato in modo condizionale in base allo stato di isLoading
. Se i dati sono ancora in fase di caricamento, viene visualizzato un messaggio di caricamento. Una volta che i dati sono stati caricati, vengono presentati i dati relativi ai siti e agli eventuali plugin che necessitano di aggiornamenti.
Notiamo anche un componente PluginPage
(PluginPage.jsx). Questo componente è stato progettato per visualizzare i singoli siti e i dettagli dei loro plugin. Include una funzionalità per attivare la visibilità dei dettagli dei plugin.
import { useState } from "react"
import { FaRegEye } from "react-icons/fa";
import { FaRegEyeSlash } from "react-icons/fa";
const PluginUse = (site) => {
const [viewPlugin, setViewPlugin] = useState(false);
return (
<>
<div className="site-card">
<div className="site-card-details">
<p>{site.name}</p>
<div className="both-btns">
<a> href={site.url} target="_blank" rel="noreferrer" className="btn">
View in MyKinsta
</a>
<button onClick={() => setViewPlugin(!viewPlugin)} className="btn" title="View Plugins">
{viewPlugin ? <FaRegEyeSlash /> : <FaRegEye />}
</button>
</div>
</div>
{viewPlugin && (
<div className="plugin-list">
{site.plugins.map((plugin, index) => {
return (
<div key={index} className="plugin-card">
<p>{plugin.name}</p>
<div className="plugin-version-info">
<p>Current Version: {plugin.version}</p>
<p>Latest Version: {plugin.update_version}</p>
</div>
</div>
);
})}
</div>
)}
</div>
</>
)
}
export default PluginUse
Configurare il file manifest
Per trasformare l’interfaccia utente e le funzionalità in un’estensione di Chrome, dobbiamo configurare il file manifest.json.
Creiamo un file manifest.json nella cartella public e incolliamo il codice qui sotto:
{
"manifest_version": 3,
"name": "Kinsta Plugins Manager - Thanks to Kinsta API",
"description": "This extension allows you to manage your WordPress site's plugin from Kinsta's MyKinsta dashboard via Kinsta API.",
"version": "0.1.0",
"icons": {
"48": "kinsta-icon.png"
},
"action": {
"default_popup": "index.html"
},
"permissions": [
"tabs"
],
"host_permissions": [
"https://my.kinsta.com/*"
]
}
Assicuriamoci di aggiungere il file dell’icona alla cartella public.
A questo punto, possiamo eseguire il comando di build (npm run build
) in modo che tutte le risorse, compresi il file manifest.json, l’index.html generato da React e altri file, vengano spostati nella cartella dist o build.
Successivamente, andiamo su chrome://extensions/
e carichiamo l’estensione in Chrome come estensione scompattata. Clicchiamo sul pulsante Load Unpacked e selezioniamo la cartella creata per l’estensione.
Limitare l’estensione a siti specifici
Questa estensione funziona in qualsiasi momento. Noi, però, vogliamo che funzioni solo quando un utente naviga verso la dashboard di MyKinsta.
Per farlo, modifichiamo il file App.jsx. Creiamo uno stato per memorizzare la scheda attiva:
const [activeTab, setActiveTab] = useState(null);
Quindi, aggiorniamo l’hook useEffect
per definire e invocare la funzione getCurrentTab
:
const getCurrentTab = async () => {
const queryOptions = { active: true, currentWindow: true };
const [tab] = await chrome.tabs.query(queryOptions);
setActiveTab(tab);
}
getCurrentTab();
Il codice precedente utilizza chrome.tabs.query
con opzioni di interrogazione specifiche per assicurarsi di recuperare solo la scheda attiva nella finestra corrente. Una volta recuperata la scheda, questa viene impostata come scheda attiva nello stato dell’estensione.
Infine, implementiamo una logica di rendering condizionale nella dichiarazione di ritorno del componente. Questo assicura che l’interfaccia di gestione del plugin venga visualizzata solo quando l’utente si trova nella dashboard di MyKinsta:
return (
<div className="container">
{activeTab?.url.includes('my.kinsta.com') ? (
<div >
<div className="title-section">
<img src={KinstaLogo} className="logo" alt="" />
</div>
<p className="info-box">
Get quick information about your site plugins that need update.
</p>
{isLoading ? (
<p>Loading...</p>
) : (
<>
<div className="content">
<p>The following {sitesWithPluginUpdate} sites have plugins that need to be updated.</p>
{sitesWithOutdatedPlugin.map((site, index) => {
return (
<PluginPage key={index} {...site} />
);
})}
</div >
</>
)}
</div >
) : (
<div >
<div className="title-section">
<img src={KinstaLogo} className="logo" alt="" />
</div>
<p className="info-box">
This extension is only available on Kinsta Dashboard.
</p>
</div>
)}
</div>
)
Dopo aver apportato le modifiche, eseguiamo nuovamente la build dell’applicazione e riaggiorniamo l’estensione Chrome. In questo modo verranno applicate le nuove logiche e restrizioni.
Riepilogo
In questo articolo abbiamo appreso le basi della creazione di un’estensione per Chrome e come crearne una con React. Abbiamo anche imparato a creare un’estensione che interagisce con l’API di Kinsta.
Come utenti di Kinsta, potete sfruttare l’enorme potenziale e la flessibilità dell’API di Kinsta per sviluppare soluzioni personalizzate per la gestione di siti, applicazioni e database.
Quale endpoint dell’API di Kinsta state usando più spesso e come lo utilizzate? Condividetelo con noi nella sezione commenti!
Lascia un commento