Uma das melhores maneiras de elevar seu status como um Desenvolvedor WordPress , pelo menos aos olhos de seus clientes, é se tornar hábil no consumo de APIs. Aqui está um cenário comum para a implementação da API do WordPress: Seu cliente pede que você adicione um widget ao site dele - digamos, por exemplo, um widget de assinatura de e-mail. Você pega algum código do serviço de e-mail de terceiros - talvez seja uma tag de script ou um iframe
- cole na página e responda ao seu cliente, “Entendi!”
Infelizmente, você está lidando com um cliente um pouco mais exigente e ele percebe as seguintes imperfeições:
Neste ponto, uma de duas coisas pode acontecer razoavelmente. Você pode declarar esses itens 'agradáveis para ter' e tranquilizar seu cliente sobre os méritos de um Solução 80/20 , ou você pode atender a esses pedidos. Em minha experiência pessoal, descobri que atender a essas solicitações, ou seja, demonstrar domínio de serviços de terceiros, é uma maneira confiável de convencer o cliente de que você é uma espécie de assistente do WordPress. Além disso, muitas vezes é divertido de fazer.
Na última década, usei o WordPress como uma plataforma para consumo de API em provavelmente 50 APIs diferentes. Algumas das APIs mais comuns são MailChimp, Google Analytics, Google Maps, CloudFlare e Bitbucket. Mas e se você precisar fazer mais, e se precisar de uma solução personalizada?
Neste artigo, vou desenvolver uma API genérica de 'serviço de e-mail', tentando o meu melhor para manter as coisas o mais agnósticas possível. No entanto, acho que é razoável supor que estamos lidando com uma API JSON REST. Aqui estão alguns tópicos de fundo que podem ajudá-lo a aproveitar os pontos técnicos deste artigo:
Se você se encontra um pouco familiarizado com esses tópicos e está interessado em se aprofundar mais, faça uma pausa agora e baixe o excelente Carteiro inscrição. Ele permite que você se comunique com APIs sem escrever código.
No entanto, se você não está familiarizado com eles, continue lendo de qualquer maneira. Um público técnico com algum grau de experiência em WordPress irá tirar o máximo proveito deste artigo, mas terei o cuidado de explicar o valor de cada técnica de uma forma menos técnica. Um leitor não técnico deixará este artigo capaz de avaliar o ROI de cada ponto antes de patrociná-lo e julgar a qualidade da implementação, uma vez entregue.
Nota: Caso precise de um rápido curso de atualização, você pode conferir nosso Guia da API REST do WordPress .
Sem preâmbulos adicionais, permita-me compartilhar com você um punhado de técnicas diferentes que eu aprecio em quase todas as APIs, projetos e equipes com as quais trabalho.
Em meu parágrafo inicial, observei que o cliente achou irritante ocupar duas áreas de administração: wp-admin e o painel de seu serviço de e-mail. Uma boa maneira de resolver isso seria fornecer a eles um widget de painel em wp-admin, para mostrar um resumo de sua atividade recente de assinante.
Mas, novamente, isso pode exigir várias solicitações HTTP para a API remota (a API fornecida pelo serviço de e-mail), resultando em longos carregamentos de página. A solução para esse problema de desempenho é armazenar chamadas de API como transientes. este Artigo Codex fornece uma ótima explicação que você definitivamente deve ler, mas vou resumi-la assim:
set_transient()
com um prazo de validade de sua escolha com base em seu próprio julgamento sobre desempenho, limites de taxa e margem de erro na exibição de dados desatualizados neste aplicativo específico.get_transient()
antes de concluir que você precisa obtê-lo da API.Considero isso uma base útil e viável, mas você pode dar um passo adiante se pensar um pouco sobre os verbos REST. Dos cinco métodos mais comuns (GET, POST, PATCH, PUT, DELETE), apenas um deles pertence ao seu cache temporário. Você consegue adivinhar qual? É GET. Em meus plug-ins, quase sempre tenho uma classe PHP dedicada a abstrair chamadas para a API remota em questão, e um argumento ao instanciar essa classe é o método HTTP. Se não for uma chamada GET, então não vou invocar nenhuma camada de cache.
Além disso, se não for uma chamada GET, então é lógico que estou tomando alguma medida para alterar os dados remotos de alguma forma, talvez adicionando, editando ou removendo um assinante de e-mail. Este pode ser um bom momento para invalidar o cache existente para esse recurso, via delete_transient()
.
Para voltar ao nosso exemplo de API de assinatura de e-mail do WordPress, veja como isso funcionaria na prática:
/subscribers
por meio de uma solicitação GET. Por ser uma solicitação GET, ela é armazenada em meu cache temporário./subscribers
por meio de uma solicitação POST. Por ser uma solicitação POST, não apenas evitará meu cache temporário, mas também me fará excluir a parte relevante do meu cache temporário, de modo que o widget do painel reflita esse novo assinante.Como cliente ou outra parte interessada menos técnica, você deve solicitar especificamente o armazenamento em cache temporário - ou, pelo menos, uma discussão sobre isso - sempre que o aplicativo estiver extraindo dados de um serviço remoto. Você deve se familiarizar com o excelente Monitor de consulta plugin para obter uma visão de como os transientes estão funcionando. Isso lhe dará uma interface para navegar pelos dados que estão sendo armazenados como temporários, com que frequência e por quanto tempo.
Alguns serviços premium de hospedagem WordPress não permitem que você use transientes na produção. Eles têm código em execução, talvez na forma de um plugin MU ou algum outro script, que irá interceptar sua tentativa de usar a API de transientes e armazenar essas informações por meio do cache de objeto em vez de. WP-Engine , em sua configuração mais comum, é um excelente exemplo disso.
Se você está simplesmente armazenando e recuperando dados, você realmente não precisa se preocupar com isso e pode nem mesmo notar que está acontecendo. Toda a família de *_transient()
As funções fornecerão o mesmo resultado final, apenas filtrado para usar o cache de objetos em vez do cache transiente. Onde você pode encontrar problemas, no entanto, é ao tentar excluir transientes. Aqui está o porquê.
Qual das opções a seguir não está entre os princípios de design?
Se sua integração de API for complexa o suficiente para merecer sua própria página de configurações, você pode desejar incluir uma IU para permitir que o usuário administrador limpe todo o cache temporário do seu plugin . O uso mais comum para este botão é quando o cliente altera alguns dados diretamente no serviço remoto e deseja invalidar o cache que estamos armazenando no WordPress. Este botão também pode ser útil se o cliente alterar as credenciais da conta, chaves de API ou apenas como um botão de “redefinição de fábrica” para depuração.
Mesmo se você fosse inteligente o suficiente para definir o namespace de todas as suas chaves temporárias para ter alguma esperança de identificar cada uma delas para delete_transient()
, o melhor cenário provavelmente ainda envolve SQL bruto, que sempre tento evitar no WordPress :
get_transient_prefix() ); $options = $wpdb -> options; $t = esc_sql( '_transient_timeout_$prefix%' ); $sql = $wpdb -> prepare ( ' SELECT option_name FROM $options WHERE option_name LIKE '%s' ', $t ); $transients = $wpdb -> get_col( $sql ); // For each transient... foreach( $transients as $transient ) { // Strip away the WordPress prefix in order to arrive at the transient key. $key = str_replace( '_transient_timeout_', '', $transient ); // Now that we have the key, use WordPress core to the delete the transient. delete_transient( $key ); } } ?>
Não é conveniente, não é eficiente. Em vez disso, esta situação exige o cache de objetos porque o cache de objetos nos dá uma maneira conveniente de agrupar valores em cache . Dessa forma, quando você precisar esvaziar todos os valores em cache relacionados ao seu plug-in, é uma simples chamada de uma linha para wp_cache_delete( $key, $group )
.
Eu resumiria tudo isso dizendo: Você não pode ser um especialista em consumir APIs se ainda não for um especialista em gerenciar o cache desses dados.
Como cliente, o principal fator a ser observado é o comportamento anormal do cache entre os ambientes de teste e produção. Em outras palavras, embora testar um novo lote de trabalho na preparação seja sempre uma boa prática, o armazenamento em cache é algo que também deve ser testado na produção com o mesmo cuidado.
Ao definir as várias classes PHP para meu plug-in, geralmente acho útil imitar a maneira como os endpoints da API são definidos - por exemplo, o que os endpoints a seguir parecem ter em comum?
Todos eles voltam coleções , com o qual quero dizer o resultado de uma solicitação GET, retornando resultados de zero para muitos em que cada resultado é um membro de uma matriz. Isso pode parecer bastante óbvio, mas acho que é um prompt útil para a seguinte estrutura de classes em meu código PHP:
class.collection.php
, uma classe abstrataclass.subscribers.php
estende a classe abstrata, Collection
.class.lists.php
estende a classe abstrata, Collection
.class.campaigns.php
estende a classe abstrata, Collection
.A classe abstrata tomaria como seu único argumento uma matriz de parâmetros de consulta: coisas como paginação, coluna de classificação, ordem de classificação e filtros de pesquisa. Teria métodos para tarefas comuns, como chamar a API remota, lidar com erros e talvez transformar os resultados em um HTMLmenu ou um jQueryUI AutoSuggest. As classes que instanciam a classe abstrata podem ser bastante curtas, talvez fazendo pouco mais do que especificar a string a ser usada no *.json
URL do endpoint da API.
Da mesma forma, o que os pontos de extremidade a seguir têm em comum?
Todos eles retornam um item , com o que quero dizer exatamente um membro específico e único de uma coleção: coisas como um assinante de e-mail específico, uma lista de e-mail ou uma campanha de e-mail. Portanto, gosto de usar a seguinte estrutura em meu código PHP:
class.item.php
, uma classe abstrataclass.subscriber.php
estende a classe abstrata, Item
.class.list.php
estende a classe abstrata, Item
.class.campaign.php
estende a classe abstrata, Item
.A classe abstrata tomaria como seu único argumento uma string para identificar o item específico que está sendo solicitado. Mais uma vez, as classes que estão sendo instanciadas podem ser bem curtas, talvez fazendo pouco mais do que especificar a string a ser usada em */duy736td.json
.
Existem muitas abordagens para estruturar a herança de classes, mas mesmo se você adotar uma abordagem diferente do que descrevi acima, aposto que há uma boa chance de que a estrutura da API remota possa ajudar a informar a estrutura do seu aplicativo.
Como cliente, um sintoma comum de arquitetura ruim é quando você precisa solicitar a mesma mudança repetidamente em um aplicativo. Por exemplo, se você solicitar que os relatórios retornem 100 resultados por página em vez de 10, e tiver que repetir essa solicitação para relatórios de assinantes, relatórios de campanha, relatórios de cancelamento de assinatura, etc, você pode estar detectando uma arquitetura de classe pobre. Nesta situação, vale a pena perguntar à sua equipe se eles se beneficiariam de um ciclo de refatoração: um corpo de trabalho em que o objetivo não é mudar o comportamento do produto, mas sim melhorar o código subjacente para que seja mais fácil mudar o comportamento do produto no futuro.
WP_Error
Tenho vergonha de admitir que levei anos a mais do que deveria para começar a usar o WP_Error
família de funções em meu código. Eu tendia a apenas codificar do meu jeito, presumindo que nunca haveria erros que valessem a pena se preocupar de forma programática ou lidando com eles caso a caso. Trabalhar com APIs remotas corta essa mentalidade como um feixe de laser, porque apresenta um caso de uso extremamente conveniente e poderoso para usar WP_Error
.
Lembre-se antes de que mencionei que geralmente tenho uma classe PHP cujo objetivo é fazer solicitações HTTP para a API remota. Quando você remove todo o clichê, toda a manipulação de dados, todas as preocupações secundárias, essa classe realmente se resume a chamar wp_remote_request()
para obter um objeto de resposta HTTP da API. Convenientemente, wp_remote_request()
em vez disso, retornará um WP_Error
se a execução da chamada falhar por algum motivo, mas e se a chamada conseguir retornar uma resposta HTTP de um tipo desfavorável?
Como exemplo, talvez tenhamos feito uma chamada para /lists.json
endpoint, mas esta conta em particular ainda não tem nenhuma lista configurada. Isso retornaria uma resposta HTTP válida, mas com um código de status de 400. Embora não seja exatamente um erro fatal em si, da perspectiva de algum código de front-end que deseja transformar essa chamada de API em um menu suspenso, um 400 pode bem ser um WSOD ! Portanto, acho útil fazer algumas análises adicionais no resultado de wp_remote_request()
, potencialmente retornando um WP_Error
Afinal:
url, $this -> args ); $code = wp_remote_retrieve_response_code( $response ); $first_digit = $code[0]; $good_responses = array( 2, 3 ); if( ! in_array( $first_digit, $good_responses ) { $body = wp_remote_retrieve_body( $response ); $out = new WP_Error( $code, $body ); } else { $out = $response; } return $out; } ?>
Esse padrão pode ajudar a simplificar o código que invoca nossa classe chamador, porque sabemos que podemos confiar com segurança em is_wp_error()
antes de prosseguir com nossa produção.
Como cliente, você deve ocasionalmente desempenhar o papel de um usuário mal-intencionado, um usuário confuso e um usuário impaciente. Use o aplicativo de maneiras que ele não deveria ser usado. Faça coisas que seus desenvolvedores não parecem querer que você faça. Observe o que acontece. Você recebe mensagens de erro úteis? Você recebe alguma mensagem de erro? Caso contrário, pode valer a pena patrocinar um corpo de trabalho em torno de um melhor tratamento de erros.
ob_get_clean()
A web programável moderna, onde quase todos os sites consomem as APIs de outros sites e são consumidos por meio de sua própria API, tornou-se uma arena incrivelmente poderosa para o código. Mas é precisamente essa qualidade que também pode torná-lo bastante lento.
princípios de definição de unidade de design
É comum que as solicitações HTTP remotas sejam as partes mais demoradas de um determinado carregamento de página. Por esse motivo, muitos componentes orientados por API são executados via Ajax ou cron. Por exemplo, uma sugestão automática para pesquisar uma lista de assinantes de e-mail provavelmente deve executar ping na fonte de dados remota sob demanda, a cada pressionamento de tecla, em vez de carregar todos os 100.000 assinantes no DOM conforme a página carrega. Se isso não for uma opção, talvez uma grande consulta possa ser sincronizada em uma tarefa cron noturna, de modo que os resultados possam ser obtidos de um espelho local em vez da API remota.
O problema com essa abordagem é que pode ser difícil depurar. Em vez de simplesmente ligar WP_DEBUG
e permitir que as mensagens de erro cheguem à janela do seu navegador, você fica parado olhando no console da rede do navegador ou seguindo um arquivo de log enquanto uma tarefa cron (com sorte?) está em execução. Acho isso desconfortável.
Uma maneira de melhorar essa situação é fazer ligações estratégicas e cuidadosas para error_log()
. Mas, novamente, um problema comum com o registro é que com aplicativos grandes ou ocupados, os registros de erros podem crescer muito grandes, ou crescer muito rapidamente, para serem úteis para monitoramento ou análise. Portanto, temos que ser seletivos com o que registramos, pensando nisso, como fazemos com nossa lógica de aplicativo real . É uma pena ter perdido tempo para registrar algum erro exótico de caso extremo que só parece ocorrer intermitentemente em alguma tarefa cron infrequente apenas para perceber que a verdadeira natureza do bug o escapou mais uma vez porque você falhou em registrar algum membro do array em particular , digamos, do valor ofensivo.
Portanto, minha filosofia tornou-se, Nem sempre registro, mas quando o faço, registro tudo . Em outras palavras, depois de identificar uma função particularmente preocupante, vou registrá-la com a rede mais ampla possível:
var_dump()
Isso equivale a
|_+_|‘ing todo o valor do bug em uma única entrada no arquivo de log de erros.
Como cliente, vale a pena verificar periodicamente o uso total da memória do arquivo para seu aplicativo. Se você perceber que de repente está se chocando contra os limites de armazenamento em sua conta de hospedagem, há uma boa chance de que a culpa seja de um log de erro que enlouqueceu. Seus desenvolvedores se beneficiarão de um ciclo de trabalho focado em um melhor registro - e seus clientes também!
Por favor, perdoe a estrutura do listicle deste artigo. Eu não poderia forçar esses pontos em um tema de artigo mais unificador porque esses padrões são muito genéricos: Eles se aplicam a qualquer endpoint JSON REST e qualquer saída WordPress .
Eles são os padrões que vejo ocorrendo repetidamente, independentemente de qual seja a API remota ou para que a estamos usando no WordPress. Eu fui tão longe a ponto de coletar todos esses tipos de princípios em um clichê de plug-in que acelera muito meu trabalho. Você tem pontos semelhantes que mantém para cada projeto? Por favor, compartilhe-os para que eu possa roubá-los e adicioná-los ao meu clichê!
Relacionado: Como Abordar o Desenvolvimento Moderno de WordPress (Parte 1)Uma maneira conveniente de usar o WordPress para publicar uma API. Essa API pode ser consumida por outros sites WordPress, outros sites não WordPress ou até mesmo pelo próprio site de publicação. Esta é uma abordagem popular para usar o WordPress como um CMS 'sem cabeça' ou mesmo apenas para ouvintes Ajax em pequena escala.
As chaves API são uma forma comum de gerenciar a autenticação. A API do WordPress é compatível com vários métodos de autenticação. Um deles é o plug-in OAuth da API REST do WordPress, que oferece aos usuários uma interface para gerenciar chaves de API.
O WP-JSON pode ser considerado um irmão da visualização RSS do WordPress junto com sua visualização front-end normal. É outra forma de enviar dados do WordPress, embora a maioria dos leitores humanos não queira consumir o WordPress neste formato. Em vez disso, seu objetivo é ser consumido por clientes API.