Fermer

octobre 8, 2018

Ajout d'itinéraires personnalisés à l'API REST WordPress –


Cet article sur les itinéraires personnalisés a été publié à l'origine par par Torque Magazine et est reproduit ici avec autorisation.

La plupart des discussions sur l'API REST de WordPress ont consisté à interroger les itinéraires par défaut. En ce sens, nous la traitons comme une API monolithique, comme l’API de Twitter par exemple.

La vérité, c’est que l’API WordPress REST n’est pas une API, mais des millions d’API hautement personnalisables, qui peuvent également être utilisé comme un outil pour créer des API. Oui, il existe des itinéraires par défaut, mais ces itinéraires constituent nécessairement un compromis entre des dizaines de millions de sites, y compris de nombreux sites qui n'ont pas encore été créés.

Tout comme WordPress, ce n'est pas que le monde WP_Query l'API REST n'est pas seulement l'API par défaut. S'en tenir aux valeurs par défaut, c'est comme avoir un projet WordPress traditionnel sans jamais créer son propre objet WP_Query ni écraser la requête par défaut de pre_get_posts . C'est possible, mais tous les travaux ne peuvent pas être réalisés avec les routes d'URL par défaut de WordPress.

Il en va de même avec l'API REST.

Dans une récente interview avec le co-principal développeur de l'API REST Ryan McCue. il explique comment la version deux du projet est scindée en deux parties: les routes par défaut et l'infrastructure permettant de créer des API RESTful. Les routes par défaut fournissent d'excellents exemples sur la manière de créer vos propres routes.

Le système utilisé pour ajouter ces routes et points de terminaison est incroyablement bien conçu. Je vais vous montrer les bases de l’utilisation de cet article dans cet article; À titre d’exemple, je vais vous montrer comment créer un itinéraire personnalisé avec deux points de terminaison affichant des informations sur les produits d’un site de commerce électronique optimisé par Easy Digital Downloads (EDD). Cet exemple est basé sur un add-on API que j'ai créé pour mon propre site. Si vous voulez voir la source complète sur GitHub ou l'API en action vous pouvez.

Bien que EDD fournisse sa propre API RESTful, je voulais exposer le champs personnalisés que j'utilise sur mon propre site. Dans ma propre implémentation, j'intègre également un second itinéraire appelé "docs", qui est encapsulé autour d'un type de publication personnalisé que j'utilise pour la documentation.

J'aurais peut-être pu intercepter l'API EDD EDD ou Le type de publication personnalisé et les méta-routes de l'API principale pour faire ce que je voulais, mais pour des raisons de simplicité (et pour avoir quelque chose qui avait exactement ce dont j'avais besoin), j'ai créé mes propres routes et points de terminaison. C'était rapide, amusant et fonctionnait très bien pour les deux endroits où je l'ai implémenté jusqu'à présent.

Ajout de routes

À la rencontre de ma nouvelle fonction favorite

La deuxième version de l'API REST introduit une nouvelle fonction appelée register_rest_route () . Cela vous permet d'ajouter une route à l'API REST et de transmettre un tableau de points de terminaison. Pour chaque point de terminaison, vous ne fournissez pas seulement une fonction de rappel pour répondre à la demande, vous pouvez également définir les champs souhaités dans votre requête, notamment les rappels par défaut, les rappels d'assainissement et de validation, ainsi qu'un rappel des autorisations séparé. 19659004] Il existe des fonctionnalités supplémentaires qui évoluent encore. Je vous recommande de lire la classe pour les routes de publication par défaut. C’est une excellente ressource sur la manière d’utiliser l’API REST pour interroger les publications.

Je vais me concentrer sur ces trois éléments: rappel, arguments de champ et vérification des autorisations. Ces trois fonctions illustreront le fonctionnement de l'architecture de l'API. Ils sont également très utiles car une fois que vous avez reçu votre rappel, vous aurez tous les champs dont vous avez besoin et ils seront nettoyés. Vous saurez également que la demande est autorisée.

Cette architecture impose la séparation des problèmes et permet de garder votre code modulaire.

Configuration de la route

Lorsque vous définissez une route personnalisée, utilisez le register_rest_route () dans une fonction reliée à «rest_api_init», qui est le action qui s'exécute lorsque l'API REST est initialisée. C’est une action importante qui aura probablement autant de valeur que «plugin_loaded» et «init».

Cette fonction accepte quatre arguments:

Le premier est l’espace de nommage de la route. Tous les itinéraires doivent être en mode de noms, ce qui est ensuite utilisé comme segment d'URL suivant après «wp-json». Les itinéraires par défaut sont en mode de noms avec wp. Cela signifie que les routes principales ont des URL telles que "wp-json / wp / posts", alors qu'une route personnalisée "dimensionnant" dans l'espace de noms "happy-hats-store" aurait l'URL "wp-json / happy-hats-store / tailles. ”

Ces espaces de noms se comportent comme des espaces de noms PHP ou des slugs uniques pour les fonctions d'un plugin. Ils évitent les affrontements entre les itinéraires. Ainsi, si j’écris un plug-in qui ajoute un itinéraire appelé menus, il peut être utilisé côte à côte avec un plug-in que vous avez écrit et qui ajoute un itinéraire appelé menus – tant que nous utilisons différents espaces de noms correspondant au nom du plug-in. Les espaces de noms pour les itinéraires sont un système intelligent, car il est très probable que deux développeurs ou plus ajouteront des itinéraires portant le même nom

Le deuxième argument est l’URL située après l’espace de nom de votre itinéraire. Dans cet exemple, mon premier itinéraire est "/ products" et le second est "/ products". ‘/ (? P [d] +).” Le deuxième itinéraire permet d’obtenir un nombre, par exemple un ID de poste dans le dernier segment d’URL. Ces URL de route sont jointes à l'espace de noms. Ainsi, si votre espace de noms est «chewbacca-api» et votre route est «/ products», son URL est «/ wp-json / chewbacca-api / products».

 register_rest_route ('chewbacca-api' , '/ produits', array ());

Il est judicieux d’inclure un numéro de version dans vos espaces de noms. J'ai utilisé calderawp_api / v2 pour mon espace de noms.

Le troisième argument est l'endroit où la vraie magie se produit. C'est l'endroit où vous ajoutez des points d'extrémité à un itinéraire. C'est ce dont traite le reste de cet article, nous allons donc l'ignorer une seconde.

Le quatrième et dernier argument est un argument booléen facultatif, appelé «neutralisation». Il est là pour vous aider à gérer les conflits susceptibles de se produire intentionnellement. ou involontairement avec des itinéraires déjà définis. Par défaut, cet argument est faux et lorsqu'il est faux, une tentative de fusion des itinéraires est effectuée. Vous pouvez éventuellement définir la valeur true pour remplacer les routes déjà déclarées.

Configuration de vos points d'extrémité

Jusqu'à présent, nous avons parlé de la configuration des routes, mais les routes ne sont utiles que si elles ont des points d'extrémité. Dans la suite de cet article, nous allons parler de l'ajout de points de terminaison à la route en utilisant le troisième argument de register_rest_route () .

Méthode de transport

Tous les points de terminaison doivent définir une ou plusieurs méthodes de transport HTTP ( GET / POST / PUT / DELETE). En définissant un noeud final comme ne fonctionnant que via des requêtes GET, vous indiquez à l'API REST où obtenir les données correctes et comment créer des erreurs pour les requêtes invalides.

Dans le tableau définissant votre noeud final, vous définissez vos méthodes de transport dans une clé appelée «méthodes». La classe WP_REST_Server fournit des constantes permettant de définir les méthodes de transport et les types de corps JSON à demander. Par exemple, voici comment définir un noeud final permettant uniquement les requêtes GET:

 register_rest_route ('chewbacca-api', '/ products', array (
    'methods' => WP_REST_Server :: READABLE,
));

Voici comment ajouter une route qui accepte tous les modes de transport:

 register_rest_route ('chewbacca-api', '/ products', array (
    'methods' => WP_REST_Server :: ALLMETHODS,
));

En utilisant ces constantes, que vous pouvez voir dans son intégralité ici vous êtes assuré que vos itinéraires sont correctement configurés pour le serveur REST.

Définition de vos champs

Ce qui est vraiment génial dans la façon dont les points finaux sont définis est que vous spécifiez les champs que vous voulez: quelles sont leurs valeurs par défaut et comment les assainir. Cela permet à la fonction de rappel pour le traitement de la demande de faire confiance aux données extraites.

L’API REST gère tout cela pour vous.

Voici un exemple de la manière dont j’ai configuré le point de terminaison principal des champs qui renvoie une collection. de produits:

 register_rest_route ("{$ root} / {$ version}", '/ products', tableau (
        tableau (
            'methods' =>  WP_REST_Server :: READABLE,
            'callback' => array ($ cb_class, 'get_items'),
            'args' => array (
                'per_page' => array (
                    'default' => 10,
                    'sanitize_callback' => 'absint',
                ),
                'page' => array (
                    'default' => 1,
                    'sanitize_callback' => 'absint',
                ),
                'soon' => array (
                    'default' => 0,
                    'sanitize_callback' => 'absint',
                ),
                'slug' => array (
                    'default' => false,
                    'sanitize_callback' => 'sanitize_title',
                )

            ),

            'permission_callback' => array ($ this, 'permissions_check')
        ),
    )

)

Vous remarquerez que la plupart d'entre eux sont des champs numériques ou booléens. Je les ai donc configurés pour être désinfectés à l'aide de absint () . Il existe un champ pour interroger par courrier postal. J'ai utilisé sanitize_title pour cela, car ils sont désinfectés de la même manière avant d'être écrits dans la base de données.

Mon autre chemin est celui de l'affichage d'un produit par ID. Dans le noeud final de cette route, je n'ai spécifié aucun champ car l'ID passé dans le dernier segment d'URL est suffisant.

 register_rest_route ("{$ root} / {$ version}", '/ products'. '/ (? P & lt ; id & gt; [d] +) ', array (
      tableau (
         'méthodes' = & gt;  WP_REST_Server :: READABLE,
         'callback' = & gt; array ($ cb_class, 'get_item'),
         'args' = & gt; tableau (

         ),
         'permission_callback' = & gt; array ($ this, 'permissions_check')
      ),
   )
)

Vous pouvez utiliser ces exemples pour créer vos propres itinéraires. N'oubliez pas que mes exemples sont écrits dans un contexte d'objet, c'est-à-dire qu'ils vont être utilisés dans une méthode de classe. De plus, cette méthode doit être associée à «rest_api_init».

La fonction de rappel

La fonction de rappel, que vous spécifiez pour chaque route dans la clé «callback», est la méthode à laquelle la demande sera envoyée, si le rappel des autorisations réussit.

Dans mon exemple, je passe mon chemin principal à une méthode de la classe de rappel appelée «get_items» et à la route du produit unique à une méthode appelée «get_item». Ceci est conforme aux conventions énoncées. dans la classe de base post requête. C’est important parce que ma classe de rappel étend cette classe dans l’API principale «WP_REST_Post_Controller». Cela me permet d’absorber beaucoup de ses fonctionnalités tout en définissant mes propres itinéraires. Je discuterai des demandes de traitement et d’y répondre ultérieurement dans cette fonction. À ce stade, nous ne faisons que définir ce que c'est.

Dans la dernière section, je vous ai montré deux enregistrements d'itinéraire. Les deux ont un tableau pour «callback» qui transmet un objet de la classe utilisée pour le rappel et le nom de la fonction.

Le rappel d'autorisations

Comme le rappel principal, cette méthode a transmis un objet de la . WP_Request_Class qui vous permet d'utiliser des parties de la demande pour votre schéma d'authentification. Le rappel des autorisations doit simplement renvoyer true ou false; La façon dont vous y arrivez dépend de vous.

Une stratégie consiste à utiliser la logique de type de vérification des capacités de l’utilisateur actuel que vous utilisez pour le développement WordPress. Cela est possible car la vérification des autorisations sera exécutée une fois que l'utilisateur actuel aura été défini. Par conséquent, si vous utilisez l'une des méthodes d'authentification, elles l'auront déjà exécutée.

Vous n'êtes pas obligé de vous fier à l'utilisateur actuel ou à l'authentification de WordPress. Une chose que vous pouvez faire est d’ajouter une autorisation spécifique pour vos itinéraires personnalisés et de vérifier les parties spécifiques de la demande pour connaître les bonnes clés. Une autre option est, si votre site implémente la connexion sociale, vous pouvez vérifier les clés oAuth, les authentifier auprès de ce réseau et, si elles réussissent, vous connecter à l'utilisateur associé à ce compte.

Je vais discuter de ces stratégies. plus à l'avenir.

Pour l'exemple de cet article, je montre comment créer une API publique en lecture seule. Nous pouvons donc créer une fonction qui retourne toujours true à utiliser comme rappel d'autorisations ou utiliser celle de WordPress. __ return_true . J'avais choisi la première option, donc je l'avais en place pour l'avenir lorsque je commencerais à ajouter des demandes POST authentifiées.

Traitement et réponse aux demandes

La fonction de rappel de chaque point d'extrémité se voit transmettre un objet de la classe WP_REST_Request . Il existe une méthode pour obtenir toutes les données de la requête désinfectées et validées, en remplissant les valeurs par défaut.

La plupart du temps, nous pouvons simplement utiliser la méthode get_params () . Cela nous donne les paramètres de la demande mappée à partir de la méthode de transport que nous avons fournie. Utiliser cette méthode, au lieu d’accéder aux variables globales POST ou GET, est important pour de nombreuses raisons.

Tout d’abord, le tableau renvoyé est validé et nettoyé pour nous. En outre, il gère les basculements entre les méthodes de transport. Cela signifie que si vous changez la définition des points d'extrémité de GET à PUT (c'est-à-dire un changement d'une ligne), tout le code du rappel fonctionnera parfaitement.

Cela conduit également à une meilleure abstraction. Je présente une version de base de mon plug-in complémentaire API dans cet article, mais si vous examinez le code source du plug-in sur lequel il est basé, vous verrez que toutes les requêtes relatives aux points de terminaison des produits et des documents sont traitées. par une classe abstraite qui gère la création d'arguments WP_Query en passant en boucle les résultats et en les renvoyant.

Quelle que soit la façon dont vous gérez le traitement de votre point de terminaison, vous souhaiterez terminer par une instance de WP_REST_Response classe. La meilleure façon de le faire consiste à utiliser la fonction assure_rest_response () qui renvoie une instance de cette classe et peut également gérer les erreurs correctement.

Cette classe garantit que votre réponse est correctement formée, JSON et a le minimum d'en-têtes nécessaires. Il fournit également des méthodes pour ajouter des en-têtes supplémentaires.

Vous pouvez voir ici comment je l'ai utilisé pour ajouter des en-têtes, en fonction de l'ajout d'en-têtes pour les résultats totaux, les pages et les liens précédents / suivants:

 / **.
 * Créez la réponse.
 *
 * @ depuis 0.0.1
 *
 * @access protégé
 *
 * @param  WP_REST_Request $ request Détails complets sur la demande
 * @param array $ args WP_Query Args
 * @param array $ data Données de réponse brutes
 *
 * @return  WP_Error |  WP_HTTP_ResponseInterface |  WP_REST_Response
 * /
fonction protégée create_response ($ request, $ args, $ data) {
   $ response = rest_ensure_response ($ data);
   $ count_query = new  WP_Query ();
   unset ($ args ['paged']);
   $ query_result = $ count_query- & gt; query ($ args);
   $ total_posts = $ count_query- & gt; found_posts;
   $ response- & gt; header ('X-WP-Total', (int) $ total_posts);
   $ max_pages = ceil ($ total_posts / $ request ['per_page']);
   $ response- & gt; header ('X-WP-TotalPages', (int) $ max_pages);


   if ($ request ['page'] & gt; 1) {
      $ prev_page = $ request ['page'] - 1;
      if ($ prev_page & gt; $ max_pages) {
         $ prev_page = $ max_pages;
      }
      $ prev_link = add_query_arg ('page', $ prev_page, rest_url ($ this- & gt; base));
      $ response- & gt; link_header ('prev', $ prev_link);
   }

   if ($ max_pages & gt; $ request ['page']) {
      $ next_page = $ request ['page'] + 1;
      $ next_link = add_query_arg ('page', $ next_page, rest_url ($ this- & gt; base));
      $ response- & gt; link_header ('next', $ next_link);
   }

   return $ response;

}

Vous remarquerez que je n’ai pas expliqué comment rassembler vos données pour obtenir une réponse.

Vous pouvez utiliser WP_Query wpdb get_post_meta ou utiliser les fonctions intégrées à un plugin. C’est à vous de décider, c’est votre API. Ce sont déjà des compétences que vous avez en tant que développeur WordPress.

Dans de nombreux cas, si vous ajoutez une API RESTful à un plugin ou à un site existant, vous devez déjà disposer de classes pour obtenir les données dont vous avez besoin. Vous pouvez utiliser l’API REST pour obtenir les paramètres de ces classes à partir d’une requête HTTP, puis transmettre les résultats à la classe de réponses de l’API REST.

Dans mon API, j’ai utilisé WP_Query pour obtenir les publications. Voici la méthode que j'ai utilisée pour parcourir l'objet WP_Query et obtenir les données dont j'avais besoin:

 / **
 * Demander des produits et créer une réponse
 *
 * @ depuis 0.0.1
 *
 * @access protégé
 *
 * @param  WP_REST_Request $ request Détails complets sur la demande
 * @param array $ args WP_Query args.
 * @param bool $ repondre. Optionnel. Que ce soit pour créer une réponse, la valeur par défaut ou simplement pour renvoyer les données.
 *
 * @return  WP_HTTP_Response
 * /
fonction protégée do_query ($ request, $ args, $ respond = true) {
   $ posts_query = new  WP_Query ();
   $ query_result = $ posts_query- & gt; query ($ args);

   $ data = array ();
   if (! empty ($ query_result)) {
      foreach ($ query_result as $ post) {
         $ image = get_post_thumbnail_id ($ post- & gt; ID);
         si ($ image) {
            $ _image = wp_get_attachment_image_src ($ image, 'grand');
            if (is_array ($ _image)) {
               $ image = $ _image [0];
            }

         }

         $ data [ $post->ID ] = array (
            'nom' = & gt; $ post- & gt; post_title,
            'link' = & gt; get_the_permalink ($ post- & gt; ID),
            'image_markup' = & gt; get_the_post_thumbnail ($ post- & gt; ID, 'large'),
            'image_src' = & gt; $ image,
            'extrait' = & gt; $ post- & gt; post_excerpt,
            'slogan' = & gt; get_post_meta ($ post- & gt; ID, 'product_tagline', true),
            "prix" = & gt; edd_get_variable_prices ($ post- & gt; ID),
            'slug' = & gt; $ post- & gt; post_name,
         )

         pour ($ i = 1; $ i & lt; = 3; $ i ++) {
            foreach (tableau (
               'Titre',
               'texte',
               'image'
            ) en tant que $ field) {
               if ('image'! = $ field) {
                  $ field = "avantage _ {$ i} _ {$ field}";
                  $ data [ $post->ID ][ $field ]  = get_post_meta ($ post-> ID, champ $, true);
               }autre{
                  $ field = "avantage _ {$ i} _ {$ field}";
                  $ _field = get_post_meta ($ post-> ID, champ $, true);
                  $ url = false;

                  if (is_array ($ _field) & amp & isset ($ _field [ 'ID' ])) {
                     $ img = $ _field [ 'ID' ];
                     $ img = wp_get_attachment_image_src ($ img, 'large');

                     if (is_array ($ img)) {

                        $ url = $ img [0];
                     }

                  }
                  $ _field [ 'image_src' ] = $ url;
                  $ data [ $post->ID ][ $field ]  = $ _field;
               }

            }

         }


         retourne $ data;
      }
   }

   si ($ répondre) {
      return $ this- & gt; create_response ($ request, $ args, $ data);
   } autre {
      retourne $ data;
   }

}

Comme vous pouvez le constater, il s'agit d'un mélange de champs de publication, de méta-champs et de fonctions définies par EDD. Encore une fois, si vous voulez voir le code source complet, y compris la façon dont j'ai ajouté un deuxième itinéraire et davantage de points de terminaison à chacun des itinéraires, dirigez-vous sur GitHub et jetez un coup d'œil à .

API personnalisées, comme l'hiver , Sont à venir

Le fait que l'API REST de WordPress ajoute un ensemble utile de routes par défaut à votre site est impressionnant. Ceci est connu.

Ce qui est encore plus excitant et plus impressionnant, c’est qu’au service de la création de routes, nous obtenons un serveur d’API RESTful vraiment impressionnant qui nous donne des outils puissants pour créer nos propres API personnalisées.






Source link