🛠 Sollte WordPress eine GraphQL API im Core haben?
Update 01/05/2024: Schau dir den Vergleich Gato GraphQL vs WP REST API an.
WordPress 5.7 kommt bald. Wie schon seit vielen Versionen wird auch die WP REST API mehrere neue Funktionen mitbringen.
Unter den neuen Funktionen hat eine meine Aufmerksamkeit geweckt: "Image Editor Accepts a List of Modifiers".
Der Endpoint
/wp/v2/media/<id>/edit, der in WordPress 5.5 eingeführt wurde, hatte eine begrenzte API, die Rotations- und Zuschneidedeklarationen auf oberster Ebene akzeptierte. In 50124 wurde diese API leistungsfähiger und flexibler gestaltet, indem ein Array von Modifikationen im neuen Request-Parametermodifiersakzeptiert wird.
import apiFetch from '@wordpress/api-fetch';
const data = {
modifiers: [
{
type: 'crop',
args: {
left : 0,
top : 0,
width : 80,
height: 80
}
},
{
type: 'rotate',
args: {
angle: 90
}
}
]
};
apiFetch( { data, method: 'POST', path: '/wp/v2/media/5/edit' } );Diese Entwicklung hat einige Zeit in Anspruch genommen.
Zunächst wurde in WordPress 5.5 der Endpoint zur Bildbearbeitung eingeführt.
Dieser Endpoint war anfangs recht starr und erforderte, alle Daten zu allen auf das Bild anzuwendenden Operationen zusammen zu übergeben. Um beispielsweise das Bild zu drehen und seine Größe zu ändern, würden wir diese Daten übergeben:
{
"x": 0,
"y": 0,
"width": 80,
"height": 80,
"rotate": 90
}Dann wurden in WordPress 5.6 Batch-Operationen in die WP REST API eingeführt.
Schließlich wurden in dem kommenden WordPress 5.7 die auf das Bild anzuwendenden Operationen entkoppelt, sodass wir die Operationen "crop" und "rotate" haben. Diese Operationen können einzeln ausgeführt werden, aber auch zusammen in derselben Anfrage per Batching.
Wie bereits gezeigt, sieht das Übergeben von Daten an den Endpoint nun viel eleganter aus:
{
"modifiers": [
{
"type": "crop",
"args": {
"left" : 0,
"top" : 0,
"width" : 80,
"height": 80
}
},
{
"type": "rotate",
"args": {
"angle": 90
}
}
]
}Neu erfinden, was schon existiert?
Die WP REST API ist nicht die einzige API für WordPress. Es gibt (mindestens) zwei Alternativen:
- GraphQL, über WPGraphQL
- GraphQL + persisted queries, über Gato GraphQL
(☝🏽 Das bin ich, dein Gastgeber für diesen Blogbeitrag ☝🏽)
GraphQL ist eine relativ neue Art von API, die bei Batch-Operationen glänzt. Mit GraphQL muss man keine Zeit und Energie in die Entwicklung einer eigenen Lösung dafür investieren, wie es bei REST der Fall ist.
Tatsächlich könnte man sagen, dass REST diese Funktion von GraphQL "kopiert".

Die Unterstützung von Batch-Operationen in der WP REST API hat mindestens 2, möglicherweise 3 Release-Zyklen in Anspruch genommen. Das ist keine unerhebliche Zeitspanne, und es erforderte den Beitrag mehrerer Personen.
Wenn WordPress auch GraphQL nutzen könnte und der Endpoint zur Bildbearbeitung auf GraphQL statt auf REST basierte, könnten diese Mitwirkenden stattdessen an anderen Entwicklungen arbeiten.
Wäre WordPress nicht besser dran und würde viel schneller entwickelt werden, wenn es die besten Eigenschaften jeder API nutzen könnte, wann immer es sinnvoll ist?
Batch-Operationen in GraphQL
Ich zeige dir nicht einen, sondern mehrere Wege, wie Gato GraphQL Batch-Operationen unterstützt.
Der erste ist der einfachste: mehrere Felder zur Wurzel der query hinzufügen. Diese query zum Beispiel meldet den Benutzer an und fügt dann einen Kommentar hinzu:
mutation LogUserInAndAddCommentToPost {
loginUser(
by: { credentials: { usernameOrEmail: "test", password: "pass" } }
) {
id
name
}
addCommentToCustomPost(
input: {
customPostID: 1459
commentAs: { html: "Adding a comment: bla bla bla" }
}
) {
id
content
date
}
}(Übrigens ist das der GraphiQL-Client. Hier ist ein Tutorial zur Verwendung.)
Diese beiden Operationen wurden auf verschiedene Objekte angewendet, aber wir möchten mehrere Operationen auf dasselbe Objekt anwenden.
Machen wir das als Nächstes: Diese query fügt demselben Beitrag zwei Kommentare hinzu.
mutation AddTwoCommentsToPost {
firstComment: addCommentToCustomPost(
input: {
customPostID: 1459
commentAs: { html: "This is my first response" }
}
) {
id
content
date
}
secondComment: addCommentToCustomPost(
input: {
customPostID: 1459
commentAs: { html: "This is my second response" }
}
) {
id
content
date
}
}Diese beiden Kommentare wurden einem bereits vorhandenen Beitrag hinzugefügt. Aber was würde passieren, wenn der Beitrag zuerst erstellt werden müsste?
In diesem Fall würde die einfache query nicht mehr funktionieren, weil wir die ID des noch zu erstellenden Beitrags nicht kennen, die als Argument für die anderen Operationen benötigt wird (beachte das ? im Feldargument):
mutation CreatePostAndAddTwoCommentsToPost {
createPost(input: { title: "Some post" }) {
id # <= I don't know what this value will be
}
addCommentToCustomPost(input: {
customPostID: ?,
commentAs: { html: "Blah blah blah" }
}) {
id
content
date
}
}Aber keine Sorge, Gato GraphQL hat dich im Griff. Es bietet nicht eine, sondern zwei Lösungen!

Die erste besteht darin, die Funktion Ausführung mehrerer queries zu verwenden.
In dieser query führen wir die erste Operation aus, exportieren ihr Ergebnis über die Direktive @export und injizieren diesen Wert dann als Eingabe in die zweite query:
mutation AddComment {
addCommentToCustomPost(
customPostID: 1459
commentAs: { html: "Some insightful comment" }
) {
id @export(as: "newCommentID")
content
date
}
}
mutation AddResponseToComment @depends(on: "AddComment") {
replyComment(
parentCommentID: $newCommentID
commentAs: { html: "Debunking your insightful comment" }
) {
id
date
content
parent {
id
}
}
}Noch eleganter können wir verschachtelte Mutations verwenden.
In dieser query führen wir die erste Operation aus und verschachteln die zweite Operation darin, sodass sie auf das während der ersten Operation erstellte Objekt angewendet wird (und dann wiederholen wir das, indem wir eine 3. Operation verschachteln, und so weiter):
mutation AddCommentAndResponseAndResponse {
addCommentToCustomPost(
input: {
customPostID: 1459
commentAs: { html: "Some insightful comment" }
}
) {
id
content
date
reply(input: { commentAs: { html: "Debunking your insightful comment" } }) {
id
date
content
parent {
id
}
reply(input: { commentAs: { html: "No, it was right!" } }) {
id
date
content
parent {
id
}
}
}
}
}Als Bonus können die Batch-Operationen nicht nur auf eine einzelne Entität angewendet werden, sondern auf viele Entitäten gleichzeitig, in derselben Anfrage.
In dieser query werden die neuen Kommentare und alle ihre Antworten mehreren Beiträgen hinzugefügt:
mutation AddCommentAndResponseToManyPosts {
posts(ids: [1657, 1153, 1499, 1459]) {
id
addComment(input: { commentAs: { html: "Some insightful comment" } }) {
id
content
date
reply(
input: { commentAs: { html: "Debunking your insightful comment" } }
) {
id
date
content
parent {
id
}
}
}
}
}Und das Plugin hat noch einen weiteren Trick auf Lager: Mit der Funktion der einbettbaren Felder können wir den Inhalt anpassen, der an jedes Feldargument übergeben wird, und dabei Daten aus dem Objekt selbst verwenden!
In dieser query enthalten die Kommentare Informationen des Objekts, auf dem sie erstellt werden:
mutation AddCustomCommentAndResponseToManyPosts {
posts(ids: [1657, 1153, 1499, 1459]) {
id
addComment(
input: {
commentAs: { html: "The post has ID {{ id }} and title {{ title }}" }
}
) {
id
content
date
reply(
input: {
commentAs: {
html: "The parent comment was posted on {{ dateStr(format: \"d/m/Y\") }}. Cool, right?"
}
}
) {
id
date
content
parent {
id
}
}
}
}
}Das Beste aus REST und GraphQL nutzen, wann immer es sinnvoll ist
Je mehr Full Site Editing entwickelt und ausgebaut wird, desto mehr wird WordPress von seinen APIs abhängen.
Was bestehende Funktionen betrifft, hat die REST API bisher sehr gute Arbeit geleistet. Es besteht keine Notwendigkeit, das neu zu bauen, was nicht kaputt ist.
Aber was neue, noch zu entwickelnde Funktionen betrifft: Würde WordPress nicht davon profitieren, entweder REST oder GraphQL zu verwenden, je nachdem, was für diese spezifische Funktion praktischer ist?
Die Antwort liegt bei dir...
