Headless WordPress : Les hauts et les bas de la création d'un WordPress découplé

Publié: 2022-03-10
Résumé rapide ↬ Tout le monde sait que si un site Web est lent, les utilisateurs l'abandonneront. De nombreuses études démontrent le lien entre les performances du site Web et les taux de conversion. Dans cet article, Denis Zoljom partage son expérience et les bases de la création d'un WordPress découplé.

WordPress a parcouru un long chemin depuis ses débuts en tant que simple outil d'écriture de blog. 15 longues années plus tard, il est devenu le premier choix de CMS pour les développeurs et les non-développeurs. WordPress alimente désormais environ 30 % des 10 millions de sites les plus populaires sur le Web.

Depuis que l'API REST est intégrée au cœur de WordPress, les développeurs peuvent l'expérimenter et l'utiliser de manière découplée, c'est-à-dire en écrivant la partie frontale en utilisant des frameworks ou des bibliothèques JavaScript. Chez Infinium, nous utilisions (et utilisons toujours) WordPress de manière 'classique' : PHP pour le frontend comme pour le backend. Au bout d'un moment, nous avons voulu essayer l'approche découplée. Dans cet article, je vais partager un aperçu de ce que nous voulions réaliser et de ce que nous avons rencontré en essayant de mettre en œuvre nos objectifs.

Plusieurs types de projets peuvent bénéficier de cette approche. Par exemple, les sites de présentation simples ou les sites qui utilisent WordPress comme backend sont les principaux candidats à l'approche découplée.

Ces dernières années, l'industrie a heureusement commencé à accorder plus d'attention à la performance. Cependant, étant un logiciel inclusif et polyvalent facile à utiliser, WordPress est livré avec une pléthore d'options qui ne sont pas nécessairement utilisées dans chaque projet. En conséquence, les performances du site Web peuvent en souffrir.

Lecture recommandée : Comment utiliser les cartes thermiques pour suivre les clics sur votre site Web WordPress

Si les longs temps de réponse du site Web vous empêchent de dormir la nuit, voici un guide pratique pour vous. Je couvrirai les bases de la création d'un WordPress découplé et quelques leçons apprises, notamment :

  1. La signification d'un « WordPress découplé »
  2. Travailler avec l'API REST WordPress par défaut
  3. Améliorer les performances avec l'approche JSON découplée
  4. Problèmes de sécurité
Plus après saut! Continuez à lire ci-dessous ↓

Alors, qu'est-ce qu'un WordPress découplé exactement ?

En ce qui concerne la façon dont WordPress est programmé, une chose est certaine : il ne suit pas le modèle de conception M odel- V iew- C ontroller (MVC) que de nombreux développeurs connaissent. En raison de son histoire et du fait qu'il s'agit d'une sorte de fork d'une ancienne plateforme de blogs appelée "b2" (plus de détails ici), il est en grande partie écrit de manière procédurale (en utilisant du code basé sur des fonctions). Les principaux développeurs de WordPress ont utilisé un système de hooks qui permettait à d'autres développeurs de modifier ou d'étendre certaines fonctionnalités.

C'est un système tout-en-un équipé d'une interface d'administration fonctionnelle. il gère la connexion à la base de données et dispose d'un ensemble d'API utiles qui gèrent l'authentification des utilisateurs, le routage, etc.

Mais grâce à l'API REST, vous pouvez séparer le backend WordPress en une sorte de modèle et de contrôleur regroupés qui gèrent la manipulation des données et l'interaction avec la base de données, et utiliser REST API Controller pour interagir avec une couche de vue distincte à l'aide de divers points de terminaison d'API. En plus de la séparation MVC, nous pouvons (pour des raisons de sécurité ou d'amélioration de la vitesse) placer l'application JS sur un serveur séparé comme dans le schéma ci-dessous :

Image illustrant le diagramme WordPress découplé avec les parties PHP et JS séparées
Diagramme WordPress découplé. ( Grand aperçu )

Avantages de l'utilisation de l'approche découplée

Une des raisons pour lesquelles vous voudrez peut-être utiliser cette approche est d'assurer une séparation des préoccupations. Le frontend et le backend interagissent via des points de terminaison ; chacun peut être sur son serveur séparé qui peut être optimisé spécifiquement pour chaque tâche respective, c'est-à-dire exécuter séparément une application PHP et exécuter une application Node.js.

En séparant votre frontend du backend, il est plus facile de le reconcevoir à l'avenir, sans changer le CMS. De plus, les développeurs front-end n'ont qu'à se soucier de ce qu'il faut faire avec les données que le back-end leur fournit. Cela leur permet de faire preuve de créativité et d'utiliser des bibliothèques modernes telles que ReactJS, Vue ou Angular pour fournir des applications Web hautement dynamiques. Par exemple, il est plus facile de créer une application Web progressive en utilisant les bibliothèques susmentionnées.

Un autre avantage se reflète dans la sécurité du site Web. L'exploitation du site Web via le backend devient plus difficile car il est en grande partie caché au public.

Lecture recommandée : WordPress Security As A Process

Inconvénients de l'utilisation de l'approche découplée

Premièrement, avoir un WordPress découplé, c'est maintenir deux instances distinctes :

  1. WordPress pour le backend ;
  2. Une application frontale distincte, comprenant des mises à jour de sécurité en temps opportun.

Deuxièmement, certaines des bibliothèques frontales ont une courbe d'apprentissage plus abrupte. Cela prendra soit beaucoup de temps pour apprendre un nouveau langage (si vous n'êtes habitué qu'au HTML et au CSS pour la création de modèles), soit il faudra faire appel à des experts JavaScript supplémentaires pour le projet.

Troisièmement, en séparant le frontend, vous perdez la puissance de l'éditeur WYSIWYG, et le bouton 'Live Preview' de WordPress ne fonctionne pas non plus.

Travailler avec l'API REST de WordPress

Avant d'approfondir le code, quelques éléments supplémentaires sur l'API REST de WordPress. La pleine puissance de l'API REST dans WordPress est arrivée avec la version 4.7 le 6 décembre 2016.

Ce que l'API REST WordPress vous permet de faire, c'est d'interagir à distance avec votre installation WordPress en envoyant et en recevant des objets JSON.

Configurer un projet

Comme il est fourni avec la dernière installation de WordPress, nous travaillerons sur le thème Twenty Seventeen. Je travaille sur Varying Vagrant Vagrants, et j'ai mis en place un site de test avec une URL https://dev.wordpress.test/ . Cette URL sera utilisée tout au long de l'article. Nous importerons également des articles depuis le référentiel des équipes de révision des thèmes de wordpress.org afin d'avoir des données de test avec lesquelles travailler. Mais d'abord, nous nous familiariserons avec les points de terminaison par défaut, puis nous créerons notre propre point de terminaison personnalisé.

Accéder au point de terminaison REST par défaut

Comme déjà mentionné, WordPress est livré avec plusieurs points de terminaison intégrés que vous pouvez examiner en accédant à la route /wp-json/ :

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

Soit en mettant cette URL directement dans votre navigateur, soit en l'ajoutant dans l'application postman, vous obtiendrez une réponse JSON de l'API WordPress REST qui ressemble à ceci :

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

Donc, pour obtenir tous les messages de notre site en utilisant REST, nous aurions besoin d'aller sur https://dev.wordpress.test/wp-json/wp/v2/posts . Notez que wp/v2/ marque les points de terminaison principaux réservés comme les publications, les pages, les médias, les taxonomies, les catégories, etc.

Alors, comment ajouter un point de terminaison personnalisé ?

Créer un point de terminaison REST personnalisé

Supposons que nous souhaitions ajouter un nouveau point de terminaison ou un champ supplémentaire au point de terminaison existant. Il y a plusieurs façons de le faire. Tout d'abord, on peut le faire automatiquement lors de la création d'un type de publication personnalisé. Par exemple, nous voulons créer un point de terminaison de documentation. Créons un petit plugin de test. Créez un dossier test-documentation dans le dossier wp-content/plugins et ajoutez le fichier documentation.php qui ressemble à ceci :

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

En enregistrant le nouveau type de publication et la taxonomie, et en définissant l'argument show_in_rest sur true , WordPress a automatiquement créé une route REST dans l'espace de noms /wp/v2/ . Vous avez maintenant les points de terminaison https://dev.wordpress.test/wp-json/wp/v2/documentation et https://dev.wordpress.test/wp-json/wp/v2/documentation-category disponibles. Si nous ajoutons un message dans notre message personnalisé de documentation nouvellement créé allant à https://dev.wordpress.test/?post_type=documentation , il nous donnera une réponse qui ressemble à ceci :

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

Ceci est un contenu de documentation

\n", "protégé": faux }, "media_vedette": 0, "modèle": "", "documentation-category": [ 2 ], "_liens": { "soi": [ { "href": "https://dev.wordpress.test/wp-json/wp/v2/documentation/4" } ], "collection": [ { "href": "https://dev.wordpress.test/wp-json/wp/v2/documentation" } ], "sur": [ { "href": "https://dev.wordpress.test/wp-json/wp/v2/types/documentation" } ], "historique des versions": [ { "href": "https://dev.wordpress.test/wp-json/wp/v2/documentation/4/revisions" } ], "wp:pièce jointe": [ { "href": "https://dev.wordpress.test/wp-json/wp/v2/media?parent=4" } ], "wp:term": [ { "taxonomy": "documentation-category", "intégrable": vrai, "href": "https://dev.wordpress.test/wp-json/wp/v2/documentation-category?post=4" } ], "curies": [ { "nom": "wp", "href": "https://api.w.org/{rel}", "modèle": vrai } ] } } ]

C'est un excellent point de départ pour notre application d'une seule page. Une autre façon d'ajouter un point de terminaison personnalisé consiste à se connecter au crochet rest_api_init et à créer nous-mêmes un point de terminaison. Ajoutons une route custom-documentation légèrement différente de celle que nous avons enregistrée. Travaillant toujours dans le même plugin, nous pouvons ajouter :

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

Et accrochez la méthode create_custom_documentation_endpoint() au crochet rest_api_init , comme ceci :

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

Cela ajoutera une route personnalisée dans le https://dev.wordpress.test/wp-json/documentation-plugin/v1/custom-documentation avec le rappel renvoyant la réponse pour cette route.

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

Il y a beaucoup d'autres choses que vous pouvez faire avec l'API REST (vous pouvez trouver plus de détails dans le manuel de l'API REST).

Contourner les temps de réponse longs lors de l'utilisation de l'API REST par défaut

Pour tous ceux qui ont essayé de créer un site WordPress découplé, ce n'est pas une nouveauté - l'API REST est lente.

Mon équipe et moi avons rencontré pour la première fois l'étrange API REST WordPress en retard sur un site client (non découplé), où nous avons utilisé les points de terminaison personnalisés pour obtenir la liste des emplacements sur une carte Google, ainsi que d'autres méta-informations créées à l'aide de Advanced Custom Fields Pro. brancher. Il s'est avéré que le temps du premier octet (TTFB) - qui est utilisé comme une indication de la réactivité d'un serveur Web ou d'une autre ressource réseau - prenait plus de 3 secondes.

Après quelques recherches, nous avons réalisé que les appels d'API REST par défaut étaient en fait très lents, en particulier lorsque nous "surchargés" le site avec des plugins supplémentaires. Alors, on a fait un petit test. Nous avons installé quelques plugins populaires et avons rencontré des résultats intéressants. L'application Postman a donné un temps de chargement de 1,97 s pour 41,9 Ko de taille de réponse. Le temps de chargement de Chrome était de 1,25 s (TTFB était de 1,25 s, le contenu a été téléchargé en 3,96 ms). Juste pour récupérer une simple liste de messages. Pas de taxonomie, pas de données utilisateur, pas de champs méta supplémentaires.

Pourquoi est-ce arrivé?

Il s'avère que l'accès à l'API REST sur le WordPress par défaut chargera l'intégralité du noyau WordPress pour servir les points de terminaison, même s'il n'est pas utilisé. De plus, plus vous ajoutez de plugins, plus les choses empirent. Le contrôleur REST par défaut WP_REST_Controller est une très grande classe qui fait beaucoup plus que nécessaire lors de la création d'une simple page Web. Il gère l'enregistrement des itinéraires, les vérifications d'autorisation, la création et la suppression d'éléments, etc.

Il existe deux solutions de contournement courantes pour ce problème :

  1. Interceptez le chargement des plugins et empêchez-les tous de les charger lorsque vous avez besoin de servir une simple réponse REST ;
  2. Chargez uniquement le strict minimum de WordPress et stockez les données dans un transitoire, à partir duquel nous récupérons ensuite les données à l'aide d'une page personnalisée.

Améliorer les performances avec l'approche JSON découplée

Lorsque vous travaillez avec des sites de présentation simples, vous n'avez pas besoin de toutes les fonctionnalités que l'API REST vous offre. Bien sûr, c'est là qu'une bonne planification est cruciale. Vous ne voulez vraiment pas créer votre site sans l'API REST, puis dire dans un an que vous souhaitez vous connecter à votre site, ou peut-être créer une application mobile qui doit utiliser la fonctionnalité de l'API REST. Est-ce que tu?

Pour cette raison, nous avons utilisé deux fonctionnalités WordPress qui peuvent vous aider lors de la diffusion de données JSON simples :

  • API transitoires pour la mise en cache,
  • Chargement du WordPress minimum nécessaire en utilisant la constante SHORTINIT .

Création d'un point de terminaison de pages découplées simples

Créons un petit plugin qui démontrera l'effet dont nous parlons. Tout d'abord, ajoutez un fichier wp-config-simple.php dans votre plugin json-transient qui ressemble à ceci :

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

La define( 'SHORTINIT', true ); empêchera le chargement de la majorité des fichiers principaux de WordPress, comme on peut le voir dans le fichier wp-settings.php .

Nous pouvons encore avoir besoin de certaines fonctionnalités de WordPress, nous pouvons donc exiger le fichier (comme wp-load.php ) manuellement. Puisque wp-load.php se trouve à la racine de notre installation WordPress, nous allons le récupérer en obtenant le chemin de notre fichier en utilisant $_SERVER['SCRIPT_FILENAME'] , puis en explosant cette chaîne par la chaîne wp-content . Cela renverra un tableau avec deux valeurs :

  1. La racine de notre installation;
  2. Le reste du chemin du fichier (qui ne nous intéresse pas).

Gardez à l'esprit que nous utilisons l'installation par défaut de WordPress, et non une installation modifiée, comme par exemple dans le passe-partout Bedrock, qui divise WordPress dans une organisation de fichiers différente.

Enfin, nous avons besoin du fichier wp-load.php , avec un peu de désinfection, pour des raisons de sécurité.

Dans notre fichier init.php , nous ajouterons ce qui suit :

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

Les méthodes d'assistance dans le code ci-dessus nous permettront de faire de la mise en cache :

  • get_allowed_post_types()
    Cette méthode permet aux types de publication de savoir que nous voulons activer l'affichage dans notre "point de terminaison" personnalisé. Vous pouvez étendre cela, et le plugin que nous avons rendu cette méthode filtrable afin que vous puissiez simplement utiliser un filtre pour ajouter des éléments supplémentaires.
  • is_post_type_allowed_to_save()
    Cette méthode vérifie simplement si le type de publication à partir duquel nous essayons de récupérer les données se trouve dans le tableau autorisé spécifié par la méthode précédente.
  • get_page_cache_name_by_slug()
    Cette méthode renverra le nom du transitoire à partir duquel les données seront récupérées.
  • get_page_data_by_slug()
    Cette méthode est la méthode qui effectuera le WP_Query sur la publication via son type de slug et de publication et renverra le contenu du tableau de publication que nous convertirons avec le JSON en utilisant la méthode get_json_page() .
  • update_page_transient()
    Cela sera exécuté sur le crochet save_post et écrasera le transitoire dans la base de données avec les données JSON de notre message. Cette dernière méthode est connue sous le nom de « méthode de mise en cache des clés ».

Expliquons les transitoires plus en profondeur.

API transitoires

L'API Transients est utilisée pour stocker des données dans la table d'options de votre base de données WordPress pendant une période de temps spécifique. Il s'agit d'un cache d'objets persistant, ce qui signifie que vous stockez un objet, par exemple, les résultats de requêtes volumineuses et lentes ou des pages complètes qui peuvent être conservées à travers les chargements de page. Il est similaire au cache d'objets WordPress standard, mais contrairement à WP_Cache , les transitoires conserveront les données lors des chargements de page, où WP_Cache (stockant les données en mémoire) ne conservera les données que pendant la durée d'une demande.

Il s'agit d'un magasin clé-valeur, ce qui signifie que nous pouvons facilement et rapidement récupérer les données souhaitées, comme le font in-memory caching systems comme Memcached ou Redis. La différence est que vous devez généralement les installer séparément sur le serveur (ce qui peut être un problème sur les serveurs partagés), alors que les transitoires sont intégrés à WordPress.

Comme indiqué sur sa page Codex, les transitoires sont intrinsèquement accélérés par les plugins de mise en cache. Puisqu'ils peuvent stocker les transitoires en mémoire au lieu d'une base de données. La règle générale est que vous ne devez pas supposer que le transitoire est toujours présent dans la base de données - c'est pourquoi il est recommandé de vérifier son existence avant de le récupérer.

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

Vous pouvez l'utiliser sans expiration (comme nous le faisons), et c'est pourquoi nous avons implémenté une sorte de "cache-busting" lors de la post-sauvegarde. En plus de toutes les fonctionnalités qu'ils offrent, ils peuvent contenir jusqu'à 4 Go de données, mais nous ne recommandons pas de stocker quoi que ce soit d'aussi gros dans un seul champ de base de données.

Lecture recommandée : Soyez vigilant : les fonctions PHP et WordPress qui peuvent rendre votre site non sécurisé

Point final : test et vérification

La dernière pièce du puzzle dont nous avons besoin est un «point final». J'utilise ici le terme point de terminaison, même s'il ne s'agit pas d'un point de terminaison puisque nous appelons directement un fichier spécifique pour récupérer nos résultats. Nous pouvons donc créer un fichier test.php qui ressemble à ceci :

 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 nous allons sur https://dev.wordpress.test/wp-content/plugins/json-transient/test.php , nous verrons ce message :

Erreur, slug de page ou type manquant !

Nous devrons donc spécifier le type de publication et le slug de publication. Lorsque nous allons maintenant sur https://dev.wordpress.test/wp-content/plugins/json-transient/test.php?slug=hello-world&type=post nous verrons :

Erreur, la page n'existe pas ou elle n'est pas mise en cache correctement. Veuillez essayer de reconstruire le cache et réessayer !

Oh, attendez! Nous devons d'abord enregistrer à nouveau nos pages et nos publications. Ainsi, lorsque vous débutez, cela peut être facile. Mais si vous avez déjà plus de 100 pages ou publications, cela peut être une tâche difficile. C'est pourquoi nous avons implémenté un moyen d'effacer les transitoires dans le plug-in Decoupled JSON Content et de les reconstruire par lot.

Mais allez-y et enregistrez à nouveau le message Hello World , puis ouvrez à nouveau le lien. Ce que vous devriez maintenant avoir est quelque chose qui ressemble à ceci :

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

Et c'est tout. Le plugin que nous avons créé a quelques fonctionnalités supplémentaires que vous pouvez utiliser, mais en un mot, c'est ainsi que vous pouvez récupérer les données JSON de votre WordPress qui est beaucoup plus rapide que d'utiliser l'API REST.

Avant et après : temps de réponse amélioré

Nous avons effectué des tests dans Chrome, où nous avons pu voir le temps de réponse total et le TTFB séparément. Nous avons testé les temps de réponse dix fois de suite : d'abord sans plugins puis avec les plugins ajoutés. De plus, nous avons testé la réponse pour une liste de messages et pour un seul message.

Les résultats du test sont illustrés dans les tableaux ci-dessous :

Graphique de comparaison illustrant les temps de réponse de l'utilisation de l'API WordPress REST par rapport à l'utilisation de l'approche découplée sans plugins ajoutés. L'approche découplée est 2 à 3 fois plus rapide
Graphique de comparaison illustrant les temps de réponse de l'utilisation de l'API WordPress REST par rapport à l'utilisation de l'approche découplée sans plugins ajoutés. L'approche découplée est 2 à 3 fois plus rapide. ( Grand aperçu )
Graphique de comparaison illustrant les temps de réponse de l'utilisation de l'API WordPress REST par rapport à l'utilisation de l'approche découplée avec des plugins ajoutés. L'approche découplée est jusqu'à 8 fois plus rapide.
Graphique de comparaison illustrant les temps de réponse de l'utilisation de l'API WordPress REST par rapport à l'utilisation de l'approche découplée avec des plugins ajoutés. L'approche découplée est jusqu'à 8 fois plus rapide. ( Grand aperçu )

Comme vous pouvez le voir, la différence est radicale.

Problèmes de sécurité

Il y a quelques mises en garde que vous devrez examiner attentivement. Tout d'abord, nous chargeons manuellement les fichiers principaux de WordPress, ce qui dans le monde WordPress est un grand non-non. Pourquoi? Eh bien, outre le fait que la récupération manuelle des fichiers principaux peut être délicate (surtout si vous utilisez des installations non standard telles que Bedrock), cela pourrait poser des problèmes de sécurité.

Si vous décidez d'utiliser la méthode décrite dans cet article, assurez-vous de savoir comment renforcer la sécurité de votre serveur.

Tout d'abord, ajoutez des en-têtes HTML comme dans le fichier test.php :

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

Le premier en-tête est un moyen de contourner la mesure de sécurité CORS afin que seule votre application frontale puisse récupérer le contenu lors de l'accès au fichier spécifié.

Deuxièmement, désactivez la traversée de répertoires de votre application. Vous pouvez le faire en modifiant les paramètres nginx ou en ajoutant Options -Indexes à votre fichier .htaccess si vous êtes sur un serveur Apache.

L'ajout d'une vérification de jeton à la réponse est également une bonne mesure qui peut empêcher tout accès indésirable. Nous travaillons actuellement sur un moyen de modifier notre plugin JSON découplé afin que nous puissions inclure ces mesures de sécurité par défaut.

Une vérification d'un en-tête d'autorisation envoyé par l'application frontale pourrait ressembler à ceci :

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

Ensuite, vous pouvez vérifier si le jeton spécifique (un secret qui n'est partagé que par les applications frontales et principales) est fourni et correct.

Conclusion

L'API REST est géniale car elle peut être utilisée pour créer des applications à part entière - créer, récupérer, mettre à jour et supprimer les données. L'inconvénient de son utilisation est sa rapidité.

Évidemment, la création d'une application est différente de la création d'un site Web classique. Vous n'aurez probablement pas besoin de tous les plugins que nous avons installés. Mais si vous avez juste besoin des données à des fins de présentation, mettre les données en cache et les servir dans un fichier personnalisé semble être la solution parfaite pour le moment, lorsque vous travaillez avec des sites découplés.

Vous pensez peut-être que créer un plugin personnalisé pour accélérer le temps de réponse du site Web est exagéré, mais nous vivons dans un monde dans lequel chaque seconde compte. Tout le monde sait que si un site Web est lent, les utilisateurs l'abandonneront. De nombreuses études démontrent le lien entre les performances du site Web et les taux de conversion. Mais si vous avez encore besoin d'être convaincu, Google pénalise les sites Web lents.

La méthode expliquée dans cet article résout le problème de vitesse rencontré par l'API WordPress REST et vous donnera un coup de pouce supplémentaire lorsque vous travaillez sur un projet WordPress découplé. Comme nous sommes dans notre quête sans fin pour extraire cette dernière milliseconde de chaque demande et réponse, nous prévoyons d'optimiser encore plus le plugin. En attendant, partagez vos idées sur l'accélération de WordPress découplé !