Não é necessário que você já gerencie muitos dentre os 800 milhões de sites WordPress na web para começar a descobrir formas de lançar novos sites com eficiência.

Clonar uma configuração existente do WordPress é uma maneira de começar a trabalhar rapidamente, e os clientes do serviço da Kinsta de hospedagem gerenciada de WordPress sabem que isso pode ser feito facilmente em nosso painel MyKinsta, de fácil utilização.

Além disso, você pode clonar sites WordPress em escala usando suas tecnologias favoritas de desenvolvimento de aplicativos e a API da Kinsta. Neste tutorial, usamos essa API e o React, uma das várias e populares bibliotecas JavaScript, para mostrar como isso funciona.

O que você está construindo

O cenário é o seguinte: você é uma agência de desenvolvimento WordPress com um ou mais sites que podem ser usados como templates iniciais. O aplicativo React de clonagem de sites WordPress que estamos criando é parecido com este:

Aplicativo React para clonagem de site com a API da Kinsta.
Aplicativo React para clonagem de site com a API da Kinsta.

Pré-requisitos

Para seguir este tutorial, você precisará de um conhecimento básico de HTML, CSS e JavaScript, e alguma familiaridade com o React. Além disso, precisará do Node.js e do npm (o gerenciador de pacotes do Node), ou o yarn, instalados em seu computador. O foco deste projeto é criar um aplicativo de clonagem do WordPress usando o React e a API da Kinsta, e não detalhes de criação e estilo da interface do usuário (UI).

Configurando o ambiente de desenvolvimento

Você pode criar um aplicativo React do zero e desenvolver sua própria interface, ou pode pegar o template inicial do Git mencionado acima, seguindo estas etapas:

  1. Visite o repositório do GitHub deste projeto.
  2. Selecione Use this template > Create a new repository para copiar o código inicial em um repositório dentro de sua conta do GitHub. (Marque a caixa include all branches.).
  3. Puxe o repositório para seu computador local e mude para o branch starter-files usando o comando: git checkout starter-files.
  4. Instale as dependências necessárias executando o comando npm install.

Quando a instalação estiver concluída, você poderá iniciar o projeto no computador local com npm run start. Isso abre o projeto em http://localhost:3000/.

Entendendo os arquivos de projeto

A pasta src é o coração de um aplicativo React, pois contém o JavaScript necessário para o webpack. Nessa pasta está o App.js, no qual as duas rotas deste projeto estão configuradas.

Dentro da pasta src estão as subpastas components e pages. A pasta components contém componentes reutilizáveis, como Header.jsx e Footer.jsx, usados nas páginas Home.jsx e Operations.jsx.

Aqui você se concentra na implantação da lógica em Home.jsx e Operations.jsx, já que o estilo e o roteamento podem ser encontrados em nossos arquivos iniciais do GitHub.

O Home.jsx tem um formulário com dois campos: o nome do site que você está criando e um campo de seleção que lista os sites do WordPress encontrados em sua conta MyKinsta (essa lista é obtida por meio da API da Kinsta).

Quando o botão de envio do formulário Clonar site é clicado, é retornado um objeto que contém uma propriedade operation_id. Essa ID e o nome de exibição serão passados como parâmetros de rota para Operations.jsx, onde o status da operação de clonagem é relatado. A interface também incluirá links para acessar o login do administrador do WordPress e a página inicial do site.

Página de operações mostrando links para o administrador do WP e o site.
Página de operações mostrando links para o administrador do WP e o site.

Usando a API da Kinsta para clonar um site do WordPress

Em Home.jsx, três solicitações de API serão feitas à API da Kinsta. A primeira é para obter uma lista de sites em sua conta Kinsta. Isso será armazenado em um estado e, em seguida, iterado para o campo de seleção. Essa solicitação será feita imediatamente após a renderização da página usando o Hook useEffect.

A segunda e a terceira solicitações são feitas quando o botão Clonar site é clicado. A segunda solicitação obtém o ID do ambiente do site que você deseja clonar. A terceira usa esse ID de ambiente e o nome de exibição do site para iniciar a clonagem do site.

Interagindo com a API da Kinsta no React

Neste tutorial, você interage com dois endpoints da API da Kinsta:

  • /sites: Você pode retornar uma lista de todos os sites, solicitar um ID de ambiente do site e, finalmente, clonar um site existente.
  • /operations: É usado para obter o status da operação. Por exemplo, quando a operação de clonagem do site está em andamento, você pode usar esse endpoint para rastrear programaticamente o status da operação para determinar quando ela foi concluída.

Para interagir com a API da Kinsta, você precisa do ID da empresa (pode ser encontrado no MyKinsta em Empresa > Detalhes de faturas > ID da empresa) e uma chave API. (Veja aqui como criar uma chave de API da Kinsta.)

Depois que você tiver essas credenciais, é melhor armazená-las com segurança como variáveis de ambiente em seu aplicativo React. Para configurar as variáveis de ambiente, crie um arquivo .env na pasta raiz do seu projeto. Dentro desse arquivo, adicione as seguintes linhas:

REACT_APP_KINSTA_COMPANY_ID = 'YOUR_COMPANY_ID' 
REACT_APP_KINSTA_API_KEY = 'YOUR_API_KEY'

Para acessar essas variáveis de ambiente em seu projeto, você pode usar a sintaxe process.env.THE_VARIABLE. Por exemplo, para acessar REACT_APP_KINSTA_COMPANY_ID, você usaria process.env.REACT_APP_KINSTA_COMPANY_ID.

Clonar um site existente com a API da Kinsta

Vamos começar buscando a lista de todos os sites quando o Home.jsx renderizar, usando o Hook useEffect e armazenando-os em um estado. Para isso, importe os hooks useEffect e useState, e crie um estado para armazenar o array dos sites que será obtido:

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

Em seguida, use o hook useEffect para consultar a API da Kinsta usando a API JavaScript Fetch. Primeiro, crie duas variáveis constantes para armazenar os cabeçalhos e a URL da API da Kinsta. Isso é feito para evitar repetição, pois você enviará mais de uma solicitação à API da Kinsta nesta página:

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

No código acima, o hook useMemo memoriza o objeto headers para que ele não precise ser reavaliado em cada renderização, pois seu valor é constante. Agora você pode criar a solicitação de 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]);

No código acima, é criada uma função assíncrona, fetchAllSites. Dentro dessa função, você primeiro define o parâmetro query (o ID da sua empresa) obtido do seu arquivo .env. Daí faz uma solicitação GET ao endpoint /sites da API da Kinsta, usando o parâmetro query. A resposta é então armazenada no estado sites que você criou anteriormente. Por fim, você chama fetchAllSites para iniciar o processo de busca.

Agora vamos incorporar os valores armazenados no estado sites, percorrendo-os para preencher o campo de seleção. O nome de exibição será mostrado ao usuário, enquanto o ID do site será usado como o valor da opção. Dessa forma, quando o formulário for enviado, o ID do site selecionado poderá ser usado para consultar os detalhes do 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>

Prosseguimos com o envio do formulário e a recuperação dos dados dele. Para fazer isso, é preciso criar variáveis de estado para cada campo de entrada:

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

Em seguida, vincule os campos do formulário a seus respectivos valores de estado adicionando os atributos value e onChange a cada elemento de entrada. O formulário ficará assim:

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

No código acima, cada elemento de entrada tem o atributo value definido como a variável de estado correspondente. E o atributo onChange é usado para atualizar o valor do estado quando o usuário interage com os campos de entrada.

Para gerenciar o envio do formulário, anexe um método onSubmit ao elemento formulário. Por exemplo:

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

Defina o método handleSubmission, que envolve fazer duas solicitações de API para a API da Kinsta. A primeira solicitação recupera o ID do ambiente do site a ser clonado, e a segunda solicitação executa a operação de clonagem.

Vamos começar recuperando a ID do ambiente. Dentro do método handleSubmission, crie uma função assíncrona para lidar com essa solicitação. A função enviará uma solicitação GET para o endpoint /sites, anexando o ID do site selecionado, seguido do 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);
}

Acima, fetchEnvironmentId é uma função assíncrona que envia uma solicitação GET à API da Kinsta. Ela busca os ambientes do site selecionado e extrai o ID do ambiente da resposta. A ID do ambiente é armazenada na variável envId, e então retornada. Ao chamar a função, atribuímos o valor retornado à variável envId.

Neste ponto você pode clonar um site existente com a API da Kinsta, pois tem as informações essenciais sobre o site de origem: ID da empresa, nome de exibição e ID do ambiente.

Dentro do método handleSubmission, crie uma função chamada cloneExistingSite para lidar com essa solicitação de API. Essa solicitação será para o endpoint /sites/clone. Diversamente das solicitações anteriores, os cabeçalhos dessa solicitação são diferentes, porque você precisa especificar o Content-Type como application/json. Além disso, esta é uma solicitação POST. Portanto, você precisa incluir um corpo de solicitação contendo a carga útil que deseja enviar à API. Veja como a solicitação será estruturada:

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

Neste código, a solicitação body é construída usando JSON.stringify() para converter o objeto carga útil em uma string de caracteres JSON. A resposta é então armazenada na variável de dados. Usando o método useNavigate da biblioteca react-router-dom, o displayName e o operation_id são passados como parâmetros de rota. Certifique-se de importar o método useNavigate e instanciá-lo:

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

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

Agora, quando você preencher o formulário e clicar no botão Clone site, um novo site iniciará o processo de clonagem, visível no painel MyKinsta. No entanto, queremos rastrear a operação de clonagem do site de forma programática na interface de usuário personalizada. Você pode gerenciar isso no Operations.jsx, usando os dados enviados pela rota.

Implantação da verificação do status da operação com a API da Kinsta

Em Operations.jsx, recupere  o ID da operação da rota, usando o método useParams da react-router-dom. Esse ID será usado para fazer uma solicitação de API sempre que o botão Check Site Status for clicado.

Primeiro, importe o método useParams e use-o para instanciar as variáveis displayName e operationId:

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

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

A seguir crie um estado para armazenar o status da operação quando a solicitação for feita:

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

No código acima, o estado é inicializado com uma mensagem padrão, que será exibida até que o botão Check Site Status seja clicado. Adicione um evento onClick ao botão Check Site Status e chame o método checkOperation quando o botão for clicado:

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

Agora crie a função checkOperation para fazer a solicitação de operação à API da Kinsta. Armazene as constantes headers e KinstaAPIUrl em variáveis, e então as utilize na solicitação da 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);
};

No código acima, uma solicitação GET é enviada para o endpoint /operations com o ID da operação, e a resposta é armazenada no estado operationData. Agora você pode usar os dados na marcação:

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

Por fim, os dados de displayName passados por meio da rota serão usados para construir a URL do novo site e a URL de administração do WordPress. Ambos os links serão abertos em uma nova aba.

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

Com essas alterações, o Operations.jsx vai recuperar o ID da operação da rota, fazer uma solicitação de API quando o botão for clicado, exibir o status da operação e fornecer links para o administrador do WordPress e a URL do site com base nos dados do displayName.

Implante seu aplicativo na Kinsta

Para implante seu aplicativo na plataforma de hospedagem de aplicativos da Kinsta, você precisa enviar o projeto para o provedor Git de sua preferência. Quando o projeto estiver hospedado no GitHub, GitLab ou Bitbucket, você poderá prosseguir com a implantação na Kinsta.

Para implantar seu repositório na Kinsta, siga estes passos:

  1. Faça login ou crie sua conta Kinsta no painel MyKinsta.
  2. Na barra lateral esquerda, clique em Aplicativos e, em seguida, clique em Adicionar serviço.
  3. Selecione Aplicativo no menu suspenso para implantar um aplicativo React na Kinsta.
  4. No modal que aparece, escolha o repositório que deseja implantar. Se tiver vários branches, você poderá selecionar o branch desejado e dar um nome ao seu aplicativo.
  5. Selecione um dos locais de centros de dados disponíveis na lista de 25 opções.
  6. A Kinsta detecta automaticamente o comando start para o seu aplicativo.

Por fim, não é seguro enviar chaves de API para hosts públicos, como seu provedor Git. Ao hospedar, você pode adicioná-las como variáveis de ambiente, usando o mesmo nome de variável e valor especificados no arquivo .env.

Defina as variáveis de ambiente no MyKinsta quando você estiver implementando.
Defina as variáveis de ambiente no MyKinsta quando você estiver implementando.

Após iniciar a implantação do seu aplicativo, o processo começa e é normalmente concluído em alguns minutos. Uma implantação bem-sucedida gera um link para o seu aplicativo, como https://clone-wp-site-12teh.kinsta.app/.

Resumo

A API da Kinsta oferece a flexibilidade de criar interfaces de usuário personalizadas para gerenciar sites WordPress, incluindo a capacidade de clonar sites existentes e gerenciar vários aspectos do seu ambiente WordPress.

Neste artigo, você aprendeu a desenvolver um aplicativo que permite a clonagem de sites fora do MyKinsta.

Como você está usando a API da Kinsta? Quais recursos e endpoints você gostaria de ver adicionados à API? Compartilhe na seção de comentários!

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.