Fermer

octobre 26, 2018

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


À propos de l'auteur

Denis Žoljom est un ingénieur WordPress travaillant chez Infinum . Il est un contributeur principal de WordPress, un plugin et un auteur de thème, et un responsable de l'intégration du plugin pour…
Pour en savoir plus sur Denis

Tout le monde sait que si un site Web est lent, les utilisateurs l'abandonnent. De nombreuses études démontrent le lien entre les performances du site Web et les taux de conversion. Dans cet article, Denis Žoljom partage son expérience et les bases de la création d’un WordPress découplé.

WordPress a parcouru un long chemin en tant que simple outil d'écriture de blog. Quinze ans plus tard, il est devenu le premier choix de CMS pour les développeurs et les non-développeurs. WordPress alimente maintenant environ 30% des 10 millions de sites les plus utilisés 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 écrire la partie frontale en utilisant Structures ou bibliothèques JavaScript. Chez Infinum nous utilisions (et utilisons toujours) WordPress de manière «classique»: PHP pour le front-end et le back-end. Après un certain temps, nous avons voulu essayer l'approche découplée. Dans cet article, je vais vous donner un aperçu de ce que nous voulions réaliser et de ce que nous avions 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 utilisant WordPress comme back-end 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. Toutefois, en tant que 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, la performance du site Web peut en souffrir.

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

la nuit, c’est 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. Signification d'un «WordPress découplé»
  2. Utilisation de l'API REST WordPress par défaut
  3. Amélioration des performances avec l'approche JSON découplée [19659014] Problèmes de sécurité

En bref, qu'est-ce qu'un WordPress découplé?

En ce qui concerne la manière dont WordPress est programmé, est certain: il ne suit pas le modèle de conception M odel- V iew- C ontroller (MVC) que de nombreux développeurs connaissent bien. En raison de son histoire et du fait qu’elle est en quelque sorte le berceau d’une ancienne plate-forme de blogging appelée «b2» (plus de détails ici ici ), elle est en grande partie écrite de manière procédurale (en utilisant du code basé sur des fonctions). Les principaux développeurs de WordPress utilisaient un système de points d'ancrage permettant à d'autres développeurs de modifier ou d'étendre certaines fonctionnalités.

Il s'agit d'un système tout-en-un doté d'une interface d'administration fonctionnelle. il gère la connexion à la base de données et propose un grand nombre d'API utiles pour gérer l'authentification, le routage, etc., mais avec l'aide de l'utilisateur.

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 pour le gérer. manipulation des données et interaction avec la base de données, et utilisation du contrôleur API REST pour interagir avec une couche de vue distincte à l'aide de divers points de terminaison 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 distinct, comme dans le schéma ci-dessous:


 Image illustrant un diagramme WordPress découplé avec des parties PHP et JS séparées
Schéma WordPress découplé . ( Grand aperçu )

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

Une des raisons pour laquelle vous pouvez utiliser cette approche est de garantir la séparation des problèmes. Le front-end et le back-end interagissent via des points de terminaison; chacun peut se trouver 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 une application Node.js.

En séparant votre interface client du serveur, il est plus facile de la redéfinir à l'avenir. , sans changer le CMS. En outre, les développeurs front-end doivent uniquement se préoccuper de l'utilisation des données fournies par le backend. Cela leur permet de faire preuve de créativité et d'utiliser des bibliothèques modernes telles que ReactJS, Vue ou Angular pour créer 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 est reflété dans la sécurité du site Web. L'exploitation du site Web via le backend devient plus difficile car elle est en grande partie cachée du public.

Lecture recommandée : La ​​sécurité de WordPress en tant que processus

Les inconvénients de l'utilisation de l'approche découplée

Première , avoir un WordPress découplé signifie maintenir deux instances distinctes:

  1. WordPress pour le back-end;
  2. une application frontale distincte, y compris des mises à jour de sécurité opportunes.

Deuxièmement, certaines bibliothèques frontales ont une plus forte pente. courbe d'apprentissage. Il vous faudra beaucoup de temps pour apprendre une nouvelle langue (si vous êtes seulement habitué à HTML et à CSS à la modélisation), ou vous devrez faire appel à d'autres experts JavaScript.

Troisièmement, en séparant l'interface, vous êtes perdre la puissance de l'éditeur WYSIWYG et le bouton 'Aperçu en direct' dans WordPress ne fonctionne pas non plus.

Utilisation de l'API REST de WordPress

Avant d'approfondir le code, quelques éléments supplémentaires concernant API WordPress REST . Toute la puissance de l'API REST dans WordPress est venue avec la version 4.7 le 6 décembre 2016.

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

Un projet

Comme il est livré avec la dernière installation de WordPress, nous allons travailler sur le thème Twenty Seventeen. Je travaille sur Varying Vagrant Vagrants et j’ai créé un site de test avec une URL http: //dev.wordpress.test/ . Cette URL sera utilisée tout au long de l'article. Nous allons également importer les publications du référentiel wordpress.org pour les équipes de révision des thèmes afin de disposer de données de test. Mais d'abord, nous allons nous familiariser avec les points de terminaison par défaut, puis nous créerons notre propre point de terminaison personnalisé.

Accès 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 allant à la / wp-json / route:

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

Soit en plaçant cette URL directement dans votre navigateur, soit en l’ajoutant dans l’application Postman, vous obtiendrez une réponse JSON de l’API REST WordPress qui ressemble à ceci:

 {
    "name": "Test dev site",
    "description": "Juste un autre site WordPress",
    "url": "http: //dev.wordpress.test",
    "home": "http: //dev.wordpress.test",
    "gmt_offset": "0",
    "timezone_string": "",
    "espaces de noms": [
        "oembed/1.0",
        "wp/v2"
    ],
    "authentification": [],
    "itinéraires": {
        "/": {
            "namespace": "",
            "méthodes": [
                "GET"
            ],
            "points finaux": [
                {
                    "methods": [
                        "GET"
                    ],
                    "args": {
                        "le contexte": {
                            "required": faux,
                            "vue par défaut"
                        }
                    }
                }
            ],
            "_liens": {
                "self": "http: //dev.wordpress.test/wp-json/"
            }
        },
        "/oembed/1.0": {
            "namespace": "oembed / 1.0",
            "méthodes": [
                "GET"
            ],
            "points finaux": [
                {
                    "methods": [
                        "GET"
                    ],
                    "args": {
                        "namespace": {
                            "required": faux,
                            "default": "oembed / 1.0"
                        },
                        "le contexte": {
                            "required": faux,
                            "vue par défaut"
                        }
                    }
                }
            ],
            "_liens": {
                "self": "http: //dev.wordpress.test/wp-json/oembed/1.0"
            }
        },
        ...
        "wp / v2": {
        ...

Donc, pour obtenir tous les articles de notre site en utilisant REST, nous devons accéder à http: //dev.wordpress.test/wp-json/wp/v2/posts . Notez que le wp / v2 / marque les points d'extrémité principaux réservés tels que les posts, les pages, les supports, les taxonomies, les catégories, etc.

Alors, comment pouvons-nous ajouter un point d'extrémité personnalisé?

Create Un point de terminaison REST personnalisé

Supposons que nous voulions 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, vous pouvez le faire automatiquement lors de la création d'un type d'article personnalisé. Par exemple, nous voulons créer un noeud final 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 / **
 * Plugin de test
 *
 * @since 1.0.0
 * @package test_plugin
 *
 * @ wordpress-plugin
 * Nom du plugin: Test Documentation Plugin
 * URI du plugin:
 * Description: Le plugin de test qui ajoute une fonctionnalité de repos
 * Version: 1.0.0
 * Auteur: Infinum 
 * URI de l'auteur: https://infinum.co/
 * Licence: GPL-2.0 +
 * URI de la licence: http://www.gnu.org/licenses/gpl-2.0.txt
 * Domaine de texte: test-plugin
 * /

espace de noms Test_Plugin;

// Si ce fichier est appelé directement, annulez.
if (! defini ('WPINC')) {
  mourir;
}

/ **
 * Classe qui contient toutes les fonctionnalités nécessaires pour la
 * type de poste personnalisé de la documentation
 *
 * @since 1.0.0
 * /
Classe Documentation {
  / **
   * Le slug de type poste personnalisé
   *
   * @var string
   *
   * @since 1.0.0
   * /
  const PLUGIN_NAME = 'plug-in de documentation';

  / **
   * Le slug de type poste personnalisé
   *
   * @var string
   *
   * @since 1.0.0
   * /
  const POST_TYPE_SLUG = 'documentation';

  / **
   * Le type de taxonomie personnalisée
   *
   * @var string
   *
   * @since 1.0.0
   * /
  const TAXONOMY_SLUG = 'documentation-category';

  / **
   * Enregistrer le type de message personnalisé
   *
   * @since 1.0.0
   * /
  fonction publique register_post_type () {
    $ args = array (
        'label' => esc_html ('Documentation', 'test-plugin'),
        'public' => true,
        'menu_position' => 47,
        'menu_icon' => 'dashicons-book',
        'prend en charge' => array ('title', 'editor', 'revisions', 'thumbnail'),
        'has_archive' => false,
        'show_in_rest' => vrai,
        'public_queryable' => false,
    )

    register_post_type (self :: POST_TYPE_SLUG, $ args);
  }

  / **
   * Enregistrer la taxonomie des balises personnalisées
   *
   * @since 1.0.0
   * /
  fonction publique register_taxonomy () {
    $ args = array (
        'hierarchical' => false,
        'label' => esc_html ('Balises de documentation', 'test-plugin'),
        'show_ui' => true,
        'show_admin_column' => vrai,
        'update_count_callback' => '_update_post_term_count',
        'show_in_rest' => vrai,
        'query_var' => true,
    )

    register_taxonomy (self :: TAXONOMY_SLUG, [ self::POST_TYPE_SLUG ]$ args);
  }
}

$ documentation = nouvelle documentation ();

add_action ('init', [ $documentation, 'register_post_type' ]);
add_action ('init', [ $documentation, 'register_taxonomy' ]);

En enregistrant le nouveau type de message et la nouvelle taxonomie, et en définissant l'argument show_in_rest sur true WordPress a automatiquement créé une route REST dans le répertoire / wp / v2 / espace de noms. Vous avez maintenant http: //dev.wordpress.test/wp-json/wp/v2/documentation et http: //dev.wordpress.test/wp-json/wp/v2/ documentation-category terminaux disponibles. Si nous ajoutons une publication dans notre publication personnalisée de documentation nouvellement créée, allant à http: //dev.wordpress.test/? Post_type = documentation elle nous donnera une réponse ressemblant à ceci:

 [
    {
        "id": 4,
        "date": "2018-06-11T19: 48: 51",
        "date_gmt": "2018-06-11T19: 48: 51",
        "guid": {
            "render": "http: //dev.wordpress.test/? post_type = documentation & p = 4"
        },
        "modifié": "2018-06-11T19: 48: 51",
        "modified_gmt": "2018-06-11T19: 48: 51",
        "slug": "test-documentation",
        "status": "publier",
        "type": "documentation",
        "link": "http: //dev.wordpress.test/documentation/test-documentation/",
        "Titre": {
            "render": "Documentation de test"
        },
        "contenu": {
            "render": "

Ceci est du contenu de la documentation

n",             "protected": false         },         "Featured_media": 0,         "modèle": "",         "documentation-category": [             2         ],         "_liens": {             "soi": [ { "href": "http://dev.wordpress.test/wp-json/wp/v2/documentation/4" } ],             "collection": [ { "href": "http://dev.wordpress.test/wp-json/wp/v2/documentation" } ],             "à propos": [ { "href": "http://dev.wordpress.test/wp-json/wp/v2/types/documentation" } ],             "version-history": [ { "href": "http://dev.wordpress.test/wp-json/wp/v2/documentation/4/revisions" } ],             "wp: attachement": [ { "href": "http://dev.wordpress.test/wp-json/wp/v2/media?parent=4" } ],             "wp: terme": [ { "taxonomy": "documentation-category", "embeddable": true, "href": "http://dev.wordpress.test/wp-json/wp/v2/documentation-category?post=4" } ],             "curies": [ { "name": "wp", "href": "https://api.w.org/{rel}", "templated": true } ]         }     } ]

C'est un excellent point de départ pour notre application d'une seule page. Pour ajouter un point de terminaison personnalisé, vous pouvez également vous connecter au crochet de repos_api_init et créer nous-mêmes un point de terminaison. Ajoutons un itinéraire à documentation personnalisée légèrement différent de celui que nous avons enregistré. Toujours dans le même plugin, nous pouvons ajouter:

 / **
 * Créer un point de terminaison personnalisé
 *
 * @since 1.0.0
 * /
fonction publique create_custom_documentation_endpoint () {
  register_rest_route (
    self :: PLUGIN_NAME. '/ v1', '/ custom-documentation',
    tableau (
        'méthodes' => 'GET',
        'callback' => [ $this, 'get_custom_documentation' ],
    )
  )
}

/ **
 * Créer un rappel pour le noeud final de la documentation personnalisée
 *
 * @return chaîne JSON qui indique le succès / échec de la mise à jour,
 * ou JSON qui indique qu'une erreur s'est produite.
 * @since 1.0.0
 * /
fonction publique get_custom_documentation () {
  / * Certaines vérifications d'autorisation peuvent être ajoutées ici. * /

  // Renvoie uniquement le nom de la documentation et le nom de la balise.
  $ doc_args = array (
      'post_type' => self :: POST_TYPE_SLUG,
      'post_status' => 'publier',
      'perm' => 'lisible'
  )

  $ query = new  WP_Query ($ doc_args);

  $ réponse = [];
  compteur $ = 0;

  // La boucle
  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 ++;
    }
  } autre {
    $ response = esc_html __ ('Il n'y a pas de messages.', 'documentation-plugin');
  }
  / * Restaurer les données de post d'origine * /
  wp_reset_postdata ();

  return rest_ensure_response ($ response);
}

Et accrochez la méthode create_custom_documentation_endpoint () à la méthode rest_api_init comme suit:

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

Ceci ajoutera un itinéraire personnalisé dans le fichier http: //dev.wordpress.test/wp-json/documentation-plugin/v1/custom-documentation renvoyant la réponse pour cet itinéraire.

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

Vous pouvez faire beaucoup d'autres choses avec l'API REST (pour plus d'informations, consultez le Manuel de l'API REST ).

Contournement des temps de réponse longs lors de l'utilisation de l'API REST par défaut [19659023] Pour ceux qui ont essayé de créer un site WordPress découplé, il ne s'agit pas d'une nouveauté: l'API REST est lente.

Mon équipe et moi avons d'abord rencontré l'étrange API REST retardée sur WordPress sur un site client (non découplée). , 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 du plug-in Advanced Custom Fields Pro . Il s'est avéré que le temps nécessaire au premier octet (TTFB) – qui sert à indiquer la réactivité d'un serveur Web ou d'une autre ressource réseau – prenait plus de 3 secondes.

Après un peu d'investigation, nous avons réalisé le réglage par défaut. Les appels d'API REST étaient en réalité très lents, en particulier lorsque nous avons «chargé» le site de plug-ins supplémentaires. Nous avons donc fait un petit test. Nous avons installé quelques plugins populaires et rencontré des résultats intéressants. L’application Postman indique un temps de chargement de 1,97 pour 41,9 Ko de taille de réponse. Le temps de chargement de Chrome était de 1.25s (TTFB de 1.25s, le contenu a été téléchargé en 3.96ms). Juste pour récupérer une simple liste de messages. Pas de taxonomie, pas de données utilisateur, pas de méta-champs supplémentaires.

Pourquoi?

Il s'avère que l'accès à l'API REST sur WordPress par défaut chargera l'intégralité du cœur de WordPress pour servir les points finaux, même s'il n'est pas utilisé. . En outre, plus vous ajoutez de plugins, plus les choses vont mal. Le contrôleur REST par défaut WP_REST_Controller est une très grande classe qui fait beaucoup plus que nécessaire pour créer une page Web simple. Il gère l'enregistrement des itinéraires, la vérification des autorisations, 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 leur chargement lorsque vous devez servir un serveur. simple réponse REST;
  2. Chargez uniquement le strict minimum de WordPress et stockez les données dans un transitoire à partir duquel nous extrayons ensuite les données à l'aide d'une page personnalisée.

Amélioration des 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 vous offre l'API REST. Bien entendu, c’est là qu’une bonne planification est cruciale. Vous ne voulez vraiment pas construire votre site sans API REST, puis dire dans quelques années que vous souhaitez vous connecter à votre site, ou peut-être créer une application mobile qui doit utiliser les fonctionnalités de l'API REST.

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

  • API Transients pour la mise en cache,
  • Chargement du minimum requis de WordPress à l'aide de SHORTINIT constante.

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

Créons un petit plug-in qui va démontrer l'effet dont nous parlons. Tout d’abord, ajoutez un fichier wp-config-simple.php dans votre plug-in json-transitient qui ressemble à ceci:

 <? Php
/ **
 * Créer une configuration wp simple pour les routes
 *
 * @since 1.0.0
 * @package json-transitoire
 * /

define ('SHORTINIT', vrai);
$ parse_uri = explode ('wp-content', $ _SERVER ['SCRIPT_FILENAME']);
require_once filter_var ($ parse_uri [0]. 'wp-load.php', FILTER_SANITIZE_STRING);

La définit ('SHORTINIT', true); empêchera le chargement de la majorité des fichiers de base WordPress, comme le montre le fichier wp-settings.php .

Nous avons peut-être encore besoin de certaines fonctionnalités de WordPress. Nous pouvons donc utiliser le fichier manuellement (comme wp-load.php ). Puisque wp-load.php se trouve à la racine de notre installation WordPress, nous le récupérerons en récupérant le chemin de notre fichier avec $ _ SERVER ['SCRIPT_FILENAME']puis en l'explosant de . ] wp-content chaîne. Cela retournera un tableau avec deux valeurs:

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

N'oubliez pas que nous utilisons le paramètre par défaut. installation de WordPress, et non modifiée, comme par exemple dans le Bedrock, qui divise WordPress en une organisation de fichier différente.

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

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

 <? php / **
 * Plugin de test
 *
 * @since 1.0.0
 * @package json-transitoire
 *
 * @ wordpress-plugin
 * Nom du plugin: Json Transient
 * URI du plugin:
 * Description: preuve de concept pour la mise en cache des appels comme des appels
 * Version: 1.0.0
 * Auteur: Infinum 
 * URI de l'auteur: https://infinum.co/
 * Licence: GPL-2.0 +
 * URI de la licence: http://www.gnu.org/licenses/gpl-2.0.txt
 * Domaine de texte: json-transitoire
 * /

espace de noms Json_Transient;

// Si ce fichier est appelé directement, annulez.
if (! defini ('WPINC')) {
  mourir;
}

classe Init {
  / **
   * Obtenir le tableau des types autorisés à effectuer des opérations.
   *
   * @return array
   *
   * @since 1.0.0
   * /
  fonction publique get_allowed_post_types () {
    return array ('post', 'page');
  }

  / **
   * Vérifiez si le type de message est autorisé à être enregistré dans transitoire.
   *
   * @param string $ post_type Récupère le type de message.
   * @return boolean
   *
   * @since 1.0.0
   * /
  fonction publique is_post_type_allowed_to_save ($ post_type = null) {
    si (! $ post_type) {
      retourne faux;
    }

    $ allowed_types = $ this-> get_allowed_post_types ();

    if (in_array ($ post_type, $ allowed_types, true)) {
      retourne vrai;
    }

    retourne faux;
  }

  / **
   * Obtenez le nom du cache de la page pour les éléments transitoires par courrier et tapez.
   *
   * @param string $ post_slug Page Slug à sauvegarder.
   * @param string $ post_type Type de page à enregistrer.
   * @retour string
   *
   * @since 1.0.0
   * /
  fonction publique get_page_cache_name_by_slug ($ post_slug = null, $ post_type = null) {
    if (! $ post_slug ||! $ post_type) {
      retourne faux;
    }

    $ post_slug = str_replace ('__trashed', '', $ post_slug);

    retourne 'jt_data_'. $ post_type. '_'. $ post_slug;
  }

    / **
   * Obtenez toutes les données postales en post slug et tapez.
   *
   * @param string $ post_slug Slug de page pour faire une requête par.
   * @param string $ post_type Type de page à interroger.
   * @return array
   *
   * @since 1.0.0
   * /
  fonction publique get_page_data_by_slug ($ post_slug = null, $ post_type = null) {
    if (! $ post_slug ||! $ post_type) {
      retourne faux;
    }

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

  / **
   * Page de retour au format JSON
   *
   * @param string $ post_slug Slug de page.
   * @param string $ post_type Type de page.
   * @return json
   *
   * @since 1.0.0
   * /
  fonction publique get_json_page ($ post_slug = null, $ post_type = null) {
    if (! $ post_slug ||! $ post_type) {
      retourne faux;
    }

    return wp_json_encode ($ this-> get_page_data_by_slug ($ post_slug, $ post_type));
  }

  / **
   * Mise à jour de la page sur transitoire pour la mise en cache sur les crochets d'action save_post.
   *
   * @param int $ post_id Identifiant de poste enregistré fourni par l'action hook.
   *
   * @since 1.0.0
   * /
  fonction publique 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 (! $ nom_cache) {
      retourne faux;
    }

    if ($ post_status === 'auto-draft' || $ $ post_status === 'inherit') {
      retourne faux;
    } else if ($ post_status === 'corbeille') {
      delete_transient ($ cache_name);
    } autre  {
      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’aide décrites dans le code ci-dessus nous permettront d’effectuer une mise en cache:

  • get_allowed_post_types ()
    Cette méthode indique aux types de publication que nous souhaitons activer l’affichage dans notre ‘endpoint’ personnalisé. Vous pouvez étendre cela et le plug-in que nous avons réellement 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 post Le type que nous essayons d'extraire des 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 renvoie le nom du transitoire à partir duquel les données seront extraites.
  • get_page_data_by_slug ()
    Cette méthode est la méthode qui effectuera le WP_Query sur le message via son slug et le type de message et renverra le contenu du tableau de messages que nous convertirons. avec le JSON utilisant la méthode get_json_page () .
  • update_page_transient ()
    Elle sera exécutée sur le hook save_post et écrasera le transient dans la base de données. avec les données JSON de notre post. 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 détail.

API Transients

L'API Transients est utilisée pour stocker des données dans la table des options de votre Base de données WordPress pour 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 de pages complètes pouvant être persistés lors du chargement de pages. Il est similaire au cache d'objets WordPress classique, mais contrairement à WP_Cache les données transitoires conserveront les données lors du chargement de pages, alors que WP_Cache (stockage des données en mémoire) conserver les données pendant la durée d'une requête.

Il s'agit d'un magasin de valeurs-clés, ce qui signifie que nous pouvons facilement et rapidement récupérer les données souhaitées, comme ce que utilisait comme système de cache en mémoire comme Memcached ou Redis faire. La différence est que vous devez généralement les installer séparément sur le serveur (ce qui peut poser problème sur des serveurs partagés), alors que les transitoires sont intégrés à WordPress.

Comme indiqué sur sa page Codex, les transitoires sont accélérés de manière inhérente. en mettant en cache des plugins. Puisqu'ils peuvent stocker des 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 transitoire est toujours présent dans la base de données – c’est pourquoi il est recommandé de vérifier son existence avant de l’extraire

 $ transient_name = get_transient ('transient_name');
if ($ transient_name === false) {
  set_transient ('nom_tradient', $ données_destransport, $ transient_expiry);
}

Vous pouvez l’utiliser sans expiration (comme nous le faisons) et c’est la raison pour laquelle nous avons mis en place une sorte de «contournement de cache» après la 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 des données de cette taille dans un seul champ de base de données.

Lecture recommandée : [19659107] Soyez vigilant: Fonctions PHP et WordPress pouvant nuire à la sécurité de votre site

Point final: tests et vérification

Le dernier élément du puzzle dont nous avons besoin est un «point final». J'utilise le terme terminal ici, même s'il ne s'agit pas d'un terminal car 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));

// Retourne l'erreur sur false.
if ($ cache === false) {
  wp_send_json ('Erreur, la page n'existe pas ou elle n'est pas correctement mise en cache. Essayez de reconstruire le cache et essayez à nouveau!');
}

// Décode json pour la sortie.
wp_send_json (json_decode ($ cache));

Si nous passons à http: //dev.wordpress.test/wp-content/plugins/json-transient/test.php nous verrons le message suivant:

Erreur, page slug ou le type est manquant!

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

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

Oh, attendez! Nous devons d'abord ré-enregistrer nos pages et nos publications. Donc, 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 mis en place un moyen de supprimer les transitoires dans le plug-in découplé JSON découplé et de les reconstruire par lot.

Mais poursuivez et sauvegardez le Hello World . postez et ouvrez de 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": "Bienvenue dans WordPress. Il s'agit de votre premier message. Modifiez-le ou supprimez-le, puis commencez à écrire!",
  "post_title": "Bonjour tout le monde!",
  "post_excerpt": "",
  "post_status": "publish",
  "comment_status": "ouvert",
  "ping_status": "ouvert",
  "post_password": "",
  "post_name": "bonjour le monde",
  "to_ping": "",
  "cinglé": "",
  "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",
  "filtre": "brut"
}

Et c’est tout. Le plug-in que nous avons créé offre des fonctionnalités supplémentaires que vous pouvez utiliser, mais en résumé, voici comment vous pouvez extraire les données JSON de WordPress plus rapidement que l'utilisation de l'API REST.

Avant et après: Amélioration du temps de réponse

Nous avons effectué des tests sous Chrome, où nous pouvions 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. Nous avons également testé la réponse pour une liste de publications et pour une publication unique.

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


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

 Graphique de comparaison décrivant les temps de réponse de l'utilisation de l'API REST de WordPress 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 décrivant les temps de réponse de l'utilisation de l'API REST de WordPress 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 constater, la différence est radicale.

Problèmes de sécurité

Il convient d’examiner attentivement certaines mises en garde. Tout d’abord, nous chargeons manuellement les fichiers de base de WordPress, qui dans le monde de WordPress est un gros no-no. Pourquoi? Outre le fait que l'extraction manuelle des fichiers de base 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, soyez Assurez-vous de savoir comment renforcer la sécurité de votre serveur.

Ajoutez d’abord des en-têtes HTML comme dans le fichier test.php :

 ('Access-Control-Allow-Origin: your-front- end-app.url ');

en-tête ('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 extraire le contenu lorsqu'elle se rend dans le fichier spécifié.

Deuxièmement, désactivez le parcours du répertoire 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.

Ajout en cours une vérification de jeton à la réponse est également une bonne mesure qui peut empêcher un accès indésirable. Nous travaillons actuellement sur un moyen de modifier notre plug-in JSON découplé afin d'inclure ces mesures de sécurité par défaut.

La vérification de l'en-tête Authorization envoyé par l'application frontend pourrait ressembler à ceci:

 if (! Isset ($ _SERVER ['HTTP_AUTHORIZATION'])) {
  revenir;
}

$ auth_header = $ _SERVER ['HTTP_AUTHORIZATION'];

Then you can check if the specific token (a secret that is only shared by the front- and back-end apps) is provided and correct.

Conclusion

REST API is great because it can be used to create fully-fledged apps — creating, retrieving, updating and deleting the data. The downside of using it is its speed.

Obviously, creating an app is different than creating a classic website. You probably won’t need all the plugins we installed. But if you just need the data for presentational purposes, caching data and serving it in a custom file seems like the perfect solution at the moment, when working with decoupled sites.

You may be thinking that creating a custom plugin to speed up the website response time is an overkill, but we live in a world in which every second counts. Everyone knows that if a website is slow, users will abandon it. There are many studies that demonstrate the connection between website performance and conversion rates. But if you still need convincing, Google penalizes slow websites.

The method explained in this article solves the speed issue that the WordPress REST API encounters and will give you an extra boost when working on a decoupled WordPress project. As we are on our never-ending quest to squeeze out that last millisecond out of every request and response, we plan to optimize the plugin even more. In the meantime, please share your ideas on speeding up decoupled WordPress!

Smashing Editorial(md, ra, yk, il)




Source link