Entwickler-AnleitungenMit der REST-API arbeiten

Mit der REST-API arbeiten

So rufst du die easy-svg/v1-Routen hinter dem Icons-Panel auf: Anmeldung, Rechte, jede Route mit Feldern, Fehlern und funktionierenden Beispielen.

Tutorial · Easy SVG

Easy SVG registriert sieben REST-Routen im Namensraum easy-svg/v1. Das Icons-Panel im Backend nutzt sie, um die Einstellungen zu lesen und zu speichern und um Icons hinzuzufügen, umzubenennen, neu zu zeichnen und zu löschen. Dieses Tutorial zeigt dir, wie du dieselben Routen selbst aufrufst, aus dem Terminal, aus einem Deployment-Skript oder aus deinem eigenen Admin-JavaScript, und was jede Route annimmt und antwortet.

Diese Routen gibt es, damit das Icons-Panel funktioniert. Sie gehören nicht zur öffentlichen Schnittstelle, die die readme verspricht: Dort steht eine kurze Liste von Funktionen, Hooks und Konstanten, und alles andere ist laut readme ein internes Detail, das umbenannt oder entfernt werden kann. Behandle jede Route auf dieser Seite als intern. Halte die Plugin-Version fest, gegen die du getestet hast, prüfe die Antwortform, bevor du dich darauf verlässt, und nimm die öffentlichen PHP-Funktionen (easy_svg_rename_icon(), easy_svg_update_icon_markup()), wenn dein Code ohnehin in WordPress läuft.

Die Routen auf einen Blick

RouteMethodeWas sie tutReferenz
/wp-json/easy-svg/v1/settingsGET, POSTLiest oder speichert die Funktionsschalter und die Größengrenzerest-settings
/wp-json/easy-svg/v1/libraryGETListet die gespeicherten Icons, optional durchsuchtrest-library
/wp-json/easy-svg/v1/library/addPOSTFügt ein Icon aus SVG-Markup hinzurest-library-add
/wp-json/easy-svg/v1/library/mediaPOSTMacht aus SVGs der Mediathek Iconsrest-library-media
/wp-json/easy-svg/v1/library/renamePOSTÄndert den sichtbaren Namen eines Iconsrest-library-rename
/wp-json/easy-svg/v1/library/replacePOSTGibt einem Icon eine neue Zeichnungrest-library-replace
/wp-json/easy-svg/v1/library/deletePOSTLöscht ein Icon endgültigrest-library-delete

Alle werden auf rest_api_init von easy_svg_panel_rest() in includes/panel.php registriert. Die Routen sind immer da, egal ob der Schalter für die Icon-Bibliothek an ist oder nicht (mehr dazu unter Stolperfallen).

Anmeldung

Jede Route braucht einen angemeldeten Benutzer. Dafür gibt es zwei Wege.

WordPress bringt seit 5.6 Anwendungspasswörter mit. Sie sind genau dafür gedacht: Ein Skript spricht mit einer Website, ohne das echte Passwort des Kontos zu kennen.

Passwort anlegen

Geh im Backend auf Benutzer > Profil (oder bearbeite den Benutzer, als der das Skript handeln soll) und scroll zu Anwendungspasswörter. Gib einen Namen ein, etwa "Icon-Deploy", klick auf Neues Anwendungspasswort hinzufügen und kopier das angezeigte Passwort. Es wird nur einmal gezeigt.

Einen Administrator nehmen

Der Benutzer braucht die Berechtigung manage_options (siehe Berechtigungen). Mit dem Anwendungspasswort eines Redakteurs bekommst du auf jeder Route eine 403.

Als Basic Auth senden

Gib Benutzername und Passwort samt Leerzeichen mit -u an curl. Lass die Anführungszeichen stehen, wegen der Leerzeichen.

curl https://example.com/wp-json/easy-svg/v1/settings \
	-u admin:'abcd efgh ijkl mnop qrst uvwx'

Anwendungspasswörter funktionieren nur über HTTPS, außer der Umgebungstyp der Website ist local. Über reines HTTP bietet WordPress sie gar nicht erst an.

So sieht eine gescheiterte Anmeldung aus:

SituationStatusCode
Keine Zugangsdaten, oder Cookie ohne Nonce401rest_forbidden
Angemeldet, aber ohne manage_options403rest_forbidden
Cookie mit falscher oder abgelaufener Nonce403rest_cookie_invalid_nonce
Falsches Anwendungspasswort401ein Anmeldefehler aus dem WordPress-Core

Berechtigungen

Jede Route, ob lesend oder schreibend, nutzt denselben Permission-Callback, easy_svg_panel_rest_permission(). Er ist eine Zeile lang:

function easy_svg_panel_rest_permission(): bool {
	return current_user_can( 'manage_options' );
}

Daraus folgen drei Dinge:

  • Es ist manage_options, nicht edit_theme_options. Der Icon-Beitragstyp selbst verlangt EASY_SVG_ICON_CAP (edit_theme_options), die REST-Routen verlangen mehr. Wer Theme-Optionen bearbeiten, aber keine Optionen verwalten darf, kommt nicht an sie heran.
  • Die Berechtigungen der Panel-Tabs zählen hier nicht. Ein Add-on kann einem Tab eine eigene Berechtigung geben (siehe easy_svg_panel_tab_capabilities()). Das entscheidet nur, welche Tabs und Menüeinträge jemand sieht. Die REST-Routen prüfen trotzdem manage_options.
  • Auch die lesenden Routen sind nur für Admins. GET /settings und GET /library sind nicht öffentlich, weil die Bibliotheksantwort das Markup jedes Icons enthält.

In einem Multisite-Netzwerk wird manage_options auf der Website geprüft, an die die Anfrage geht. Ein Website-Administrator kann die Routen also auf seiner eigenen Website nutzen.

Wie eine Anfrage verarbeitet wird

Die Reihenfolge zu kennen hilft, denn welcher Fehler zurückkommt, hängt davon ab, welcher Schritt abgelehnt hat.

WordPress prüft die Argumente, bevor es die Berechtigung prüft. Eine Anfrage, der ein Pflichtfeld fehlt, antwortet mit 400, auch wenn niemand angemeldet ist. Lies eine 400 also nicht als "meine Zugangsdaten stimmen".

Jeder POST-Handler liest den JSON-Body und sonst nichts. Jeder beginnt mit $request->get_json_params(). WordPress füllt das nur, wenn die Anfrage Content-Type: application/json mitschickt. Das hat eine fiese Folge: Die Schemaprüfung in Schritt C schaut an jeder Stelle, an der ein Parameter stehen kann (JSON-Body, Formular-Body, Query-String), der Handler aber nur in den JSON-Body. Eine Anfrage kann die Prüfung also bestehen und trotzdem leer beim Handler ankommen:

# Besteht das Schema (id=42 steht im Query-String),
# aber der Handler sieht keinen JSON-Body, liest id als 0 und antwortet 404.
curl -X POST 'https://example.com/wp-json/easy-svg/v1/library/delete?id=42' \
	-u admin:'abcd efgh ijkl mnop qrst uvwx'

Die Lösung ist immer dieselbe: Schick die Felder als JSON, mit dem Header.

curl -X POST https://example.com/wp-json/easy-svg/v1/library/delete \
	-u admin:'abcd efgh ijkl mnop qrst uvwx' \
	-H 'Content-Type: application/json' \
	-d '{"id":42}'

Die einzige Ausnahme ist GET /library, das search wie jede GET-Route aus dem Query-String liest.

WordPress wandelt die Typen um, bevor der Handler läuft. Weil die Routen ihre Argumente deklarieren, bereinigt WordPress die JSON-Werte auf den deklarierten Typ. Aus "id":"42" wird die Zahl 42, aus "icons":"false" das Boolean false. Ein Wert, der sich nicht umwandeln lässt ("id":"abc", "icons":"vielleicht", "max_mb":2.5), wird mit 400 rest_invalid_param abgelehnt.

Fehlerantworten

Jeder Fehler, ob von WordPress oder von Easy SVG, hat die übliche WordPress-Form:

{
	"code": "easy_svg_add_failed",
	"message": "That name cannot be turned into an icon name. Use letters and numbers.",
	"data": {
		"status": 422
	}
}

Schemafehler von WordPress bringen zusätzlich ein Objekt params mit, das das Feld nennt:

{
	"code": "rest_invalid_param",
	"message": "Invalid parameter(s): id",
	"data": {
		"status": 400,
		"params": {
			"id": "id must be greater than or equal to 1"
		}
	}
}

Entscheide anhand von code und data.status. Zeig message den Leuten, aber werte den Text nie aus: Er ist übersetzt.

Meldungen kommen in der Sprache der Website zurück. Willst du sie in der Sprache des Benutzerprofils, häng _locale=user an den Query-String, etwa /wp-json/easy-svg/v1/library/add?_locale=user. Das Icons-Panel macht das bei jedem Aufruf.

Die Bibliotheksantwort

Sechs der Routen antworten mit demselben Objekt: der aktuellen Icon-Liste. Sie wird von easy_svg_panel_library_payload() gebaut und immer direkt aus der Datenbank gelesen, nie aus dem Icon-Cache. Sie zeigt also schon den Schreibvorgang, den du gerade gemacht hast.

itemsarray

Die Icons, älteste zuerst (sortiert nach Beitrags-ID), höchstens EASY_SVG_PANEL_LIBRARY_MAX (500). Jeder Eintrag hat id (Zahl, die ID des esw_icon-Beitrags), slug (Text, der Name, den Icon-Block und easy_svg_icon() verwenden), label (Text, der sichtbare Name) und content (Text, das gespeicherte Markup, schon bereinigt und gehärtet). Immer eine Liste, nie ein Objekt.

totalinteger

Ohne Suche: wie viele veröffentlichte Icons die Website hat, das können mehr sein, als in items stehen. Mit Suche: die Zahl der zurückgegebenen Treffer, also nie mehr als 500.

truncatedboolean

Ob die Liste bei 500 abgeschnitten wurde. Ohne Suche ist es true, wenn total größer ist als die Zahl der Einträge. Mit Suche ist es true, sobald die Suche alle 500 Plätze gefüllt hat, auch eine Suche mit genau 500 Treffern meldet also true.

Blättern gibt es nicht. Icons nach dem 500. erreichst du über diese Routen nicht, nur eine engere Suche (search) zeigt sie.

Einstellungen: GET und POST /settings

Liest oder speichert die drei Werte auf dem Tab Einstellungen des Panels. Vollständige Referenz: rest-settings.

GET nimmt keine Argumente und gibt easy_svg_settings() zurück. POST führt den JSON-Body mit dem Gespeicherten zusammen, schickt das Ergebnis durch easy_svg_sanitize_settings(), speichert es und gibt die Einstellungen so zurück, wie sie jetzt sind. Ein Schlüssel, den du weglässt, behält seinen gespeicherten Wert, ein ausdrückliches false schaltet eine Funktion ab.

body
svg_uploadboolean

Ob SVG-Dateien in die Mediathek hochgeladen werden dürfen. Nimmt true, false und die Formen, die WordPress umwandelt (1, 0, "true", "false").

body
iconsboolean

Ob die Icon-Bibliothek eingeschaltet ist: der Beitragstyp esw_icon, die Easy-SVG-Sammlung für den Icon-Block und der Shortcode [easy_svg_icon].

body
max_mbinteger

Das größte SVG, das der Sanitizer verarbeitet, in Megabyte. Das Schema lehnt alles unter 1 ab (400 rest_invalid_param) und alles, was keine ganze Zahl ist. Eine Obergrenze im Schema gibt es absichtlich nicht: Ein Wert über der Obergrenze aus easy_svg_max_mb_ceiling() (20, außer der Filter easy_svg_max_mb_ceiling hebt sie an) wird auf diese Grenze gesetzt und gespeichert, nicht abgelehnt.

# Lesen
curl https://example.com/wp-json/easy-svg/v1/settings \
	-u admin:'abcd efgh ijkl mnop qrst uvwx'

# Icon-Bibliothek einschalten, den Rest in Ruhe lassen
curl -X POST https://example.com/wp-json/easy-svg/v1/settings \
	-u admin:'abcd efgh ijkl mnop qrst uvwx' \
	-H 'Content-Type: application/json' \
	-d '{"icons":true}'
StatusCodeWann
400rest_invalid_parammax_mb unter 1 oder keine ganze Zahl, ein Schalter, der kein Boolean ist

Gut zu wissen:

  • Änderungen wirken ab der nächsten Anfrage. Upload- und Icon-Funktion werden eingehängt, wenn easy-svg.php lädt. Die Anfrage, die icons: true speichert, läuft also noch ohne Icon-Bibliothek. Die Antwort zeigt den neuen Wert trotzdem schon.
  • Unbekannte Schlüssel fallen weg. Der Sanitizer gibt nur svg_upload, icons und max_mb zurück.
  • Ein POST als Formular tut stillschweigend nichts. Der Handler sieht einen leeren JSON-Body, führt nichts zusammen und antwortet 200 mit den unveränderten Einstellungen.

Icons auflisten: GET /library

Vollständige Referenz: rest-library.

curl 'https://example.com/wp-json/easy-svg/v1/library?search=pfeil' \
	-u admin:'abcd efgh ijkl mnop qrst uvwx'

Außer der Anmeldung hat diese Route keinen eigenen Fehler. Für den Titel nutzt die Suche die normale Beitragssuche von WordPress, für den Slug eine eigene LIKE-Abfrage (easy_svg_icon_ids_by_slug_like()). Beide Treffermengen werden zusammengeführt, bevor die Grenze von 500 greift.

Icon hinzufügen: POST /library/add

Speichert ein Icon aus SVG-Markup. Vollständige Referenz: rest-library-add.

body
markupstring
Required

Das SVG-Markup als Text. Es läuft durch den Sanitizer der Website, durch dieselben Größen- und Komplexitätsgrenzen wie ein Upload und danach durch eine Härtung, die alles Aktive entfernt, weil der Icon-Block das Ergebnis direkt ins HTML schreibt. Fehlt es ganz: 400 rest_missing_callback_param. Ist es da, aber leer oder nur Leerraum: 422 mit der Meldung für "empty".

body
labelstring

Der sichtbare Name. Im Schema optional, in der Praxis Pflicht: Ohne Label oder mit einem, aus dem sich kein Slug machen lässt, scheitert das Hinzufügen mit 422 und der Meldung für "bad_name". Das Label wird mit sanitize_text_field() bereinigt, Tags fallen also weg. Der Slug entsteht daraus mit sanitize_title() und muss mit ^[a-z0-9] beginnen, danach Buchstaben, Ziffern, _ oder - enthalten und mit einem Buchstaben oder einer Ziffer enden. Ein Label nur in einer Schrift, die WordPress nicht in ASCII umwandeln kann (Kyrillisch, Japanisch und so weiter), ergibt keinen gültigen Slug und wird abgelehnt. Umlaute sind kein Problem, sie werden umgeschrieben.

Ist der Slug schon vergeben, macht WordPress ihn eindeutig (aus herz wird herz-2). Die Antwort sagt es dir: added.slug ist der Slug, den das Icon bekommen hat, added.wanted der, den das Label wollte.

curl -X POST https://example.com/wp-json/easy-svg/v1/library/add \
	-u admin:'abcd efgh ijkl mnop qrst uvwx' \
	-H 'Content-Type: application/json' \
	-d '{"label":"Herz","markup":"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 21l-8-8a5 5 0 0 1 8-6 5 5 0 0 1 8 6z"/></svg>"}'

Um eine Datei von der Platte zu schicken, lass jq das JSON bauen, dann sind die Anführungszeichen richtig maskiert:

jq -n --arg label 'Herz' --rawfile markup herz.svg \
	'{label: $label, markup: $markup}' |
curl -X POST https://example.com/wp-json/easy-svg/v1/library/add \
	-u admin:'abcd efgh ijkl mnop qrst uvwx' \
	-H 'Content-Type: application/json' \
	--data-binary @-

Jede Ablehnung durch den Speicher antwortet mit 422 easy_svg_add_failed. Nur die Meldung unterscheidet die Gründe, ein maschinenlesbares Feld für den Grund gibt es nicht. Die Prüfungen laufen in dieser Reihenfolge, und die erste, die scheitert, bestimmt die Meldung (aus easy_svg_panel_add_message(), hier im englischen Original):

GrundMeldung
Die Sanitizer-Bibliothek ist nicht geladenThe sanitizer is unavailable, so nothing was stored. Reinstall the plugin to restore it.
Kein Label, oder eines ohne gültigen SlugThat name cannot be turned into an icon name. Use letters and numbers.
Markup leer oder nur LeerraumThat SVG is empty, so there was nothing to store.
Markup länger als easy_svg_max_bytes()That SVG is larger than the size allowed in Settings.
Zu viele Processing Instructions oder use-Elemente (easy_svg_svg_too_complex())That SVG has too many parts to be read safely.
Der Sanitizer hat abgelehnt, oder es blieb nichts Zeichenbares übrigThat is not an SVG the sanitizer accepts.
Der Datenbank-Schreibvorgang scheiterte, oder im gespeicherten Beitrag steht kein svgThat SVG could not be stored: it arrived without a drawing, or the write was refused.

Der Handler hat außerdem einen Zweig 409 easy_svg_no_store für den Fall, dass der Icon-Speicher fehlt. Er kann nicht auslösen: Er prüft function_exists( 'easy_svg_add_icon' ), und includes/icon-manager.php, wo diese Funktion steht, wird bei jeder Anfrage geladen. Bau keine Logik darauf auf.

Aus der Mediathek hinzufügen: POST /library/media

Macht aus SVG-Dateien, die schon Anhänge sind, Icons. Du schickst Anhang-IDs, nie Dateiinhalte: Der Server liest jede Datei selbst von der Platte. Vollständige Referenz: rest-library-media.

body
idsinteger[]
Required

Anhang-IDs, mindestens 1 und höchstens EASY_SVG_MEDIA_MAX_IDS (25). Die Grenze steht im Schema der Route, ein Client kann sie also mit einer OPTIONS-Anfrage auslesen. Jeder Eintrag muss eine ganze Zahl sein (oder ein Zahlen-String, den WordPress umwandelt). Die IDs werden in der gesendeten Reihenfolge verarbeitet, Doppelte werden nicht entfernt: Dieselbe ID zweimal ergibt zwei Icons (stern und stern-2).

Der Titel des Anhangs wird zum Label des Icons. Jede Datei läuft durch denselben Sanitizer, dieselben Grenzen und dieselbe Härtung wie bei /library/add, denn ein SVG, das hochgeladen wurde, bevor Easy SVG aktiv war, wurde vielleicht nie bereinigt.

curl -X POST https://example.com/wp-json/easy-svg/v1/library/media \
	-u admin:'abcd efgh ijkl mnop qrst uvwx' \
	-H 'Content-Type: application/json' \
	-d '{"ids":[101,102,103]}'

Eine Anfrage wird entweder als Ganzes abgelehnt oder antwortet 200 mit einer report-Zeile pro ID. Eine schlechte Datei hält die anderen nie auf.

StatusCodeWann
400rest_missing_callback_paramNirgends in der Anfrage ein ids
400rest_invalid_paramids leer, mehr als 25, oder ein Eintrag, der keine ganze Zahl ist
400easy_svg_no_idsids hat das Schema bestanden, steht aber nicht im JSON-Body (als Query-String oder Formularfeld gesendet)

Das eigene 400 easy_svg_too_many des Handlers ("Choose at most 25 files at a time.") ist über REST nicht erreichbar: maxItems im Schema lehnt eine längere Liste vorher ab. Der Zweig 409 easy_svg_no_store ist aus demselben Grund wie bei /library/add unerreichbar.

Pro Zeile ist state einer dieser Werte:

StateBedeutung
addedGespeichert. Die Zeile hat zusätzlich slug und wanted, und ihr id ist jetzt die ID des neuen Icons.
not_foundKein Beitrag mit dieser ID (oder eine ID von 0 oder kleiner). label ist dann leer.
not_svgDer MIME-Typ des Anhangs ist nicht image/svg+xml, oder der Sanitizer hat die Datei abgelehnt.
no_fileDie Datei ist auf diesem Server nicht lesbar, meist weil die Mediathek in einen Cloud-Speicher ausgelagert ist.
bad_name, empty, too_large, too_complex, not_saved, no_sanitizerDieselben Ablehnungen wie bei /library/add, mit denselben Meldungen. Ein Titel, aus dem kein Slug wird, ergibt bad_name.

Icon umbenennen: POST /library/rename

Ändert den sichtbaren Namen und sonst nichts. Der Slug bleibt, weil Themes, Shortcodes und gespeicherte Icon-Blöcke darauf verweisen. Vollständige Referenz: rest-library-rename.

body
idinteger
Required

Die Beitrags-ID des Icons, wie items[].id sie meldet. Mindestens 1.

body
labelstring
Required

Der neue Name. Wird mit sanitize_text_field() bereinigt, bleibt nichts übrig (nur Leerzeichen oder nur Tags wie <br>), wird die Umbenennung abgelehnt. Anders als bei /library/add muss der neue Name nicht als Slug taugen.

curl -X POST https://example.com/wp-json/easy-svg/v1/library/rename \
	-u admin:'abcd efgh ijkl mnop qrst uvwx' \
	-H 'Content-Type: application/json' \
	-d '{"id":42,"label":"Herz (gefüllt)"}'
StatusCodeMeldung
400rest_missing_callback_param / rest_invalid_paramid oder label fehlt, oder id unter 1
404easy_svg_no_iconIcon not found. (kein Beitrag, oder einer, der kein esw_icon ist)
422easy_svg_bad_labelAn icon needs a name.
500easy_svg_rename_failedThe icon could not be renamed.

Geschrieben wird über die öffentliche Funktion easy_svg_rename_icon(). Sie schaltet kses für dieses eine Update ab (sonst würde der SVG-Inhalt für einen Administrator ohne unfiltered_html entfernt) und leert die zwischengespeicherte Icon-Liste, damit der Editor den neuen Namen sofort zeigt.

Zeichnung eines Icons ersetzen: POST /library/replace

Gibt einem vorhandenen Icon neues Markup und behält Name und Slug, damit jede Seite, die es nutzt, die neue Zeichnung zeigt. Vollständige Referenz: rest-library-replace.

body
idinteger
Required

Die Beitrags-ID des Icons. Mindestens 1.

body
markupstring
Required

Das neue SVG-Markup. Wird genau wie bei /library/add geprüft: Sanitizer, Größengrenze, Komplexitätsgrenze, Härtung.

jq -n --argjson id 42 --rawfile markup herz-v2.svg \
	'{id: $id, markup: $markup}' |
curl -X POST https://example.com/wp-json/easy-svg/v1/library/replace \
	-u admin:'abcd efgh ijkl mnop qrst uvwx' \
	-H 'Content-Type: application/json' \
	--data-binary @-
StatusCodeMeldung
400rest_missing_callback_param / rest_invalid_paramid oder markup fehlt, oder id unter 1
404easy_svg_no_iconIcon not found.
422easy_svg_replace_refusedThat file is not an SVG this library can use.

Die 422 deckt jedes andere Ergebnis von easy_svg_update_icon_markup() ab: leeres Markup, eine Ablehnung durch Sanitizer oder Grenzen, einen fehlenden Sanitizer und einen gescheiterten Datenbank-Schreibvorgang. Die Meldung spricht in all diesen Fällen von der Datei, auch wenn die Datei in Ordnung war und nur das Schreiben scheiterte.

Die Prüfung läuft gegen den aktuellen Titel des Icons, weil die gemeinsame Prüffunktion daraus einen Slug ableitet. Wurde ein Icon in etwas umbenannt, aus dem kein Slug wird (nur Satzzeichen oder eine nicht lateinische Schrift), wird jedes Ersetzen mit 422 abgelehnt, egal welches Markup du schickst. Benenn es zuerst lateinisch um und ersetz dann.

Icon löschen: POST /library/delete

Löscht ein Icon endgültig. Vollständige Referenz: rest-library-delete.

body
idinteger
Required

Die Beitrags-ID des Icons. Mindestens 1. Löschen lässt sich nur ein Beitrag vom Typ esw_icon, jede andere ID, etwa eine Seite oder ein Anhang, antwortet mit 404, und nichts wird angefasst.

curl -X POST https://example.com/wp-json/easy-svg/v1/library/delete \
	-u admin:'abcd efgh ijkl mnop qrst uvwx' \
	-H 'Content-Type: application/json' \
	-d '{"id":42}'
StatusCodeMeldung
400rest_missing_callback_param / rest_invalid_paramid fehlt oder liegt unter 1
404easy_svg_no_iconIcon not found.
Es gibt kein Rückgängig. Der Beitrag wird mit wp_delete_post( $id, true ) gelöscht und landet nicht im Papierkorb. Seiten, Templates und Icon-Blöcke, die den Slug nutzen, zeigen danach nichts mehr an, ohne Fehlermeldung. Der Handler prüft auch nicht, was wp_delete_post() zurückgegeben hat: Eine 200 heißt also "das war ein Icon, und das Löschen wurde versucht". Brauchst du Gewissheit, schau in items der Antwort.

Rezept: ersetzen statt einen "-2"-Zwilling anlegen

Fügst du ein Icon hinzu, dessen Name vergeben ist, bekommst du herz-2 neben herz. Wolltest du eigentlich eine neue Zeichnung für herz, bietet das Icons-Panel den Tausch an, und du kannst dasselbe mit drei Aufrufen: hinzufügen, den abweichenden Slug bemerken, das Original ersetzen und die Kopie löschen.

async function myaddonUpsertIcon( label, markup ) {
	const result = await wp.apiFetch( {
		path: '/easy-svg/v1/library/add',
		method: 'POST',
		data: { label, markup },
	} );

	const { id: newId, slug, wanted } = result.added;
	if ( slug === wanted ) {
		return result; // Der Name war frei, sonst ist nichts zu tun.
	}

	const original = result.items.find( ( icon ) => icon.slug === wanted );
	if ( ! original ) {
		return result; // Das Original liegt jenseits der ersten 500 Icons.
	}

	await wp.apiFetch( {
		path: '/easy-svg/v1/library/replace',
		method: 'POST',
		data: { id: original.id, markup },
	} );

	return wp.apiFetch( {
		path: '/easy-svg/v1/library/delete',
		method: 'POST',
		data: { id: newId },
	} );
}

Das Markup wird zweimal geprüft (beim Hinzufügen und beim Ersetzen). Das ist in Ordnung: Was beim ersten Mal durchkam, kommt auch beim zweiten Mal durch, außer der Titel des Original-Icons ergibt keinen Slug (siehe den Hinweis beim Ersetzen).

Stolperfallen

  • JSON oder gar nichts. Jeder POST-Handler liest nur get_json_params(). Ohne Content-Type: application/json sind die Felder für den Handler unsichtbar, obwohl sie die Prüfung bestanden haben: /settings antwortet 200 und ändert nichts, /library/add lehnt mit "bad_name" ab, /library/rename, /library/replace und /library/delete antworten 404.
  • 400 vor 401. WordPress prüft die Argumente vor der Berechtigung. Eine fehlerhafte Anfrage ohne Zugangsdaten bekommt eine 400, keine 401.
  • Der Icon-Schalter sperrt die Routen nicht. Alle sieben Routen funktionieren auch bei ausgeschalteter Icon-Bibliothek. Icons, die du dann hinzufügst, sind echte esw_icon-Beiträge und tauchen auf, sobald der Schalter an ist. Die Antwort 409 easy_svg_no_store in den Handlern für add und media ist unerreichbar.
  • Die zwischengespeicherte Icon-Liste kann Schreibvorgängen bei ausgeschaltetem Schalter hinterherhinken. Die Hooks, die den Cache beim Speichern und Löschen leeren (save_post_esw_icon, deleted_post), werden nur bei eingeschalteter Icon-Bibliothek registriert. /library/rename und /library/replace leeren den Cache selbst, /library/add und /library/delete nicht. Die REST-Liste betrifft das nicht (sie liest die Datenbank), aber easy_svg_icon() und der Icon-Block lesen den Cache, und der lebt bis zu einem Tag.
  • Einstellungen wirken ab der nächsten Anfrage, nicht in der, die sie gespeichert hat.
  • 500 Icons sind die Decke jeder Antwort. Kein Blättern. Achte auf truncated.
  • Ein Fehlercode, viele Gründe. easy_svg_add_failed und easy_svg_replace_refused tragen den Grund nur in der übersetzten message. Werte sie nicht aus. Brauchst du den Grund, prüf vorher selbst oder ruf die PHP-Funktionen auf, die mit einem Zustandswort antworten.
  • Labels können HTML-Entities enthalten. Bei /library/media ist das Label der Titel des Anhangs, so wie get_the_title() ihn nach den the_title-Filtern liefert (typografische Anführungszeichen werden zu &#8217; und Ähnlichem). Escape Labels bei der Ausgabe und vergleich sie nicht Byte für Byte mit dem, was du in der Mediathek getippt hast.
  • Löschen ist endgültig. Kein Papierkorb, keine Revision, keine Warnung vor Seiten, die den Slug noch nutzen.
  • Intern heißt intern. Routennamen, Felder und Codes können sich mit jedem Release ändern. Pack deine Aufrufe in eine kleine eigene Client-Funktion, dann ist eine Änderung eine einzige Korrektur.

Siehe auch