Category: WordPress

Nonces in der REST API

Wenn Du einfach mal schnell ein Nonce in der REST API von WordPress validieren möchtest kann es passieren, dass Du auf ein kleines Hindernis stößt. Ich hatte letztens ein kleines Script geschrieben, welches entweder über die admin-ajax.php läuft, wenn die REST API nicht vorhanden ist, ober aber über die REST API.

Schauen wir uns folgendes Script an, um das folgende Problem zu verdeutlichen:

Wir registrieren also die Ajax Action für admin-ajax.php und eine neue Rest Route. Der Callback ajax_nonce_test() bereitet im Wesentlichen die Daten auf und führt dann auf nonce_test(), die Funktion, welche auch von der Rest Route /rest-api-nonces/v1/nonce-test aufgerufen wird.

Am Ende registrieren wir noch einen Shortcode, der uns nur schnell die Test-URLs ausgibt.

Soweit der Überblick. Zentral ist nun, was in nonce_test() passiert. Hier wird geprüft, ob das in $request['testnonce'] übergebene Nonce gültig ist. Wenn nicht wird “FALSE” zurückgegeben, oder aber “TRUE”.

Jetzt zum Witz. Loggen wir uns ein, gehen auf die Seite und rufen die admin-ajax.php auf, so werden wir "TRUE" erhalten, über die REST API "FALSE". Whaaaat? Mehrere Sachen sollten hier beachtet werden:

  1. Die REST-API authentifiziert eine⋅n Benutzer⋅in anders als die admin-ajax.php.
  2. Um ein Nonce zu erstellen und zu verifizieren wird die User-ID herangezogen.

Ob ein⋅e Benutzer⋅in eingeloggt ist oder nicht, darüber entscheidet ein Cookie, welcher beim Einloggen hinterlegt wird. Passt der Cookie, sind wir eingeloggt. Geht die Nutzer⋅in auf die admin-ajax.php so ist er oder sie eingeloggt. Die REST API allerdings verwendet eine etwas umfangreichere Cookie-Authentifizierung. Hier genügt nicht ein einfaches Cookie, sondern dieses muss zusammen mit einem – Ironie der Geschichte – gültigen Nonce übergeben werden.

Basics der Authentifizierung in der REST API

In der WP_REST_Server gibt es eine check_authentication Methode, die eigentlich nur aus dem Filter rest_authentication_errors besteht. Wird über diesen Filter ein WP_Error-Objekt übergeben gilt eine Authentifizierung als gescheitert und wir erhalten ein “Du bist nicht berechtigt”-Response zurück. Über diesen Filter können also User-Authentifizierungen stattfinden.

Von Haus aus bringt WordPress die sogenannte “Cookie-Authentifizierung” mit, welche in der rest_cookie_check_errors() stattfindet. Wenn der Prozess in diese Funktion rennt sind wir noch immer – über unseren Cookie – eingeloggt. Doch wenn das entsprechende Nonce nicht gefunden wird, werden wir zunächst ausgeloggt, bevor es – jetzt eben nicht mehr eingeloggt – weiter geht. Wird ein Nonce gefunden, welches allerdings den falschen Wert enthält, so wird ein WP_Error zurückgegeben und der Zugriff ganz geblockt.

Wenn wir also mit dem Codesnippet von oben schließlich in unserem nonce_test()-Callback ankommen, haben wir keine User-ID mehr, die es allerdings braucht, da das Nonce mit einer solchen ID erstellt wurde.

Wie funktioniert Cookie Authentifizierung in der REST API?

Statt also irgendwie willkürlich ein Nonce zu übergeben, welches dann im Callback geprüft wird (es mag Gründe dafür geben, aber in meinem Fall brauchte ich es nicht noch einmal), sollte also ein spezielles Nonce übergeben werden: wp_create_nonce( 'wp_rest' );. Und natürlich muss auch der Parameter stimmen. Das wp_rest Nonce kann entweder über den Parameter _wpnonce oder aber über den Request Header X-WP-Nonce. übergeben werden. Eine gute Einführung dazu findest Du auf der API Dokumentation.

Zurück zu meinem Beispiel

Für meine Zwecke genügte es also, über den _wpnonce Parameter zu gehen. Da das Nonce in der REST API automatisch schon geprüft wird, verschiebe ich die Nonce-Validierung in die Ajax-Funktion. So sieht mein überarbeiteter Code aus:

Fazit

Wenn Du also irgendwo in Deinem Rest API Callback Nonces brauchst, achte darauf dass der Loginstatus der Nutzer⋅innen mit dem im Frontend überein stimmt. Vermutlich erledigt sich damit auch schon die Notwendigkeit für Dich, ein Nonce überhaupt zu benutzen, aber es mag Umstände geben, in denen es Sinn machen kann, auch im Callback Nonces zu validieren.

Ist diese REST API auch was für mich?

FrontKit

In den letzten Jahren ist ja viel über die WordPress REST API geschrieben und spekuliert worden. Das sie fantastisch sei und sich mit ihr alles ändern könne. Zugleich scheint das Thema aber sehr weit weg zu sein von der eigentlichen WordPress Endanwenderin. Auch wenn die REST API mit 4.7 in den Core kommt wird man sich nach wie vor über wp-login.php einloggen, auf das Dashboard gelangen und seine Artikel wie gewohnt schreiben. Obwohl die API im Core ist wird sich für die Endanwenderin erstmal nicht viel geändert haben und zu Recht kann man sich die Frage stellen: Wozu der ganze Hype?

Die REST API ist derzeit vor allem eines: Eine Spielwiese für WordPress Entwicklerinnen. Wenn diese Euch dann begeistert über die API erzählen, dann kriegt Ihr häufig irgendwann kryptische Texte zu lesen und mit leuchtenden Augen berichten wir dann, dass das jetzt die REST API sei.

So sieht also die REST API aus?
So sieht also die REST API aus?

Gerne wird dann, ob der neuen Möglichkeiten, mit hübschen Schlagwörtern um sich geschmissen wie “Decoupled themes“, “Headless CMS“, neue “SAAS”-Modelle und vielleicht am eingängigsten noch “Mobile Apps”, da haben wir dann doch alle schonmal irgendwie drauf gedrückt, auf so eine App, ist aber dann doch etwas unspezifisch. Die Wahrheit ist, dass doch alles noch etwas wolkig daher kommt, so in der Form: Mit der REST API könnte man.

Eine kleine Demo

Also ist dieses REST API jetzt etwas für mich? In diesem kleinen Screencast möchte ich ein Plugin vorführen, welches ich für eine gelungene Anwendung auf Grundlage der REST API halte: Das “FrontKit for WordPress” – ein neuer Frontend Editor.

Wie ich auch schon im Screencast erwähnt habe, ist das Plugin derzeit im Alpha Stadium. In meinen Tests lief es aber wunderbar mit WordPress Twenty Sixteen. Von Hause aus unterstützt das Plugin die offizielle Twenty-Reihe von dreizehn bis 16 und ich denke einmal, dass Twentyseventeen, sobald es erscheint, auch unterstützt werden wird.

Wenn Ihr jedoch keines der offiziellen Themes verwendest, so funktioniert das Plugin erst einmal nicht, denn es weiß nicht, wo es den Inhalt und den Titel eines Blogbeitrags im HTML Code finden kann. Deshalb müsst Ihr in der functions.php Eures Child Themes erklären, dass das Theme FrontKit unterstützt und wo in der HTML-Ausgabe es den Titel und den Inhalt findet.

Sagen wir, Euer Titel ist immer von <h1 class="entry-title"> umschlossen und der Inhalt von einem <div class="entry-content">, so könnte die Unterstützung von FrontKit durch das Theme folgendermaßen deklariert werden:

.single-post sollte dabei im <body>-Tag durch die Funktion body_class() automatisch eingefügt werden.

FrontKit ist nur eines von vielen Beispielen, wie die REST API, welche ab Dezember in WordPress enthalten sein wird, in Zukunft die Arbeit mit WordPress erleichtern und verschönern könnten.

Was denkt Ihr? Habt Ihr andere Beispiele oder vielleicht selbst schon eine Idee, wie Ihr die REST API einsetzen möchtet?

(Private) Metadaten in der REST API

Ich hatte ja schon vor einiger Zeit einen Beitrag verfasst, dass im Zuge der REST API die Funktion register_meta() neue Bedeutung erlangt. Mittlerweile hat sich einiges getan. Nicht nur, dass die API mit 4.7 in den Core kommen soll 🎉: Die WordPress REST API kann nun auch Metadaten ausgeben und authentifizierte Nutzer können Metadaten ändern.

Sagen wir, das Postmetafeld foo soll über die API zugänglich gemacht werden. Dazu muss man foo nun zunächst über register_meta() registrieren. Im ersten Parameter übergibt man, um welchen Typen von Metadatum es sich handelt: Für Metadaten, welche an Seiten oder Beiträge angehängt werden, übergibt man post. Für Usermetadaten user und für Termmetadaten term. Der zweite Parameter enthält die Bezeichnung des Datums, in unserem Fall wäre dies foo und schließlich übergibt man einen Argumentenarray:

  • show_in_rest
    ist ein Boolean. Setzt man ihn auf true wird das Metafeld an die API übergeben.
  • type
    gibt den Typen an. Also beispielsweise, ob es sich um einen string oder um einen integer handelt.
  • description
    dient dazu, eine Beschreibung zu hinterlegen, welche das Feld beschreibt und auch über die API ausgegeben wird.
  • auth_callback
    enthält den bereits aus der ursprünglichen Version von register_meta() bekannten Authentifizierungs Callback.
  • sanitize_callback
    enthält den bereits aus der ursprünglichen Version von register_meta() bekannten Reinigungs Callback, welcher aufgerufen wird, um das Datum vor dem Speichern zu reinigen.
  • single
    gibt an, ob dieses Datum nur ein einziges Mal gespeichert werden kann, oder ob es mehrere Einträge unter dem selben Schlüssel geben kann. Dies entspricht dem single-Boolean in get_post_meta().

Um nun foo über die API bereitzustellen, genügt es schon, den Schlüssel wie folgt zu registrieren:

register_meta( 'post', 'foo', array(
	'show_in_rest' => true,
));

Die Ausgabe in der API sähe dann wie folgt aus:

Ein Metafeld in der Rest API Ausgabe
Ein Metafeld in der Rest API Ausgabe

Da wir das Feld nicht als single ausgewiesen haben, wird es als Array ausgegeben. mit single true würde nur der String zurückgegeben.

Mehr Informationen zur REST API und zu spezifischen Befehlen der REST API finden sich auf wp-api.org.

Private Metafelder

In unserem Gespräch über die REST API auf dem WP Sofa hatte Felix Arntz die Frage aufgeworfen, ob es möglich wäre, Metafelder auch so zu registrieren, dass nur authentifizierte Nutzer die Möglichkeit hätten, diese einzusehen. Man denke beispielsweise an eine App, welche einen Blick auf den tagesaktuellen Umsatz von Produkten wirft. Das wären keine Daten, die man öffentlich zugänglich machen wollte.

register_meta() bietet von sich aus dazu zunächst keine Optionen an, weshalb ich das im Gespräch zunächst verneinte. Doch es wäre ja tatsächlich eine interessante Erweiterung und etwas Schade, wenn das nicht ginge. Heute hatte ich etwas Gelegenheit noch einmal darüber nachzudenken und kam zu dem Schluss, dass register_meta() eine solche Unterscheidung auch gar nicht braucht, weil wir diese während des Registrierungsprozesses selbstverständlich selber treffen können.

Was ich meine: Ein authentifizierter Aufruf in der API ist letztlich ein eingeloggter Benutzer und sämtliche Funktionen wie current_user_can() funktionieren.

Wenn wir also bestimmte Felder über die API nur bestimmten Nutzern zugänglich machen wollen, so können wir dies schon jetzt aufgrund der Art und Weise, wie ein authentifizierter Aufruf in WordPress funktioniert:

add_action( 'rest_api_init', function() {
	if ( ! current_user_can( 'edit_posts' ) ) {
		return;
	}

	register_meta( 'post', 'foo', array(
		'show_in_rest' => true,
	));
});

BuddyPress 2.7 ist auf dem Weg

Gestern wurde die Beta-Version von BuddyPress 2.7 vorgestellt. Die finale Version soll schließlich Mitte Oktober erscheinen. Eines meiner liebsten Erweiterungen ist dabei die überarbeiteten Profilfelder, die jetzt über einen Date-Selector verfügen!

Der neue Date-Selector
Der neue Date-Selector in BuddyPress 2.7

Darüber hinaus wurde erneut am Templatesystem gearbeitet, sowie etliche Performancegewinne erzielt. Gelungen finde ich auch den “Unsubscribe”-Link für Email-Abos. Ab sofort muss man sich dazu nicht mehr einloggen, sondern der Link übernimmt die Abmeldung automatisch und das ist sicherlich viel Wert.

Um 2.7 zu benutzen muss man allerdings mindestens WordPress 4.2 verwenden. Eine Liste aller Änderungen, welche in die neue Version bisher eingeflossen sind, findet sich hier. Die entsprechende Ankündigung hier.

Es ist immer gut, wenn Beta-Versionen von möglichst vielen unterschiedlichen Usern getestet werden, dazu kann man sie hier herunterladen. Denkt aber daran, dass Beta-Versionen nicht für den Produktiveinsatz gedacht sind und mit hoher Wahrscheinlichkeit noch Bugs enthalten. Je mehr Leute allerdings diese Betas durchtesten, desto stabiler wird die endgültige Version schließlich sein. Wenn ihr beim Testen auf ein Problem stoßt, so solltet ihr das Supportforum aufsuchen und dort davon berichten, damit das Problem behoben werden kann, bevor die stabile Version veröffentlicht wird.

Wenn Du BuddyPress bisher noch nicht kennst, hier habe ich einen kleinen Beitrag verfasst was BuddyPress alles kann.

Die ini_get_all() Warnung in WordPress 4.6 angehen

Gestern Nacht wurde WordPress 4.6 veröffentlicht. Dieses Release glänzt mit “Shiny Updates” sowie der Unterstützung nativer Fonts im Admin, aber vor allem unter der Haupe hat sich wieder Einiges getan. Ein großer Dank gebührt dabei neben anderen Dominik Schilling, der dieses Release in führender Rolle begleitet hat und monatelang daran gearbeitet hat. Auch dem deutschsprachigen Polyglot-Team, welches es wieder einmal geschafft hat, alle neuen Textelemente der Version rechtzeitig zur Veröffentlichung übersetzt zu haben, gebührt viel Dank.

Bisher läuft das Update ziemlich reibungslos. Ich beispielsweise hatte auf diesem Blog keinerlei Probleme. Allerdings hat sich gezeigt, dass es in manchen Server-Konfigurationen zu der Ausgabe einer kleinen Fehlermeldung kommen kann:

Warning: ini_get_all() has been disabled for security reasons in /var/www/html/wp-includes/load.php on line 1020
Die Fehlermeldung
Die ini_get_all() Fehlermeldung auf der Login-Seite. In meinem Fall ist sie etwas umfangreicher, da ich diese in einer speziellen Entwicklungsumgebung ausgebe, die mir noch mehr Informationen ausgibt.

Was bedeutet diese Fehlermeldung

WordPress läuft mit PHP. Dein Hoster kann mit Hilfe der Datei php.ini individuell festlegen, einige Funktionen zu deaktivieren. So blockieren einige Hoster beispielsweise den Befehl system() mit dem man System-Befehle ausführen kann. In der Konfigurationsdatei findet sich dazu die Zeile disable_functions. Hier können Funktionen deaktiviert werden, welche vom Hoster als für nicht sicher erklärt werden. Wenn Du also eine solche Fehlermeldung bekommst, so wurde die Funktion ini_get_all() in diese Liste mit aufgenommen.

Das bedeutet allerdings nicht, dass Dein WordPress nun nicht mehr läuft. Allerdings erhälst Du nun eine Fehlermeldung, die ich – zumindest in meinen Tests – auch nicht unterdrücken konnte, indem ich die WordPress Konstante WP_DEBUG auf false setzte (was bei einer Liveseite automatisch der Fall ist, es sei denn, man hätte dies in der wp-config.php absichtlich geändert).

Ist mein WordPress jetzt unsicher?

Was macht die Funktion ini_get_all() eigentlich und warum wird sie in WordPress benötigt? Mit Hilfe dieser Funktion kann man die Konfigurationseinstellungen der php.ini auslesen. Für ressourcenintensive Prozesse versucht WordPress manchmal das in der php.ini gesetzte Arbeitsspeicherlimit hochzusetzen. Dies passiert beispielsweise um sicherzustellen, dass Bilder die hochgeladen werden auch korrekt verarbeitet werden können. Nun erlaubt allerdings nicht jeder Hoster die Einstellungen der Konfiguration mit Hilfe des Befehls ini_set() zu ändern. Um also für diesen Fall gewappnet zu sein führt WordPress 4.6 die Funktion wp_is_ini_value_changeable() ein. Diese Funktion prüft, ob ein bestimmter Wert der php.ini mit Hilfe von ini_set() geändert werden kann. Nur in diesem Fall wird dann versucht beispielsweise das Arbeitsspeicherlimit zu erhöhen. Eine sinnvolle Aktion also, die ein bisschen Ärger sparen kann. Nur: Um das herauszufinden nutzt wp_is_ini_value_changeable() die Funktion ini_get_all() und handelt sich damit Ärger mit anderen Hostern ein, welche es für ein Sicherheitsrisiko halten, einem PHP-Script die aktuelle Konfiguration mitzuteilen?!

Warum die Funktion als unsicher angesehen werden soll erschließt sich mir nicht ganz, allerdings wird sie im beschriebenen Kontext nicht in irgendeiner Art und Weise eingesetzt die als unsicher einzustufen wäre. Dein WordPress ist nicht unsicher wegen der Verwendung von ini_get_all().

Mittlerweile ist ein Patch unterwegs, welches dieses Problem beheben soll. Es ist also davon auszugehen, dass das Problem mit 4.6.1, welches wahrscheinlich in wenigen Tagen herauskommen wird und die ersten Stolpersteine der Version behebt, auch dieses Problem beheben wird.

Soll ich jetzt nicht updaten?

Wenn Du sicher gehen möchtest, dass Du dieses Problem nicht hast, kannst Du vor dem Update prüfen, ob die Funktion bei Dir deaktiviert wurde. Gehe dabei wie folgt vor:

Erstelle eine Datei mit folgendem Inhalt:

<?php phpinfo(); ?>

Nenne diese Datei beispielsweise phpinfo.php. Lade sie via FTP in Deinen Webspace und rufe sie im Browser unter http://deine-domain.de/phpinfo.php auf. Hier siehst Du nun eine Zusammenfassung Deines PHP-Systems. Suche hier mit der Suchfunktion des Browsers nach ini_get_all. Wenn Du nichts findest kannst Du sicher sein, dass diese Funktion nicht deaktiviert wurde.
Wichtig: Lösche die Datei phpinfo.php wieder, da diese Informationen enthält, welche Du eigentlich nicht öffentlich zugänglich haben möchtest.

Alternativ kannst Du auch auf das WordPress Plugin phpinfo zurückgreifen. Dieses Plugin gibt Dir die Informationen im WordPress Admin unter Einstellungen > WordPress phpinfo() aus.

Und natürlich: Wie bei jedem Update solltest Du auch hier natürlich zunächst ein Backup Deiner Seite angelegt haben.

Ich habe aber schon geupdated und jetzt dieses Problem

Richtig ärgerlich an diesem Problem (daneben, dass es die Seite häßlich macht) ist, dass es den Pfad zu Deiner WordPress Installation ausgibt. Das möchtest Du wirklich nicht. Prüfe bei Deinem Hoster, ob Du eine eigene php.ini für Deinen Webspace erstellen kannst. Üblicherweise findet sich so eine Information in der FAQ zu Deinem Webspace. Wenn dies der Fall ist kannst Du eine php.ini einsetzen, welche diese Funktion nicht deaktiviert. Wie Du dabei vorgehst erfährst Du üblicherweise von Deinem Hoster.

Sollte dies nicht möglich sein, bitte Deinen Hoster, diese Funktion nicht zu deaktivieren. Viele Hoster lassen sich auf so etwas ein, wenn man freundlich fragt.

Sollte auch das nicht möglich sein kannst Du zu guter Schluss folgendes machen: Gehe in die Datei wp-includes/load.php. Dort findest Du in Zeile 1020 das Problem. Dort steht:

$ini_all = ini_get_all();

Setze nun vor die Funktion ini_get_all() ein @-Zeichen:

$ini_all = @ini_get_all();

Dies wird die Fehlermeldung unterdrücken. Normalerweise würde ich niemals empfehlen die System-Dateien von WordPress zu ändern, aber in diesem Fall nimmst Du diese Änderung nur temporär vor. Änderungen in den Systemdateien werden mit dem nächsten Update überschrieben. Da das nächste Update allerdings absehbar dieses Problem angegangen sein wird willst Du ja direkt, dass deine Änderung wieder aus dem System getilgt wird.

Wie konnte es zu einem solchen Fehler kommen

Zunächst einmal, es handelt sich um eine relativ kleine Warnung die zwar ärgerlich ist aber nicht Dein System kaputt macht. Seit fast einem Monat wird WordPress 4.6 von vielen unterschiedlichen freiwilligen Helfern auf den unterschiedlichsten Serverkonfigurationen getestet und getestet. Das sind die sogenannten Release Candidates, welche vor der Veröffentlichung einer neuen Version veröffentlicht werden. Kein einziger dieser Helfer hatte allerdings eine Serverkonfiguration, bei der dieses Problem aufgetaucht wäre. Es ist also ein eher seltenes Problem. Verhindern kann jeder ein solches Problem. Gerade, wenn Du von diesem Problem betroffen bist und weist, dass Du eine eher exotische Serverkonfiguration hast wäre es super, wenn Du Dich beim nächsten WordPress Release einbringst und den Release Candidate testest. Natürlich nicht mit Deiner eigenen Webseite. Aber Du könntest ein Unterverzeichnis erstellen, in welchem Du eine Testversion von WordPress am Laufen hast. Wenn dann der Release Candidate veröffentlicht wird (worüber Du beispielsweise in den WordPress News im Admin informiert wirst) kannst Du diesen dort testen und noch bevor die nächste Version draußen ist, würdest Du sehen, ob Du in Probleme rennst wegen der neuen Version oder Deiner Serverkonfiguration. Nicht nur würdest Du Dir dann Ärger ersparen. Es ist super einfach, bei einem solchen Problem dieses schnell zu melden, so dass es gefixt würde, bevor die Version überhaupt veröffentlicht ist. Dazu gibt es das sogenannte Alpha/Beta-Forum, in welchem man sich melden kann. Je mehr Leute testen, desto weniger Fehler wird es geben! Erfahre hier, wie Du mithelfen kannst, WordPress zu verbessern.