WordPress sem cabeça: os altos e baixos da criação de um WordPress desacoplado
Publicados: 2022-03-10O WordPress percorreu um longo caminho desde o seu início como uma simples ferramenta de escrita de blog. Longos 15 anos depois, tornou-se a escolha número um de CMS para desenvolvedores e não desenvolvedores. O WordPress agora alimenta cerca de 30% dos 10 milhões de sites da web.
Desde que a API REST foi empacotada no núcleo do WordPress, os desenvolvedores podem experimentá-la e usá-la de forma desacoplada, ou seja, escrevendo a parte front-end usando frameworks ou bibliotecas JavaScript. Na Infinum, estávamos (e ainda estamos) usando o WordPress de uma maneira 'clássica': PHP para frontend e backend. Depois de um tempo, queríamos dar uma chance à abordagem dissociada. Neste artigo, compartilharei uma visão geral do que queríamos alcançar e o que encontramos ao tentar implementar nossos objetivos.
Existem vários tipos de projetos que podem se beneficiar dessa abordagem. Por exemplo, sites de apresentação simples ou sites que usam o WordPress como backend são os principais candidatos para a abordagem desacoplada.
Nos últimos anos, a indústria, felizmente, começou a prestar mais atenção ao desempenho. No entanto, sendo um software inclusivo e versátil, fácil de usar, o WordPress vem com uma infinidade de opções que não são necessariamente utilizadas em cada projeto. Como resultado, o desempenho do site pode sofrer.
Leitura recomendada : Como usar mapas de calor para rastrear cliques em seu site WordPress
Se os longos tempos de resposta do site o mantêm acordado à noite, este é um tutorial para você. Abordarei o básico da criação de um WordPress desacoplado e algumas lições aprendidas, incluindo:
- O significado de um “WordPress desacoplado”
- Trabalhando com a API REST padrão do WordPress
- Melhorando o desempenho com a abordagem JSON desacoplada
- Preocupações com segurança
Então, o que exatamente é um WordPress desacoplado?
Quando se trata de como o WordPress é programado, uma coisa é certa: ele não segue o padrão de design Model- V iew - C ontroller (MVC) com o qual muitos desenvolvedores estão familiarizados. Por causa de sua história e por ser uma espécie de bifurcação de uma antiga plataforma de blogs chamada “b2” (mais detalhes aqui), é em grande parte escrito de forma procedural (usando código baseado em funções). Os desenvolvedores principais do WordPress usaram um sistema de ganchos que permitia que outros desenvolvedores modificassem ou estendessem certas funcionalidades.
É um sistema tudo-em-um equipado com uma interface administrativa funcional; ele gerencia a conexão do banco de dados e tem várias APIs úteis expostas que lidam com autenticação de usuários, roteamento e muito mais.
Mas, graças à API REST, você pode separar o back-end do WordPress como uma espécie de modelo e controlador agrupados que lidam com manipulação de dados e interação com o banco de dados e usar o REST API Controller para interagir com uma camada de visualização separada usando vários endpoints da API. Além da separação do MVC, podemos (por motivos de segurança ou melhorias de velocidade) colocar o JS App em um servidor separado como no esquema abaixo:

Vantagens de usar a abordagem desacoplada
Um motivo pelo qual você pode querer usar essa abordagem é garantir uma separação de preocupações. O front-end e o back-end estão interagindo por meio de endpoints; cada um pode estar em seu servidor separado que pode ser otimizado especificamente para cada tarefa respectiva, ou seja, executando separadamente um aplicativo PHP e executando um aplicativo Node.js.
Ao separar seu front-end do back-end, é mais fácil redesenhá-lo no futuro, sem alterar o CMS. Além disso, os desenvolvedores front-end só precisam se preocupar com o que fazer com os dados que o back-end fornece a eles. Isso permite que eles sejam criativos e usem bibliotecas modernas como ReactJS, Vue ou Angular para fornecer aplicativos da Web altamente dinâmicos. Por exemplo, é mais fácil criar um aplicativo da Web progressivo ao usar as bibliotecas mencionadas.
Outra vantagem se reflete na segurança do site. Explorar o site por meio do back-end se torna mais difícil, pois é amplamente oculto do público.
Leitura recomendada : Segurança do WordPress como um processo
Desvantagens do uso da abordagem desacoplada
Primeiro, ter um WordPress desacoplado significa manter duas instâncias separadas:
- WordPress para o backend;
- Um aplicativo front-end separado, incluindo atualizações de segurança oportunas.
Em segundo lugar, algumas das bibliotecas front-end têm uma curva de aprendizado mais acentuada. Levará muito tempo para aprender um novo idioma (se você estiver acostumado apenas a HTML e CSS para modelagem) ou exigirá trazer especialistas adicionais em JavaScript para o projeto.
Terceiro, ao separar o frontend, você está perdendo o poder do editor WYSIWYG, e o botão 'Live Preview' no WordPress também não funciona.
Trabalhando com a API REST do WordPress
Antes de nos aprofundarmos no código, mais algumas coisas sobre a API REST do WordPress. O poder total da API REST no WordPress veio com a versão 4.7 em 6 de dezembro de 2016.
O que a API REST do WordPress permite que você faça é interagir remotamente com sua instalação do WordPress enviando e recebendo objetos JSON.
Configurando um projeto
Como ele vem com a instalação mais recente do WordPress, estaremos trabalhando no tema Twenty Seventeen. Estou trabalhando em Varying Vagrant Vagrants e configurei um site de teste com uma URL https://dev.wordpress.test/
. Este URL será usado em todo o artigo. Também importaremos postagens do repositório do Wordpress.org Theme Review Teams para que tenhamos alguns dados de teste com os quais trabalhar. Mas primeiro, vamos nos familiarizar com o trabalho com endpoints padrão e, em seguida, criaremos nosso próprio endpoint personalizado.
Acesse o endpoint REST padrão
Como já mencionado, o WordPress vem com vários endpoints integrados que você pode examinar acessando a rota /wp-json/
:
https://dev.wordpress.test/wp-json/
Colocando esse URL diretamente no seu navegador ou adicionando-o no aplicativo carteiro, você receberá uma resposta JSON da API REST do WordPress que se parece com isso:
{ "name": "Test dev site", "description": "Just another WordPress site", "url": "https://dev.wordpress.test", "home": "https://dev.wordpress.test", "gmt_offset": "0", "timezone_string": "", "namespaces": [ "oembed/1.0", "wp/v2" ], "authentication": [], "routes": { "/": { "namespace": "", "methods": [ "GET" ], "endpoints": [ { "methods": [ "GET" ], "args": { "context": { "required": false, "default": "view" } } } ], "_links": { "self": "https://dev.wordpress.test/wp-json/" } }, "/oembed/1.0": { "namespace": "oembed/1.0", "methods": [ "GET" ], "endpoints": [ { "methods": [ "GET" ], "args": { "namespace": { "required": false, "default": "oembed/1.0" }, "context": { "required": false, "default": "view" } } } ], "_links": { "self": "https://dev.wordpress.test/wp-json/oembed/1.0" } }, ... "wp/v2": { ...
Portanto, para obter todas as postagens em nosso site usando REST, precisaríamos acessar https://dev.wordpress.test/wp-json/wp/v2/posts
. Observe que o wp/v2/
marca os endpoints principais reservados, como postagens, páginas, mídia, taxonomias, categorias e assim por diante.
Então, como adicionamos um endpoint personalizado?
Criar um endpoint REST personalizado
Digamos que queremos adicionar um novo endpoint ou campo adicional ao endpoint existente. Existem várias maneiras de fazermos isso. Primeiro, isso pode ser feito automaticamente ao criar um tipo de postagem personalizado. Por exemplo, queremos criar um endpoint de documentação. Vamos criar um pequeno plugin de teste. Crie uma pasta test-documentation na pasta wp-content/plugins e adicione o arquivo documentation.php que se parece com isso:
<?php /** * Test plugin * * @since 1.0.0 * @package test_plugin * * @wordpress-plugin * Plugin Name: Test Documentation Plugin * Plugin URI: * Description: The test plugin that adds rest functionality * Version: 1.0.0 * Author: Infinum <[email protected]> * Author URI: https://infinum.co/ * License: GPL-2.0+ * License URI: https://www.gnu.org/licenses/gpl-2.0.txt * Text Domain: test-plugin */ namespace Test_Plugin; // If this file is called directly, abort. if ( ! defined( 'WPINC' ) ) { die; } /** * Class that holds all the necessary functionality for the * documentation custom post type * * @since 1.0.0 */ class Documentation { /** * The custom post type slug * * @var string * * @since 1.0.0 */ const PLUGIN_NAME = 'documentation-plugin'; /** * The custom post type slug * * @var string * * @since 1.0.0 */ const POST_TYPE_SLUG = 'documentation'; /** * The custom taxonomy type slug * * @var string * * @since 1.0.0 */ const TAXONOMY_SLUG = 'documentation-category'; /** * Register custom post type * * @since 1.0.0 */ public function register_post_type() { $args = array( 'label' => esc_html( 'Documentation', 'test-plugin' ), 'public' => true, 'menu_position' => 47, 'menu_icon' => 'dashicons-book', 'supports' => array( 'title', 'editor', 'revisions', 'thumbnail' ), 'has_archive' => false, 'show_in_rest' => true, 'publicly_queryable' => false, ); register_post_type( self::POST_TYPE_SLUG, $args ); } /** * Register custom tag taxonomy * * @since 1.0.0 */ public function register_taxonomy() { $args = array( 'hierarchical' => false, 'label' => esc_html( 'Documentation tags', 'test-plugin' ), 'show_ui' => true, 'show_admin_column' => true, 'update_count_callback' => '_update_post_term_count', 'show_in_rest' => true, 'query_var' => true, ); register_taxonomy( self::TAXONOMY_SLUG, [ self::POST_TYPE_SLUG ], $args ); } } $documentation = new Documentation(); add_action( 'init', [ $documentation, 'register_post_type' ] ); add_action( 'init', [ $documentation, 'register_taxonomy' ] );
Ao registrar o novo tipo de postagem e taxonomia e definir o argumento show_in_rest
como true
, o WordPress criou automaticamente uma rota REST no namespace /wp/v2/
. Agora você tem https://dev.wordpress.test/wp-json/wp/v2/documentation
e https://dev.wordpress.test/wp-json/wp/v2/documentation-category
endpoints disponíveis. Se adicionarmos uma postagem em nossa postagem personalizada de documentação recém-criada indo para https://dev.wordpress.test/?post_type=documentation
, ela nos dará uma resposta parecida com esta:
[ { "id": 4, "date": "2018-06-11T19:48:51", "date_gmt": "2018-06-11T19:48:51", "guid": { "rendered": "https://dev.wordpress.test/?post_type=documentation&p=4" }, "modified": "2018-06-11T19:48:51", "modified_gmt": "2018-06-11T19:48:51", "slug": "test-documentation", "status": "publish", "type": "documentation", "link": "https://dev.wordpress.test/documentation/test-documentation/", "title": { "rendered": "Test documentation" }, "content": { "rendered": "
Este é algum conteúdo de documentação
\n", "protegido": falso }, "featured_media": 0, "modelo": "", "categoria-documentação": [ 2 ], "_links": { "auto": [ { "href": "https://dev.wordpress.test/wp-json/wp/v2/documentation/4" } ], "coleção": [ { "href": "https://dev.wordpress.test/wp-json/wp/v2/documentation" } ], "cerca de": [ { "href": "https://dev.wordpress.test/wp-json/wp/v2/types/documentation" } ], "versão-histórico": [ { "href": "https://dev.wordpress.test/wp-json/wp/v2/documentation/4/revisions" } ], "wp: anexo": [ { "href": "https://dev.wordpress.test/wp-json/wp/v2/media?parent=4" } ], "wp:termo": [ { "taxonomia": "categoria-documentação", "incorporável": verdadeiro, "href": "https://dev.wordpress.test/wp-json/wp/v2/documentation-category?post=4" } ], "curios": [ { "nome": "wp", "href": "https://api.w.org/{rel}", "modelado": verdadeiro } ] } } ]
Este é um ótimo ponto de partida para nosso aplicativo de página única. Outra maneira de adicionar um endpoint personalizado é conectando ao gancho rest_api_init
e criando um endpoint nós mesmos. Vamos adicionar uma rota custom-documentation
um pouco diferente daquela que registramos. Ainda trabalhando no mesmo plugin, podemos adicionar:
/** * Create a custom endpoint * * @since 1.0.0 */ public function create_custom_documentation_endpoint() { register_rest_route( self::PLUGIN_NAME . '/v1', '/custom-documentation', array( 'methods' => 'GET', 'callback' => [ $this, 'get_custom_documentation' ], ) ); } /** * Create a callback for the custom documentation endpoint * * @return string JSON that indicates success/failure of the update, * or JSON that indicates an error occurred. * @since 1.0.0 */ public function get_custom_documentation() { /* Some permission checks can be added here. */ // Return only documentation name and tag name. $doc_args = array( 'post_type' => self::POST_TYPE_SLUG, 'post_status' => 'publish', 'perm' => 'readable' ); $query = new \WP_Query( $doc_args ); $response = []; $counter = 0; // The Loop if ( $query->have_posts() ) { while ( $query->have_posts() ) { $query->the_post(); $post_id = get_the_ID(); $post_tags = get_the_terms( $post_id, self::TAXONOMY_SLUG ); $response[ $counter ]['title'] = get_the_title(); foreach ( $post_tags as $tags_key => $tags_value ) { $response[ $counter ]['tags'][] = $tags_value->name; } $counter++; } } else { $response = esc_html__( 'There are no posts.', 'documentation-plugin' ); } /* Restore original Post Data */ wp_reset_postdata(); return rest_ensure_response( $response ); }
E conecte o método create_custom_documentation_endpoint()
ao gancho rest_api_init
, assim:
add_action( 'rest_api_init', [ $documentation, 'create_custom_documentation_endpoint' ] );
Isso adicionará uma rota personalizada em https://dev.wordpress.test/wp-json/documentation-plugin/v1/custom-documentation
com o retorno de chamada retornando a resposta para essa rota.
[{ "title": "Another test documentation", "tags": ["Another tag"] }, { "title": "Test documentation", "tags": ["REST API", "test tag"] }]
Há muitas outras coisas que você pode fazer com a API REST (você pode encontrar mais detalhes no manual da API REST).
Contorne tempos de resposta longos ao usar a API REST padrão
Para quem já tentou construir um site WordPress desacoplado, isso não é novidade – a API REST é lenta.
Minha equipe e eu encontramos pela primeira vez a estranha API REST com atraso do WordPress em um site de cliente (não desacoplado), onde usamos os endpoints personalizados para obter a lista de locais em um mapa do Google, juntamente com outras informações meta criadas usando o Advanced Custom Fields Pro plugar. Descobriu-se que o tempo do primeiro byte (TTFB) — que é usado como indicação da capacidade de resposta de um servidor web ou outro recurso de rede — levou mais de 3 segundos.
Após um pouco de investigação, percebemos que as chamadas padrão da API REST eram realmente muito lentas, especialmente quando “sobrecarregamos” o site com plugins adicionais. Então, fizemos um pequeno teste. Instalamos alguns plugins populares e encontramos alguns resultados interessantes. O aplicativo carteiro deu o tempo de carregamento de 1,97s para 41,9KB de tamanho de resposta. O tempo de carregamento do Chrome foi de 1,25s (TTFB foi de 1,25s, o conteúdo foi baixado em 3,96ms). Apenas para recuperar uma simples lista de posts. Sem taxonomia, sem dados do usuário, sem meta campos adicionais.

Por quê isso aconteceu?
Acontece que acessar a API REST no WordPress padrão carregará todo o núcleo do WordPress para servir os endpoints, mesmo que não seja usado. Além disso, quanto mais plugins você adiciona, pior as coisas ficam. O controlador REST padrão WP_REST_Controller
é uma classe muito grande que faz muito mais do que o necessário ao construir uma página web simples. Ele lida com registro de rotas, verificações de permissão, criação e exclusão de itens e assim por diante.
Há duas soluções comuns para esse problema:
- Intercepte o carregamento dos plugins e evite carregá-los todos quando precisar servir uma resposta REST simples;
- Carregue apenas o mínimo do WordPress e armazene os dados em um transiente, do qual buscamos os dados usando uma página personalizada.
Melhorando o desempenho com a abordagem JSON desacoplada
Ao trabalhar com sites de apresentação simples, você não precisa de todas as funcionalidades que a API REST oferece. Claro, é aqui que um bom planejamento é crucial. Você realmente não quer construir seu site sem a API REST e depois dizer daqui a alguns anos que gostaria de se conectar ao seu site ou talvez criar um aplicativo móvel que precise usar a funcionalidade da API REST. Você?
Por esse motivo, utilizamos dois recursos do WordPress que podem ajudá-lo ao fornecer dados JSON simples:
- API de transitórios para armazenamento em cache,
- Carregando o WordPress mínimo necessário usando a constante
SHORTINIT
.
Criando um endpoint de páginas desacopladas simples
Vamos criar um pequeno plugin que irá demonstrar o efeito que estamos falando. Primeiro, adicione um arquivo wp-config-simple.php em seu plugin json-transient
que se parece com isso:
<?php /** * Create simple wp configuration for the routes * * @since 1.0.0 * @package json-transient */ define( 'SHORTINIT', true ); $parse_uri = explode( 'wp-content', $_SERVER['SCRIPT_FILENAME'] ); require_once filter_var( $parse_uri[0] . 'wp-load.php', FILTER_SANITIZE_STRING );
O define( 'SHORTINIT', true );
impedirá que a maioria dos arquivos principais do WordPress sejam carregados, como pode ser visto no arquivo wp-settings.php .
Ainda podemos precisar de algumas funcionalidades do WordPress, então podemos exigir o arquivo (como wp-load.php ) manualmente. Como o wp-load.php fica na raiz da nossa instalação do WordPress, vamos buscá-lo obtendo o caminho do nosso arquivo usando $_SERVER['SCRIPT_FILENAME']
e, em seguida, explodindo essa string pela string wp-content
. Isso retornará uma matriz com dois valores:
- A raiz da nossa instalação;
- O resto do caminho do arquivo (que não nos interessa).
Tenha em mente que estamos usando a instalação padrão do WordPress, e não uma modificada, como por exemplo no clichê Bedrock, que divide o WordPress em uma organização de arquivos diferente.
Por fim, exigimos o arquivo wp-load.php , com um pouco de sanitização, por segurança.
Em nosso arquivo init.php , adicionaremos o seguinte:
* Author URI: https://infinum.co/ * License: GPL-2.0+ * License URI: https://www.gnu.org/licenses/gpl-2.0.txt * Text Domain: json-transient */ namespace Json_Transient; // If this file is called directly, abort. if ( ! defined( 'WPINC' ) ) { die; } class Init { /** * Get the array of allowed types to do operations on. * * @return array * * @since 1.0.0 */ public function get_allowed_post_types() { return array( 'post', 'page' ); } /** * Check if post type is allowed to be save in transient. * * @param string $post_type Get post type. * @return boolean * * @since 1.0.0 */ public function is_post_type_allowed_to_save( $post_type = null ) { if( ! $post_type ) { return false; } $allowed_types = $this->get_allowed_post_types(); if ( in_array( $post_type, $allowed_types, true ) ) { return true; } return false; } /** * Get Page cache name for transient by post slug and type. * * @param string $post_slug Page Slug to save. * @param string $post_type Page Type to save. * @return string * * @since 1.0.0 */ public function get_page_cache_name_by_slug( $post_slug = null, $post_type = null ) { if( ! $post_slug || ! $post_type ) { return false; } $post_slug = str_replace( '__trashed', '', $post_slug ); return 'jt_data_' . $post_type . '_' . $post_slug; } /** * Get full post data by post slug and type. * * @param string $post_slug Page Slug to do Query by. * @param string $post_type Page Type to do Query by. * @return array * * @since 1.0.0 */ public function get_page_data_by_slug( $post_slug = null, $post_type = null ) { if( ! $post_slug || ! $post_type ) { return false; } $page_output = ''; $args = array( 'name' => $post_slug, 'post_type' => $post_type, 'posts_per_page' => 1, 'no_found_rows' => true ); $the_query = new \WP_Query( $args ); if ( $the_query->have_posts() ) { while ( $the_query->have_posts() ) { $the_query->the_post(); $page_output = $the_query->post; } wp_reset_postdata(); } return $page_output; } /** * Return Page in JSON format * * @param string $post_slug Page Slug. * @param string $post_type Page Type. * @return json * * @since 1.0.0 */ public function get_json_page( $post_slug = null, $post_type = null ) { if( ! $post_slug || ! $post_type ) { return false; } return wp_json_encode( $this->get_page_data_by_slug( $post_slug, $post_type ) ); } /** * Update Page to transient for caching on action hooks save_post. * * @param int $post_id Saved Post ID provided by action hook. * * @since 1.0.0 */ public function update_page_transient( $post_id ) { $post_status = get_post_status( $post_id ); $post = get_post( $post_id ); $post_slug = $post->post_name; $post_type = $post->post_type; $cache_name = $this->get_page_cache_name_by_slug( $post_slug, $post_type ); if( ! $cache_name ) { return false; } if( $post_status === 'auto-draft' || $post_status === 'inherit' ) { return false; } else if( $post_status === 'trash' ) { delete_transient( $cache_name ); } else { if( $this->is_post_type_allowed_to_save( $post_type ) ) { $cache = $this->get_json_page( $post_slug, $post_type ); set_transient( $cache_name, $cache, 0 ); } } } } $init = new Init(); add_action( 'save_post', [ $init, 'update_page_transient' ] );
Os métodos auxiliares no código acima nos permitirão fazer algum cache:
-
get_allowed_post_types()
Este método permite que os tipos de postagem saibam que queremos habilitar a exibição em nosso 'endpoint' personalizado. Você pode estender isso, e o plug-in, na verdade, tornamos esse método filtrável para que você possa usar um filtro para adicionar itens adicionais. -
is_post_type_allowed_to_save()
Este método simplesmente verifica se o tipo de postagem do qual estamos tentando buscar os dados está na matriz permitida especificada pelo método anterior. -
get_page_cache_name_by_slug()
Este método retornará o nome do transiente do qual os dados serão buscados. -
get_page_data_by_slug()
Este método é o método que irá realizar aWP_Query
no post através de seu tipo slug e post e retornará o conteúdo do array post que converteremos com o JSON usando o métodoget_json_page()
. -
update_page_transient()
Isso será executado no ganchosave_post
e substituirá o transiente no banco de dados com os dados JSON do nosso post. Este último método é conhecido como o “método de cache de chave”.
Vamos explicar os transientes com mais profundidade.
API de transitórios
A API Transients é usada para armazenar dados na tabela de opções do seu banco de dados WordPress por um período específico de tempo. É um cache de objeto persistente, o que significa que você está armazenando algum objeto, por exemplo, resultados de consultas grandes e lentas ou páginas inteiras que podem ser persistidas em carregamentos de página. É semelhante ao WordPress Object Cache normal, mas ao contrário WP_Cache
, os transientes persistirão os dados nos carregamentos da página, onde o WP_Cache
(armazenando os dados na memória) manterá os dados apenas pela duração de uma solicitação.
É um armazenamento de valor-chave, o que significa que podemos buscar os dados desejados com facilidade e rapidez, semelhante ao que in-memory caching systems
como Memcached ou Redis, fazem. A diferença é que você normalmente precisa instalá-los separadamente no servidor (o que pode ser um problema em servidores compartilhados), enquanto os transientes são integrados ao WordPress.
Conforme observado em sua página do Codex — os transientes são inerentemente acelerados por plugins de cache. Uma vez que eles podem armazenar transientes na memória em vez de um banco de dados. A regra geral é que você não deve presumir que o transiente esteja sempre presente no banco de dados — e é por isso que é uma boa prática verificar sua existência antes de buscá-lo
$transient_name = get_transient( 'transient_name' ); if ( $transient_name === false ) { set_transient( 'transient_name', $transient_data, $transient_expiry ); }
Você pode usá-lo sem expiração (como estamos fazendo), e é por isso que implementamos uma espécie de 'cache-busting' no post save. Além de todas as ótimas funcionalidades que eles oferecem, eles podem armazenar até 4 GB de dados, mas não recomendamos armazenar nada tão grande em um único campo de banco de dados.
Leitura recomendada : Fique atento: Funções PHP e WordPress que podem tornar seu site inseguro
Ponto de extremidade final: teste e verificação
A última peça do quebra-cabeça que precisamos é um 'ponto final'. Estou usando o termo endpoint aqui, embora não seja um endpoint, pois estamos chamando diretamente um arquivo específico para buscar nossos resultados. Assim, podemos criar um arquivo test.php que se parece com isso:
get_page_cache_name_by_slug( $post_slug, $post_type ) ); // Return error on false. if ( $cache === false ) { wp_send_json( 'Error, the page does not exist or it is not cached correctly. Please try rebuilding cache and try again!' ); } // Decode json for output. wp_send_json( json_decode( $cache ) );
Se formos para https://dev.wordpress.test/wp-content/plugins/json-transient/test.php
, veremos esta mensagem:
Erro, slug de página ou tipo está faltando!
Portanto, precisaremos especificar o tipo de postagem e o slug de postagem. Quando agora formos para https://dev.wordpress.test/wp-content/plugins/json-transient/test.php?slug=hello-world&type=post
veremos:
Erro, a página não existe ou não está armazenada em cache corretamente. Tente reconstruir o cache e tente novamente!
Oh espere! Precisamos salvar novamente nossas páginas e postagens primeiro. Então, quando você está começando, isso pode ser fácil. Mas se você já tem mais de 100 páginas ou postagens, isso pode ser uma tarefa desafiadora. É por isso que implementamos uma maneira de limpar os transientes no plug-in Decoupled JSON Content e reconstruí-los em um lote.
Mas vá em frente e salve novamente a postagem Hello World e abra o link novamente. O que você deve ter agora é algo parecido com isto:
{ "ID": 1, "post_author": "1", "post_date": "2018-06-26 18:28:57", "post_date_gmt": "2018-06-26 18:28:57", "post_content": "Welcome to WordPress. This is your first post. Edit or delete it, then start writing!", "post_title": "Hello world!", "post_excerpt": "", "post_status": "publish", "comment_status": "open", "ping_status": "open", "post_password": "", "post_name": "hello-world", "to_ping": "", "pinged": "", "post_modified": "2018-06-30 08:34:52", "post_modified_gmt": "2018-06-30 08:34:52", "post_content_filtered": "", "post_parent": 0, "guid": "http:\/\/dev.wordpress.test\/?p=1", "menu_order": 0, "post_type": "post", "post_mime_type": "", "comment_count": "1", "filter": "raw" }
E é isso. O plugin que criamos tem mais algumas funcionalidades extras que você pode usar, mas em poucas palavras, é assim que você pode buscar os dados JSON do seu WordPress que é muito mais rápido do que usar a API REST.
Antes e depois: tempo de resposta aprimorado
Realizamos testes no Chrome, onde pudemos ver o tempo total de resposta e o TTFB separadamente. Testamos os tempos de resposta dez vezes seguidas: primeiro sem plugins e depois com os plugins adicionados. Além disso, testamos a resposta para uma lista de postagens e para uma única postagem.
Os resultados do teste estão ilustrados nas tabelas abaixo:


Como você pode ver, a diferença é drástica.
Preocupações com segurança
Existem algumas ressalvas que você precisa dar uma boa olhada. Em primeiro lugar, estamos carregando manualmente os arquivos principais do WordPress, que no mundo WordPress é um grande não-não. Por quê? Bem, além do fato de que buscar manualmente os arquivos principais pode ser complicado (especialmente se você estiver usando instalações fora do padrão, como o Bedrock), isso pode representar algumas preocupações de segurança.
Se você decidir usar o método descrito neste artigo, certifique-se de saber como fortalecer a segurança do servidor.
Primeiro, adicione cabeçalhos HTML como no arquivo test.php :
header( 'Access-Control-Allow-Origin: your-front-end-app.url' ); header( 'Content-Type: application/json' );
O primeiro cabeçalho é uma maneira de contornar a medida de segurança CORS para que apenas seu aplicativo front-end possa buscar o conteúdo ao acessar o arquivo especificado.
Segundo, desative a passagem de diretório do seu aplicativo. Você pode fazer isso modificando as configurações do nginx
ou adicionando Options -Indexes
ao seu arquivo .htaccess se estiver em um servidor Apache.
Adicionar uma verificação de token à resposta também é uma boa medida que pode impedir o acesso indesejado. Na verdade, estamos trabalhando em uma maneira de modificar nosso plug-in JSON desacoplado para que possamos incluir essas medidas de segurança por padrão.
Uma verificação de um cabeçalho de autorização enviado pelo aplicativo front-end pode ter esta aparência:
if ( ! isset( $_SERVER['HTTP_AUTHORIZATION'] ) ) { return; } $auth_header = $_SERVER['HTTP_AUTHORIZATION'];
Em seguida, você pode verificar se o token específico (um segredo que é compartilhado apenas pelos aplicativos front-end e back-end) foi fornecido e está correto.
Conclusão
A API REST é ótima porque pode ser usada para criar aplicativos completos — criando, recuperando, atualizando e excluindo os dados. A desvantagem de usá-lo é a sua velocidade.
Obviamente, criar um aplicativo é diferente de criar um site clássico. Você provavelmente não precisará de todos os plugins que instalamos. Mas se você só precisa dos dados para fins de apresentação, armazenar dados em cache e servi-los em um arquivo personalizado parece ser a solução perfeita no momento, ao trabalhar com sites desacoplados.
Você pode estar pensando que criar um plugin personalizado para acelerar o tempo de resposta do site é um exagero, mas vivemos em um mundo em que cada segundo conta. Todo mundo sabe que se um site for lento, os usuários irão abandoná-lo. Existem muitos estudos que demonstram a conexão entre o desempenho do site e as taxas de conversão. Mas se você ainda precisa de convencimento, o Google penaliza sites lentos.
O método explicado neste artigo resolve o problema de velocidade que a API REST do WordPress encontra e lhe dará um impulso extra ao trabalhar em um projeto WordPress desacoplado. Como estamos em nossa busca sem fim para extrair o último milissegundo de cada solicitação e resposta, planejamos otimizar ainda mais o plug-in. Enquanto isso, compartilhe suas ideias sobre como acelerar o WordPress desacoplado!