WordPress sin cabeza: los altibajos de crear un WordPress desacoplado

Publicado: 2022-03-10
Resumen rápido ↬ Todo el mundo sabe que si un sitio web es lento, los usuarios lo abandonarán. Muchos estudios demuestran la conexión entre el rendimiento del sitio web y las tasas de conversión. En este artículo, Denis Zoljom comparte su experiencia y los conceptos básicos para crear un WordPress desacoplado.

WordPress recorrió un largo camino desde sus inicios como una simple herramienta de escritura de blogs. 15 largos años después, se convirtió en la opción número uno de CMS para desarrolladores y no desarrolladores por igual. WordPress ahora impulsa aproximadamente el 30% de los 10 millones de sitios principales en la web.

Desde que la API REST se incluyó en el núcleo de WordPress, los desarrolladores pueden experimentar y usarla de forma desacoplada, es decir, escribiendo la parte frontal mediante el uso de marcos o bibliotecas de JavaScript. En Infinum, estábamos (y todavía estamos) usando WordPress de una manera 'clásica': PHP tanto para el frontend como para el backend. Después de un tiempo, queríamos probar el enfoque desacoplado. En este artículo, compartiré una descripción general de lo que queríamos lograr y lo que encontramos al intentar implementar nuestros objetivos.

Hay varios tipos de proyectos que pueden beneficiarse de este enfoque. Por ejemplo, los sitios de presentación simple o los sitios que usan WordPress como backend son los principales candidatos para el enfoque desacoplado.

En los últimos años, afortunadamente, la industria comenzó a prestar más atención al rendimiento. Sin embargo, al ser un software versátil, inclusivo y fácil de usar, WordPress viene con una gran cantidad de opciones que no se utilizan necesariamente en todos y cada uno de los proyectos. Como resultado, el rendimiento del sitio web puede verse afectado.

Lectura recomendada : Cómo usar mapas de calor para rastrear los clics en su sitio web de WordPress

Si los largos tiempos de respuesta del sitio web lo mantienen despierto por la noche, este es un procedimiento para usted. Cubriré los conceptos básicos de la creación de un WordPress desacoplado y algunas lecciones aprendidas, que incluyen:

  1. El significado de un “WordPress desacoplado”
  2. Trabajar con la API REST predeterminada de WordPress
  3. Mejora del rendimiento con el enfoque JSON desacoplado
  4. Preocupaciones de seguridad
¡Más después del salto! Continúe leyendo a continuación ↓

Entonces, ¿qué es exactamente un WordPress desacoplado?

Cuando se trata de cómo se programa WordPress, una cosa es cierta: no sigue el patrón de diseño Modelo- V ista - Controlador (MVC) con el que muchos desarrolladores están familiarizados. Debido a su historia y por ser una especie de bifurcación de una antigua plataforma de blogs llamada “b2” (más detalles aquí), está escrito en gran medida de manera procedimental (usando código basado en funciones). Los desarrolladores principales de WordPress utilizaron un sistema de ganchos que permitía a otros desarrolladores modificar o ampliar ciertas funcionalidades.

Es un sistema todo en uno que está equipado con una interfaz de administración en funcionamiento; administra la conexión de la base de datos y tiene un montón de API útiles expuestas que manejan la autenticación del usuario, el enrutamiento y más.

Pero gracias a la API REST, puede separar el backend de WordPress como una especie de modelo y controlador agrupados que manejan la manipulación de datos y la interacción con la base de datos, y usar el controlador API REST para interactuar con una capa de vista separada usando varios puntos finales API. Además de la separación de MVC, podemos (por razones de seguridad o mejoras de velocidad) colocar la aplicación JS en un servidor separado como en el esquema a continuación:

Imagen que muestra el diagrama de WordPress desacoplado con la parte de PHP y JS separada
Diagrama de WordPress desacoplado. (Vista previa grande)

Ventajas de usar el enfoque desacoplado

Una de las razones por las que es posible que desee utilizar este enfoque es para garantizar una separación de preocupaciones. El frontend y el backend interactúan a través de puntos finales; cada uno puede estar en su servidor separado que se puede optimizar específicamente para cada tarea respectiva, es decir, ejecutar una aplicación PHP y ejecutar una aplicación Node.js por separado.

Al separar su frontend del backend, es más fácil rediseñarlo en el futuro, sin cambiar el CMS. Además, los desarrolladores front-end solo deben preocuparse por qué hacer con los datos que les proporciona el backend. Esto les permite ser creativos y usar bibliotecas modernas como ReactJS, Vue o Angular para ofrecer aplicaciones web altamente dinámicas. Por ejemplo, es más fácil crear una aplicación web progresiva cuando se usan las bibliotecas antes mencionadas.

Otra ventaja se refleja en la seguridad del sitio web. Explotar el sitio web a través del backend se vuelve más difícil ya que en gran medida está oculto al público.

Lectura recomendada : La seguridad de WordPress como proceso

Deficiencias del uso del enfoque desacoplado

Primero, tener un WordPress desacoplado significa mantener dos instancias separadas:

  1. WordPress para el backend;
  2. Una aplicación front-end separada, que incluye actualizaciones de seguridad oportunas.

En segundo lugar, algunas de las bibliotecas frontales tienen una curva de aprendizaje más pronunciada. Tomará mucho tiempo aprender un nuevo idioma (si solo está acostumbrado a HTML y CSS para las plantillas), o requerirá la incorporación de expertos en JavaScript adicionales al proyecto.

En tercer lugar, al separar la interfaz, está perdiendo el poder del editor WYSIWYG, y el botón 'Vista previa en vivo' en WordPress tampoco funciona.

Trabajar con la API REST de WordPress

Antes de profundizar en el código, un par de cosas más sobre la API REST de WordPress. Todo el poder de la API REST en WordPress llegó con la versión 4.7 el 6 de diciembre de 2016.

Lo que la API REST de WordPress le permite hacer es interactuar con su instalación de WordPress de forma remota enviando y recibiendo objetos JSON.

Configuración de un proyecto

Dado que viene incluido con la última instalación de WordPress, trabajaremos en el tema Twenty Seventeen. Estoy trabajando en Varying Vagrant Vagrants y he configurado un sitio de prueba con una URL https://dev.wordpress.test/ . Esta URL se utilizará en todo el artículo. También importaremos publicaciones del repositorio de equipos de revisión de temas de wordpress.org para que tengamos algunos datos de prueba con los que trabajar. Pero primero, nos familiarizaremos con el trabajo con puntos finales predeterminados y luego crearemos nuestro propio punto final personalizado.

Acceda al punto final REST predeterminado

Como ya se mencionó, WordPress viene con varios puntos finales incorporados que puede examinar yendo a la ruta /wp-json/ :

 https://dev.wordpress.test/wp-json/

Ya sea colocando esta URL directamente en su navegador o agregándola en la aplicación de cartero, obtendrá una respuesta JSON de la API REST de WordPress que se parece a esto:

 { "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": { ...

Entonces, para obtener todas las publicaciones en nuestro sitio usando REST, tendríamos que ir a https://dev.wordpress.test/wp-json/wp/v2/posts . Tenga en cuenta que wp/v2/ marca los extremos principales reservados, como publicaciones, páginas, medios, taxonomías, categorías, etc.

Entonces, ¿cómo agregamos un punto final personalizado?

Crear un punto final REST personalizado

Digamos que queremos agregar un nuevo punto final o un campo adicional al punto final existente. Hay varias maneras en que podemos hacer eso. Primero, uno se puede hacer automáticamente al crear un tipo de publicación personalizada. Por ejemplo, queremos crear un punto final de documentación. Vamos a crear un pequeño complemento de prueba. Cree una carpeta de documentación de prueba en la carpeta wp-content/plugins y agregue el archivo documentation.php que se ve así:

 <?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' ] );

Al registrar el nuevo tipo de publicación y la taxonomía, y establecer el argumento show_in_rest en true , WordPress creó automáticamente una ruta REST en el espacio de nombres /wp/v2/ . Ahora tiene https://dev.wordpress.test/wp-json/wp/v2/documentation y https://dev.wordpress.test/wp-json/wp/v2/documentation-category puntos finales disponibles. Si agregamos una publicación en nuestra publicación personalizada de documentación recién creada que va a https://dev.wordpress.test/?post_type=documentation , nos dará una respuesta similar a 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 es un contenido de documentación.

\norte", "protegido": falso }, "medios_presentados": 0, "plantilla": "", "categoría-documentación": [ 2 ], "_Enlaces": { "uno mismo": [ { "href": "https://dev.wordpress.test/wp-json/wp/v2/documentation/4" } ], "colección": [ { "href": "https://dev.wordpress.test/wp-json/wp/v2/documentation" } ], "sobre": [ { "href": "https://dev.wordpress.test/wp-json/wp/v2/types/documentation" } ], "historial de versiones": [ { "href": "https://dev.wordpress.test/wp-json/wp/v2/documentation/4/revisions" } ], "wp: archivo adjunto": [ { "href": "https://dev.wordpress.test/wp-json/wp/v2/media?parent=4" } ], "wp:término": [ { "taxonomy": "documentation-category", "incrustable": cierto, "href": "https://dev.wordpress.test/wp-json/wp/v2/documentation-category?post=4" } ], "curios": [ { "nombre": "wp", "href": "https://api.w.org/{rel}", "plantillado": verdadero } ] } } ]

Este es un excelente punto de partida para nuestra aplicación de una sola página. Otra forma en que podemos agregar un punto final personalizado es conectarnos al gancho rest_api_init y crear un punto final nosotros mismos. Agreguemos una ruta custom-documentation que sea un poco diferente a la que registramos. Aún trabajando en el mismo complemento, podemos agregar:

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

Y enganche el método create_custom_documentation_endpoint() al enganche rest_api_init , así:

 add_action( 'rest_api_init', [ $documentation, 'create_custom_documentation_endpoint' ] );

Esto agregará una ruta personalizada en https://dev.wordpress.test/wp-json/documentation-plugin/v1/custom-documentation con la devolución de llamada que devuelve la respuesta para esa ruta.

 [{ "title": "Another test documentation", "tags": ["Another tag"] }, { "title": "Test documentation", "tags": ["REST API", "test tag"] }]

Hay muchas otras cosas que puede hacer con la API REST (puede encontrar más detalles en el manual de la API REST).

Evitar tiempos de respuesta largos cuando se usa la API REST predeterminada

Para cualquiera que haya intentado crear un sitio de WordPress desacoplado, esto no es algo nuevo: la API REST es lenta.

Mi equipo y yo nos encontramos por primera vez con la extraña API REST que retrasaba WordPress en un sitio de cliente (no desacoplado), donde usamos los puntos finales personalizados para obtener la lista de ubicaciones en un mapa de Google, junto con otra metainformación creada con Advanced Custom Fields Pro. enchufar. Resultó que el tiempo del primer byte (TTFB), que se usa como indicación de la capacidad de respuesta de un servidor web u otro recurso de red, tomó más de 3 segundos.

Después de investigar un poco, nos dimos cuenta de que las llamadas a la API REST predeterminadas eran realmente muy lentas, especialmente cuando "sobrecargamos" el sitio con complementos adicionales. Entonces, hicimos una pequeña prueba. Instalamos un par de complementos populares y encontramos algunos resultados interesantes. La aplicación de cartero proporcionó un tiempo de carga de 1,97 s para un tamaño de respuesta de 41,9 KB. El tiempo de carga de Chrome fue de 1,25 s (TTFB fue de 1,25 s, el contenido se descargó en 3,96 ms). Solo para recuperar una lista simple de publicaciones. Sin taxonomía, sin datos de usuario, sin metacampos adicionales.

¿Por qué pasó esto?

Resulta que acceder a la API REST en el WordPress predeterminado cargará todo el núcleo de WordPress para servir a los puntos finales, aunque no se use. Además, cuantos más complementos agregue, peor se pondrán las cosas. El controlador REST predeterminado WP_REST_Controller es una clase realmente grande que hace mucho más de lo necesario al crear una página web simple. Maneja el registro de rutas, la verificación de permisos, la creación y eliminación de elementos, etc.

Hay dos soluciones comunes para este problema:

  1. Intercepte la carga de los complementos y evite cargarlos todos cuando necesite servir una respuesta REST simple;
  2. Cargue solo el mínimo de WordPress y almacene los datos en un transitorio, desde el cual luego obtenemos los datos usando una página personalizada.

Mejora del rendimiento con el enfoque JSON desacoplado

Cuando trabaja con sitios de presentación simples, no necesita toda la funcionalidad que le ofrece la API REST. Por supuesto, aquí es donde una buena planificación es crucial. Realmente no desea crear su sitio sin la API REST y luego decir dentro de un año que le gustaría conectarse a su sitio, o tal vez crear una aplicación móvil que necesite usar la funcionalidad de la API REST. ¿Vos si?

Por esa razón, utilizamos dos características de WordPress que pueden ayudarlo cuando entrega datos JSON simples:

  • API de transitorios para almacenamiento en caché,
  • Cargando el WordPress mínimo necesario usando la constante SHORTINIT .

Creación de un extremo de páginas desacopladas simples

Vamos a crear un pequeño complemento que demuestre el efecto del que estamos hablando. Primero, agregue un archivo wp-config-simple.php en su complemento json-transient que se vea así:

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

El define( 'SHORTINIT', true ); evitará que se carguen la mayoría de los archivos principales de WordPress, como se puede ver en el archivo wp-settings.php .

Es posible que aún necesitemos algunas de las funciones de WordPress, por lo que podemos solicitar el archivo (como wp-load.php ) manualmente. Dado que wp-load.php se encuentra en la raíz de nuestra instalación de WordPress, lo buscaremos obteniendo la ruta de nuestro archivo usando $_SERVER['SCRIPT_FILENAME'] y luego explotando esa cadena por wp-content string. Esto devolverá una matriz con dos valores:

  1. La raíz de nuestra instalación;
  2. El resto de la ruta del archivo (que no nos interesa).

Tenga en cuenta que estamos usando la instalación predeterminada de WordPress, y no una modificada, como por ejemplo en el repetitivo Bedrock, que divide WordPress en una organización de archivos diferente.

Por último, requerimos el archivo wp-load.php , con un poco de desinfección, por seguridad.

En nuestro archivo init.php , agregaremos lo siguiente:

* 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' ] );

Los métodos de ayuda en el código anterior nos permitirán hacer algo de almacenamiento en caché:

  • get_allowed_post_types()
    Este método permite que los tipos de publicaciones sepan que queremos habilitar la visualización en nuestro 'punto final' personalizado. Puede extender esto, y el complemento en realidad hemos hecho este método filtrable para que pueda usar un filtro para agregar elementos adicionales.
  • is_post_type_allowed_to_save()
    Este método simplemente verifica si el tipo de publicación del que estamos tratando de obtener los datos está en la matriz permitida especificada por el método anterior.
  • get_page_cache_name_by_slug()
    Este método devolverá el nombre del transitorio del que se obtendrán los datos.
  • get_page_data_by_slug()
    Este método es el método que realizará WP_Query en la publicación a través de su slug y tipo de publicación y devolverá el contenido de la matriz de publicación que convertiremos con el JSON usando el método get_json_page() .
  • update_page_transient()
    Esto se ejecutará en el save_post y sobrescribirá el transitorio en la base de datos con los datos JSON de nuestra publicación. Este último método se conoce como el "método de almacenamiento en caché de claves".

Expliquemos los transitorios con más profundidad.

API de transitorios

La API de transitorios se utiliza para almacenar datos en la tabla de opciones de su base de datos de WordPress durante un período de tiempo específico. Es un caché de objetos persistentes, lo que significa que está almacenando algún objeto, por ejemplo, resultados de consultas grandes y lentas o páginas completas que pueden persistir entre cargas de página. Es similar a la caché de objetos de WordPress normal, pero a diferencia de WP_Cache , los datos transitorios persistirán a lo largo de las cargas de la página, mientras que WP_Cache (que almacena los datos en la memoria) solo retendrá los datos durante la duración de una solicitud.

Es un almacén de clave-valor, lo que significa que podemos obtener fácil y rápidamente los datos deseados, de forma similar a lo que hacen in-memory caching systems como Memcached o Redis. La diferencia es que, por lo general, necesitará instalarlos por separado en el servidor (lo que puede ser un problema en los servidores compartidos), mientras que los transitorios están integrados con WordPress.

Como se indica en su página de Codex, los complementos de almacenamiento en caché aceleran inherentemente los transitorios. Ya que pueden almacenar transitorios en la memoria en lugar de una base de datos. La regla general es que no debe asumir que el transitorio siempre está presente en la base de datos, por lo que es una buena práctica verificar su existencia antes de buscarlo.

 $transient_name = get_transient( 'transient_name' ); if ( $transient_name === false ) { set_transient( 'transient_name', $transient_data, $transient_expiry ); }

Puede usarlo sin caducidad (como lo estamos haciendo), y es por eso que implementamos una especie de 'caché-busting' en el guardado posterior. Además de toda la gran funcionalidad que brindan, pueden almacenar hasta 4 GB de datos, pero no recomendamos almacenar nada tan grande en un solo campo de base de datos.

Lectura recomendada : Esté atento: funciones de PHP y WordPress que pueden hacer que su sitio sea inseguro

Punto final final: pruebas y verificación

La última pieza del rompecabezas que necesitamos es un 'punto final'. Estoy usando el término punto final aquí, aunque no es un punto final ya que estamos llamando directamente a un archivo específico para obtener nuestros resultados. Entonces podemos crear un archivo test.php que se vea así:

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

Si vamos a https://dev.wordpress.test/wp-content/plugins/json-transient/test.php , veremos este mensaje:

¡Falta el error, el slug de la página o el tipo!

Por lo tanto, necesitaremos especificar el tipo de publicación y el slug de la publicación. Cuando ahora vayamos a https://dev.wordpress.test/wp-content/plugins/json-transient/test.php?slug=hello-world&type=post veremos:

Error, la página no existe o no está cacheada correctamente. ¡Intente reconstruir el caché y vuelva a intentarlo!

¡Oh espera! Necesitamos volver a guardar nuestras páginas y publicaciones primero. Entonces, cuando estás comenzando, esto puede ser fácil. Pero si ya tiene más de 100 páginas o publicaciones, esta puede ser una tarea desafiante. Es por eso que implementamos una forma de borrar los transitorios en el complemento de contenido JSON desacoplado y reconstruirlos en un lote.

Pero continúe y vuelva a guardar la publicación Hello World y luego abra el enlace nuevamente. Lo que deberías tener ahora es algo parecido a esto:

 { "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" }

Y eso es. El complemento que creamos tiene algunas funciones adicionales que puede usar, pero en pocas palabras, así es como puede obtener los datos JSON de su WordPress que es mucho más rápido que usar la API REST.

Antes y después: tiempo de respuesta mejorado

Realizamos pruebas en Chrome, donde pudimos ver el tiempo de respuesta total y el TTFB por separado. Probamos los tiempos de respuesta diez veces seguidas: primero sin complementos y luego con los complementos agregados. Además, probamos la respuesta para una lista de publicaciones y para una sola publicación.

Los resultados de la prueba se ilustran en las siguientes tablas:

Gráfico de comparación que muestra los tiempos de respuesta del uso de la API REST de WordPress frente al uso del enfoque desacoplado sin complementos agregados. El enfoque desacoplado es de 2 a 3 veces más rápido
Gráfico de comparación que muestra los tiempos de respuesta del uso de la API REST de WordPress frente al uso del enfoque desacoplado sin complementos agregados. El enfoque desacoplado es de 2 a 3 veces más rápido. (Vista previa grande)
Gráfico de comparación que muestra los tiempos de respuesta del uso de la API REST de WordPress frente al uso del enfoque desacoplado con complementos agregados. El enfoque desacoplado es hasta 8 veces más rápido.
Gráfico de comparación que muestra los tiempos de respuesta del uso de la API REST de WordPress frente al uso del enfoque desacoplado con complementos agregados. El enfoque desacoplado es hasta 8 veces más rápido. (Vista previa grande)

Como puedes ver, la diferencia es drástica.

Preocupaciones de seguridad

Hay algunas advertencias que deberá analizar detenidamente. En primer lugar, estamos cargando manualmente los archivos principales de WordPress, lo que en el mundo de WordPress es un gran no-no. ¿Por qué? Bueno, además del hecho de que obtener manualmente los archivos principales puede ser complicado (especialmente si está utilizando instalaciones no estándar como Bedrock), podría plantear algunos problemas de seguridad.

Si decide utilizar el método descrito en este artículo, asegúrese de saber cómo fortalecer la seguridad de su servidor.

Primero, agregue encabezados HTML como en el archivo test.php :

 header( 'Access-Control-Allow-Origin: your-front-end-app.url' ); header( 'Content-Type: application/json' );

El primer encabezado es una forma de eludir la medida de seguridad de CORS para que solo su aplicación de front-end pueda obtener el contenido cuando vaya al archivo especificado.

En segundo lugar, deshabilite el recorrido de directorios de su aplicación. Puede hacer esto modificando la configuración de nginx o agregando Options -Indexes a su archivo .htaccess si está en un servidor Apache.

Agregar una verificación de token a la respuesta también es una buena medida que puede evitar el acceso no deseado. De hecho, estamos trabajando en una forma de modificar nuestro complemento JSON desacoplado para que podamos incluir estas medidas de seguridad de forma predeterminada.

Una verificación de un encabezado de Autorización enviado por la aplicación frontend podría verse así:

 if ( ! isset( $_SERVER['HTTP_AUTHORIZATION'] ) ) { return; } $auth_header = $_SERVER['HTTP_AUTHORIZATION'];

Luego, puede verificar si el token específico (un secreto que solo comparten las aplicaciones de front-end y back-end) se proporciona y es correcto.

Conclusión

La API REST es excelente porque se puede usar para crear aplicaciones completas: crear, recuperar, actualizar y eliminar los datos. La desventaja de usarlo es su velocidad.

Obviamente, crear una aplicación es diferente a crear un sitio web clásico. Probablemente no necesitará todos los complementos que instalamos. Pero si solo necesita los datos con fines de presentación, almacenar datos en caché y servirlos en un archivo personalizado parece ser la solución perfecta en este momento, cuando se trabaja con sitios desacoplados.

Puede estar pensando que crear un complemento personalizado para acelerar el tiempo de respuesta del sitio web es una exageración, pero vivimos en un mundo en el que cada segundo cuenta. Todo el mundo sabe que si un sitio web es lento, los usuarios lo abandonarán. Hay muchos estudios que demuestran la conexión entre el rendimiento del sitio web y las tasas de conversión. Pero si aún necesita que lo convenzan, Google penaliza los sitios web lentos.

El método explicado en este artículo resuelve el problema de velocidad que encuentra la API REST de WordPress y le dará un impulso adicional cuando trabaje en un proyecto de WordPress desacoplado. Como estamos en nuestra búsqueda interminable para exprimir ese último milisegundo de cada solicitud y respuesta, planeamos optimizar el complemento aún más. Mientras tanto, comparta sus ideas sobre cómo acelerar WordPress desacoplado.