Websupporter

Vor allem über WordPress.

Warum Ajax über die WP REST API laufen lassen?

Die WP REST API hat in den letzten Monaten immer wieder für Wirbel gesorgt. Viel wurde geschrieben. Decoupled Themes, decoupled admins, mobile apps und jede Menge andere Schlagwörter fliegen durch die Luft. Ab sofort werden Themes total anders geschrieben werden, lernt REACT! Die einen „Yeah“ die andern 😱
Na toll, da hat man sich gerade ein wenig in die WordPress Entwicklung reingefunden und gleich soll wieder alles anders werden?

Doch, wenn wir es mal kurz runterbrechen und uns mit einem ganz alltäglichen Beispiel der REST API annähern verschwinden viele der Sorgen. Ein großer Vorteil, den die WP REST API derzeit für jeden mitbringt: Sie bietet ein schnelleres Interface für Ajax Requests und das ist doch erstmal super.

Bisher haben wir Ajax Anfragen an die wp-admin/admin-ajax.php geschickt. Und – gelinde gesagt – das ist eine ziemlich langsame Methode. Dieser Weg war ursprünglich für ein paar Ajaxabfragen im Admin gedacht, blieb aber die einzige Schnittstelle und wurde deshalb auch von Plugins und so weiter für das Frontend genutzt.

Zwei Nachteile hat dieser Weg:

  • Manche sperren den wp-admin/-Ordner komplett via .htaccess. Ob gut oder schlecht, hilfreich oder nicht sei einmal dahingestellt. Doch dies bedeutet, dass Ajax-Requests hier so lange gegen die Wand laufen, bis man sich im Browser authentifiziert hat. Genau das sollen Frontend-Nutzer ja nicht; die Ajax-Anfragen funktionieren also nicht.
  • Die admin-ajax.php lädt den kompletten Admin, die ganzen Filter, die ganzen Hooks, alles mögliche, was wir für unsere Requests überhaupt nicht benötigen. Die Folge: Eine Ajax Abfrage, eigentlich bekannt für ihre Geschwindigkeit, lahmt.

In meinen Tests konnte ich für die gleiche Operation auf einer ziemlich leeren Seite (ein bißchen Content, BuddyPress und mein Plugin installiert) deutliche Ladezeit-Einsparungen erzielen:

Zehn Abfragen über admin-ajax.php
Zehn Abfragen über admin-ajax.php – 1,93 Sekunden

Zehn Abfragen über die REST API
Zehn Abfragen über die REST API – 1,25 Sekunden

Die REST API ist also ziemlich flott und die meisten Plugins lassen sich relativ schnell von einer Methode auf die andere umstellen. Dies mache ich gerade mit meinem BuddyPress Desktop Notifications Plugin, welches bald in Version 0.9 herauskommen wird und BuddyPress Nutzern Notifications anzeigt.

Sehen wir uns zunächst den bisherigen Code für den Ajax-Request an:

Embed from gist.github.com

Click the button below to load the content from gist.github.com.

Wir registrieren die Ajax Action Hook, sammeln unsere Daten in der Variablen $entries, geben diese als JSON Objekt aus und lassen das Script sterben.

Die selbe Funktion über die REST API:

Embed from gist.github.com

Click the button below to load the content from gist.github.com.

Erst einmal sieht es sehr viel mehr Code aus, das liegt aber vor allem an meinen Kommentaren, da ich mir vorgenommen habe, das Plugin langsam auch mal etwas schöner zu kommentieren. Schaut man sich die zentrale dn_query() an, sieht man, dass sich der Code kaum geändert hat. Nur gebe ich nun kein JSON-Objekt mehr mit echo aus und lasse das Script sterben sondern gebe die $entries zurück. Den Rest erledigt die REST API für mich.

Wir registrieren nun eine neue API REST Route im Action Hook rest_api_init. Dazu nutzen wir die Funktion register_rest_route(). Der erste Parameter gibt unseren „Namespace“ an, den können wir frei wählen, aber ich glaube, hier werde ich einfach immer meinen Plugin Slug verwenden, um mögliche Konflikte zu vermeiden und danach geben ich im zweiten Parameter meine Route an. Aus diesen Angaben ergibt sich zum Schluss die URL zu diesem Endpunkt.

Hat das Script früher
http://localhost/wp-admin/admin-ajax.php

aufgerufen, so wird es jetzt
http://localhost/buddypress/wp-json/buddypress-desktop-notification/v1/notifications

aurufen müssen.

Danach übergebe ich zum einen Optionen-Array, in welchem die Methode festgelegt wird (in meinem Fall WP_REST_Server::READABLE was schlicht GET entspricht, die Callback-Funktion, meine gute alte dn_query(), sowie die erwarteten Argumente, also übergebenen Parameter. In meinem Fall since. Die darüber übergebenen Werte werden mit der in validate_callback hinterlegten Funktion dn_strtotime() validiert, so dass ich sicher sein kann, dass die Daten vor dem Aufruf von dn_query() valide sind. Schließlich, da nur eingeloggte Nutzer ihre Benachrichtigungen sehen sollen, lege ich im permission_callback die Funktion is_user_logged_in() fest.

Und das war es auch beinahe schon. Da ich bisher auch die admin-ajax.php über wp_localize_script() übergeben hatte musste ich hier die URL entsprechend nur austauschen:

esc_url_raw( rest_url() ) . 'buddypress-desktop-notification/v1/notifications'

Gibt mir die komplette URL zu meinem Endpoint zurück.

Darüber hinaus muss ich im Script ein Nonce übergeben, welches die Sicherheit der Ajax-Abfrage erhöht, so dass mein Localize-Array nun etwa so aussieht:

'ajax_url' => esc_url_raw( rest_url() ) . 'buddypress-desktop-notification/v1/notifications',
'nonce' => wp_create_nonce( 'wp_rest' ),

Auf Javascript-Seite sieht meine jQuery.ajax() nun folgendermaßen aus:

Embed from gist.github.com

Click the button below to load the content from gist.github.com.

Entscheidend ist hier vor allem der beforeSend-Teil. Da die Notifications ja nur für eingeloggte Benutzer auf meiner Seite sichtbar sein sollen nutze ich die eingebaute COOKIE-Authentifizierung und muss zusätzlich noch das Nonce im Header 'X-WP_Nonce' mit übergeben.

Done und fast 50 Prozent schnellere Abfragen und dafür lohnt es sich allemal, sich ein wenig durch die Dokumentation der API zu wühlen. Ihr werdet schnell feststellen, das ist nicht der einzige Grund, warum sich das lohnt!

Über den Autoren

Seine erste Webseite hat David Remer 1998 in HTML verfasst. Wenig später war er fasziniert von DHTML und JavaScript. Heute konzentriert sich vor allem auf das Entwickeln von WordPress Themes und Plugins für Inpsyde. Außerdem hat er das Buch "WordPress für Entwickler" verfasst.

Kommentare

  1. Das liest sich echt gut. Ich meinerseits wollte jedoch noch warten, mich auf die REST-API einzulassen, weil man doch immer wider liest dass sie noch nicht stabil wäre. Ich möchte nicht die Ajax-Aufrufe auf REST umstellen, um dann in 1 Jahr dasselbe nochmal tun – würde ich mir gern sparen ….

    1. Hi Andreas,
      der erste Teil der Rest API, auf den ich mich hier beziehe, sozusagen die Serverinfrastruktur ist ja schon Bestandteil des WordPress Core, als solche ist dieser Teil stabil und bei der Weiterentwicklung wird auf die Backwards Compatibility geachtet.

      Also, ich kann es ganz gut verstehen, wenn man insgesamt noch etwas abwarten möchte. Tatsächlich wird derzeit beispielsweise ein Update der schon im Core befindlichen API ausgerollt, welches nicht ganz abwärtskompatibel ist. Allerdings bin ich insgesamt recht zuversichtlich, dass der erste Teil den Kinderschuhen langsam entwachsen ist.

      Anders verhält es sich mit dem zweiten Teil der Rest API, die einzelnen Endpoints für beispielsweise Posts und Users. Dieser ist nach wie vor in grundlegender Bearbeitung und derzeit nur als Plugin installierbar. Hier gibt es nach wie vor tiefgreifende Änderungen. Wenn man diese tatsächlich schon einsetzen möchte, dann wird das mitunter etwas holprig (der Produktiveinsatz ist meines Wissens derzeit auch nicht empfohlen).

    1. Hi Hansjörg,
      ja, dieser Beitrag wendet sich eher an Entwickler von WordPress Plugins und einem reinen Anwender wird das wahrscheinlich nicht so viel bringen.

      Prinzipiell versucht der Beitrag anhand eines Beispiels zu demonstrieren, dass Pluginautoren relativ leicht ihre Ajax-Requests über die REST API laufen lassen können, was eben einige Vorteile bereithält. Es geht dabei nicht ausschließlich um BuddyPress Addons, sondern sämtliche WordPress Plugins.

      Wenn Du als Anwender daran interessiert bist, ob die Ajax Anfragen der Plugins, die Du verwendest, über die REST API laufen, dann kannst Du in Deiner Browser-Konsole sehen, ob die Anfragen an wp-admin/admin-ajax.php gehen oder aber über wp-json/….

      Da die REST API allerdings noch realtiv frisch ist laufen die meisten Plugins noch über die admin-ajax.php, folglich dieser kleine Beitrag 🙂

      1. Hi David

        Danke für die Erläuterungen. Ehrlicherweise muss ich gestehen, bis dato noch nichts von der REST API mitbekommen zu haben. Aber wenn ich das richtig verstanden habe, erfolgen damit Ajax Requests schneller als in der herkömmlichen Art und Weise, oder?
        Bringt ein Plugin wie https://de.wordpress.org/plugins/rest-api/ hier eine Möglichkeit, als „Anwender“ die oben gemachten Tipps umzusetzen?

        Gruß

        Hansjörg

        1. Hallo Hansjörg,
          wenn ich Dich richtig verstehe hast Du – als Anwender – ein Plugin, welches Ajax Requests durchführt und Du fragst mich, ob Du, wenn Du das Rest-API Plugin installierst, diese Ajax Requests sozusagen dahin umleiten könntest. Dann kurz und knapp nein.

          Der Pluginautor könnte sein Plugin umschreiben, damit es die Rest API, welche schon Teil von WordPress ist und nicht extra installiert werden muss, statt den bisherigen Weg nutzt.

          Die ganze Geschichte um die REST API ist tatsächlich eine ziemlich lange, vielleicht sollte ich demnächst einen Blogpost sozusagen „für Anwender“ beziehungsweise zur REST API allgemein machen.

          Vielleicht einen Beitrag: Was ist die REST API, warum ist da schon was im WordPress Core, wieso gibt es da trotzdem noch ein Plugin, warum gibt es eine Version 2, was unterscheidet das Plugin im Repository vom Plugin auf GitHub, was ist geplant für die WordPress Verion 4.7… Hmhmhm, ich sehe, ich mache mir gerade schon Notizen. Mal sehen, vielleicht irgendwann die nächsten Wochen mache ich da nochmal einen Beitrag.

  2. Aus den Releasenotes zu WP 4.5:
    Developers who utilize the REST API infrastructure will want to take note of a breaking change in this release that could potentially cause issues with plugins that depend on the API. The changes break backwards compatibility for the sake of fixing a bug regarding slashed data.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.