In diesem Artikel befassen wir uns mit einer wichtigen Art von Caching, die Ihnen in WordPress zur Verfügung steht: Transients. Wie jeder Cache verwenden Sie Transients, um Daten zu speichern, deren Abruf lange dauert, sodass sie beim nächsten Mal, wenn Sie sie benötigen, super schnell zurückgegeben werden. Das Schöne an Transients ist, dass sie sich selbst aufräumen, solange Sie die hier beschriebenen Fallstricke beachten!
Das Web ist wirklich „API-lastig“ geworden. Damit meine ich, dass fast jede große Website Inhalte von anderen Websites abruft und dorthin sendet. Denken Sie an
- Nahezu die Hälfte von ESPN.com scheint tatsächlich Twitter zu sein.
- Programmable Web verfolgt inzwischen über 13.000 APIs.
- Eine der größten Initiativen rund um WordPress seit vielen Monaten ist die WP-API.
In meiner eigenen Arbeit habe ich festgestellt, dass die Erwartungen von Kunden und Arbeitgebern gestiegen sind und die Hoffnung – nein, die *Annahme* – beinhalten, dass meine Fähigkeiten die API-Integration umfassen. Es reicht nicht aus, ein E-Mail-Anmeldeformular als <iframe> einzufügen. Vielmehr benötigt meine Agentur diese in einem [Shortcode] abstrahiert, um die Wartung zu erleichtern. Es reicht nicht aus, einen Produkt-Slider über JavaScript von Drittanbietern einzufügen, sondern der Designer erwartet präzise Kontrolle über die Animationen. Das Einloggen eines Entwicklers in ein CDN, um zu sehen, ob eine Domain im Entwicklungsmodus ist, ist zu zeitaufwendig, daher rufen wir das CDN an und zeigen den Status im Dashboard an.
WordPress bietet uns einige phänomenale Werkzeuge für API-Integrationen. Eines davon ist die Transients API. Es ist eines meiner Lieblingsteile, die mit WordPress geliefert werden, und ich möchte ein paar Tricks mit Ihnen teilen. Wenn Sie neu in Transients im Allgemeinen sind, lesen Sie weiter. Wenn Sie das Konzept bereits verstanden haben und zu den Details springen möchten, können Sie dies gerne tun.
Noch eine Sache: Ich gehe davon aus, dass Sie mit HTTP-Anfragen von einem WordPress-Plugin vertraut sind, da es den Rahmen dieses Artikels sprengen würde, dies im Detail darzulegen. Meine Beispiele verwenden alle die WordPress HTTP API für Anfragen.
Was haben Transients mit API-Integrationen zu tun?
Jedes Mal, wenn Sie einen Remote-Server aufrufen, entstehen zusätzliche Latenzzeiten, manchmal sogar erheblich. Transients ermöglichen es Ihnen, die Antwort von der Remote-API zu cachen und sie in Ihrer WordPress-Datenbank zu speichern (nun ja, *normalerweise* in der Datenbank; dazu später mehr). Außerdem haben viele APIs eine Ratenbegrenzung, was bedeutet, dass Sie nur *x* Anfragen innerhalb eines bestimmten Zeitraums stellen dürfen. Transients ermöglichen es Ihnen, diese API-Antwort von *sich selbst* abzurufen und sparen Ihnen so viele, viele Remote-Aufrufe.
Was genau sind Transients?
Sie sind eine Möglichkeit, Informationen zu cachen. Transients sind eine Form des Cachings, die auf dem Server stattfindet, im Gegensatz zum Browser-Caching. Stellen Sie sich einen Transient als einen Organismus vor, der aus drei Komponenten besteht
- Ein Schlüssel. Eine kurze Zeichenkette. Der Name des Organismus.
- Ein Wert. Jede PHP-Variable. Der Körper – das Innere, wenn Sie so wollen – des Organismus.
- Eine Lebensdauer. Oft ausgedrückt als Zeitkonstante wie
DAY_IN_SECONDS. Die Zeitspanne, für die wir möchten, dass dieser Organismus lebt.
Transients sind sehr ähnlich zu WordPress-Optionen, nur dass Transients eine festgelegte Lebensdauer haben. Aus diesem Grund sind sie eine ausgezeichnete Wahl für die Speicherung von Ergebnissen von Remote-Aufrufen.
Huh… Was passiert, wenn die Remote-API ihre Antwort ändert? Und werden all diese Transients meine Datenbank nicht verstopfen?
Das ist das Coole an Transients: Sie laufen automatisch ab. Wenn Sie versuchen, einen Transient nach seinem Ablauf aus Ihrer Datenbank abzurufen, löscht WordPress ihn automatisch und verhindert so jegliche Überfüllung. Gleichzeitig wird er neu erstellt und stellt sicher, dass Sie (relativ) aktuelle Inhalte von der Remote-API haben.
Whoa, warte, WordPress wird meine wertvollen Informationen löschen?
Ja, das wird es. Transients sind absolut *nicht* zum Speichern von Daten gedacht, die nicht automatisch neu erstellt werden können. Daher würden Sie einen Transient nicht verwenden, um beispielsweise Daten zu speichern, die ein Benutzer in einem Formular auf Ihrer Website eingibt.
Sind Transients nur für Remote-Aufrufe?
Transients sind für jeden Informationsbrocken, dessen Generierung lange dauert. Sie verbessern die Serverlatenz für jede Routine, die komplexer ist als der Abruf einer einzelnen Datenbankzelle. Dennoch sind sie *mehr* Code, und mehr Code bedeutet mehr Fehler. Daher reserveiere ich sie tendenziell entweder für Remote-Aufrufe oder für wirklich große Abfragen.
Wie funktioniert das genau?
Nehmen wir an, Sie möchten eine Liste Ihrer aktuellen Abonnenten für Ihren E-Mail-Newsletter erhalten. Sie verwenden einen Drittanbieter-Dienst für E-Mail-Updates, und dieser stellt Ihre Abonnentenliste über eine API zur Verfügung. Hier ist die Sequenz
- Im Moment müssten Sie die API aufrufen, um die Abonnentenliste anzufordern, da Sie diese Informationen nicht zur Hand haben.
- Die API antwortet auf Ihre Anfrage mit der Abonnentenliste, und obwohl es ein paar hundert Millisekunden dauert, erhalten Sie die benötigte API-Antwort.
- Sie speichern diese Daten auf *Ihrem* Server in einem Transient und geben ihm eine Lebensdauer von
HOUR_IN_SECONDS, d. h. eine Stunde. - Für die nächste Stunde wird jedes Mal, wenn ein Benutzer Ihre Liste der aktuellen Abonnenten lädt, dies sehr schnell geschehen, da alles in einem großen Haufen in einer Zelle Ihrer Datenbank gespeichert ist.
- Eine Stunde vergeht und ein Benutzer versucht, Ihre Seite zu laden. WordPress bemerkt, dass die Lebensdauer abgelaufen ist, löscht Ihren lokalen Wert, und Sie sind zurück bei Schritt eins dieses Prozesses.
Ich verstehe es immer noch nicht.
Das WROX-Buch über Plugin-Entwicklung hat ein fantastisches Kapitel über Transients, ebenso wie das Codex.
Okay, ich verstehe es. Geben Sie mir einen Ausschnitt.
Hier sind Transients in ihrer grundlegendsten Form
<?php
/**
* Get a list of email subscribers.
*
* @return object The HTTP response that comes as a result of a wp_remote_get().
*/
function css_t_subscribers() {
// Do we have this information in our transients already?
$transient = get_transient( 'css_t_subscribers' );
// Yep! Just return it and we're done.
if( ! empty( $transient ) ) {
// The function will return here every time after the first time it is run, until the transient expires.
return $transient;
// Nope! We gotta make a call.
} else {
// We got this url from the documentation for the remote API.
$url = 'https://api.example.com/v4/subscribers';
// We are structuring these args based on the API docs as well.
$args = array(
'headers' => array(
'token' => 'example_token'
),
);
// Call the API.
$out = wp_remote_get( $url, $args );
// Save the API response so we don't have to call again until tomorrow.
set_transient( 'css_t_subscribers', $out, DAY_IN_SECONDS );
// Return the list of subscribers. The function will return here the first time it is run, and then once again, each time the transient expires.
return $out;
}
}
?>
Das ist die grundlegende Routine: Prüfen Sie lokal auf den Wert. Wenn Sie ihn haben, großartig. Wenn nicht, holen Sie ihn remote und speichern Sie ihn lokal für das nächste Mal.
Aber es wurden mir Tricks versprochen.
Ja! Ich habe einige Tricks zu teilen, jetzt wo Sie die Grundlagen gesehen haben. Ich werde das nicht in einem abschließenden Beispiel zusammenfassen, da Ihre Behandlung wahrscheinlich auf Ihre Anwendung zugeschnitten werden muss. Dies ist eine Fundgrube, und ich werde sie nach den drei Komponenten eines Transients organisieren, die ich zuvor erklärt habe
- Der Name.
- Der Inhalt.
- Die Lebensdauer.
Faszinierend: Das sind auch die drei Werte, die an set_transient() übergeben werden.
Tricks zur Benennung Ihres Transients
Dies ist bei weitem der tiefste Teil meiner Fundgrube an Tricks, wenn es um Transients geht. Es ist ein wenig kontraintuitiv, aber *die Benennung Ihrer Transients ist das Schwierigste an ihrer Verwendung*. Die Art und Weise, wie Sie Ihre Transients benennen, kann eine Reihe von mächtigen Möglichkeiten eröffnen oder Ihr Plugin komplett zerstören.
Präfixieren Ihrer Transient-Namen
Es ist hilfreich, alle Transients identifizieren zu können, die zu Ihrem Plugin gehören. Der Weg dorthin ist, sie mit Ihrem Plugin-Namespace zu präfixieren. Dies ist auch entscheidend, um Kollisionen mit anderen Transients zu vermeiden. Deshalb sehen Sie mich in den meisten meiner Beispiele `css_t_subscribers` anstelle von nur `subscribers` verwenden, wobei `css_t` mein imaginäres Präfix für css-tricks.com ist.
Ändern des Namens, um den Cache zu brechen
Es gibt zwei schwierige Dinge in der Informatik: Cache-Invalidierung, Benennung von Dingen und Off-by-one-Fehler. — Leon Bambricks, Variation des Phil Karlton-Zitats
Erstaunlich! Von den drei schwierigen Problemen der Informatik betreffen zwei die Benennung Ihres Transients: Benennung von Dingen und Cache-Invalidierung. Die Benennung Ihres Transients hängt mit der Cache-Invalidierung zusammen, denn wenn Sie den *Namen* Ihres Transients *ändern*, kann WordPress ihn nicht mehr finden. Das kann tatsächlich eine *gute* Sache sein, denn es zwingt Ihr Plugin, die Remote-API aufzurufen, um frische Daten zu erhalten.
Ein Anlass dafür könnte die Veröffentlichung einer neuen Version des Plugins sein. Es liegt nahe, dass, wenn sich der Plugin-Code geändert hat, Ihr Code aktualisierte Transients abrufen sollte, anstatt die alten weiter zu verwenden, die den alten Plugin-Code voraussetzen. Eine Möglichkeit, dies zu tun, ist die Einbeziehung der Versionsnummer Ihres Plugins in Ihren Transient-Namen
<?php
// This is the version number for our plugin.
CSS_T_VERSION = '3.1.4';
function css_t_subscribers() {
// Do we have this information in our transients already?
$transient = get_transient( 'css_t_subscribers' . CSS_T_VERSION );
// Do things...
// Save the API response so we don't have to call again until tomorrow.
set_transient( 'css_t_subscribers' . CSS_T_VERSION, $out, DAY_IN_SECONDS );
}
?>
Ich verwende gerne eine Konstante, da Konstanten global sind, so dass ich sie nicht in meine Funktion übergeben muss – sie ist bereits vorhanden. Ich stelle jedoch sicher, dass die Konstante selbst präfixiert ist, um Kollisionen mit anderen Konstanten zu vermeiden.
Aber dann, aus dem Nichts, eine Fallstrick! Da sich Ihr Transient-Name bei jedem Update Ihres Plugins ändert, wird WordPress niemals Gelegenheit haben, Ihre Transients unter ihren alten Namen aufzurufen. Das bedeutet, sie werden nie gelöscht! Ihre Transients bleiben für immer in Ihrer Datenbank und erreichen den gefürchteten „Überfüllungs“-Status, über den sich die Leute manchmal Sorgen machen, wenn es um Transients geht. Das ist ein Grund, warum es wichtig ist, alle Ihre Transients zu präfixieren. Angesichts dieses Präfixes könnten Sie alle Transients, die zu Ihrem Plugin gehören, automatisch löschen und vielleicht sogar einen hilfreichen „Cache leeren“-Button in den Einstellungen Ihres Plugins bereitstellen. Das ist eine etwas heikle Angelegenheit, daher werde ich die Details für später im Artikel aufheben.
Ich gebe es zu: Ich habe nie ein Testszenario eingerichtet, um zu bestätigen, dass Transients irgendwann zu Überfüllungen führen könnten, wie ich es beschrieben habe, aber es scheint in einigen Fällen zu passieren. Darüber hinaus scheint eine Lektüre der Kernfunktion get_transient() diese Hypothese zu unterstützen. WP Engine scheint dem ebenfalls zuzustimmen.
Auch erwähnenswert: Sie *könnten* Ihre Plugin-Version dynamisch aus dem Docblock am Anfang Ihres Plugins über get_plugin_data() abrufen. Dieses Skript lädt jedoch nur in wp-admin. Ich stelle mir vor, dass man es auch im Frontend laden könnte, obwohl ich es noch nicht ausprobiert habe. Ich kann dafür keine Garantie geben.
Verwendung von Magic Constants für die Benennung Ihrer Transients
PHP enthält einige nützliche Variablen, die als Magic Constants bezeichnet werden. Die nützlichsten sind __CLASS__ und __FUNCTION__. Diese Konstanten geben den Namen der aktuellen PHP-Klasse bzw. die aktuelle Funktion als Zeichenkette zurück. Dies kann Ihren Code bei der Benennung vieler Dinge, einschließlich Transients, optimieren.
<?php
class CSS_T {
function subscribers() {
$transient_key = __CLASS__ .'_' . __FUNCTION__;
}
}
?>
Sie könnten diese Technik problemlos mit der oben genannten Versionsnummerntechnik kombinieren.
Einbeziehung Ihres Remote-API-Schlüssels in Ihren Transient-Namen
Die meisten APIs erfordern, dass Sie einen eindeutigen API-Schlüssel erstellen oder eine andere Möglichkeit haben, Ihre Remote-Aufrufe Ihrem Konto zuzuordnen. Wenn Sie feststellen, dass Sie diesen API-Schlüssel ändern müssen, liegt es nahe, dass Ihre Transients auf Remote-Aufrufe mit nur dem neuen Schlüssel verweisen sollen. Aus diesem Grund könnten Sie Ihren API-Schlüssel an Ihren Transient-Namen anhängen
<?php
function css_t_subscribers( $limit = 50 ) {
$api_key = 'W$3Th&j8Ias76gF%^Fukg3%$Dy3ghd!@';
$transient_name = __FUNCTION__ . '_' . $api_key';
}
?>
Sie könnten besorgt sein, Ihren API-Schlüssel im Cyberspace herumfliegen zu sehen, da dies ein Sicherheitsrisiko darstellen könnte. Sie könnten dieses Problem mildern, indem Sie den API-Schlüssel verschlüsseln, ein Ansatz, der zufällig auch andere Vorteile hat, die ich kurz besprechen werde.
Einbeziehung der Remote-URL und der Request-Parameter in Ihren Transient-Namen
Eine Remote-API liefert eine andere Antwort, basierend auf der genauen URL, die Sie abfragen. Einige Beispiele könnten sein
<?php
// Getting all subscribers VS getting just 50 of them.
$subscribers = 'https://api.example.com/subscribers';
$fifty_subscribers = 'https://api.example.com/subscribers?limit=50';
// Getting all campaigns VS getting just the ones that have already sent.
$campaigns = 'https://api.example.com/campaigns';
$sent_campaigns = 'https://api.example.com/campaigns?status=sent';
?>
Es ist sehr wahrscheinlich, dass Ihr Plugin viele Kombinationen dieser Parameter senden möchte, daher würden Sie sie als Funktionsargumente darstellen. Angesichts dessen können Sie diese Werte verwenden, um dynamisch eindeutige Transient-Schlüssel für jede Abfrage zu erstellen.
<?php
function css_t_subscribers( $limit = 50 ) {
// The base url for getting subscribers.
$url = 'https://api.example.com/subscribers';
// Sanitize the limit variable.
$limit = absint( $limit );
// Add the limit variable to the url.
$url = add_query_arg( array( 'limit', $limit ), $url );
// Use the url in the transient name.
$transient_name = __FUNCTION__ . '_' . $url';
}
?>
VORSICHT! Es gibt ein Problem!
Mann, wir hängen hier wie Betrunkene Zeug an unsere Transient-Schlüssel an! Es ist absolut vernünftig, all diese Elemente in Ihrem Transient-Namen zu haben
- Plugin-Namespace.
- PHP-Klassenname.
- PHP-Funktionsname.
- Plugin-Versionsnummer.
- Remote-API-URL.
- Remote-API-Request-Parameter.
- Remote-API-Schlüssel.
Sie könnten mit einem Transient-Namen enden, der weit über 100 Zeichen lang ist, und das funktioniert nicht. Warum nicht? Denn *wenn Sie Ihren Transient-Schlüssel länger als 40 Zeichen machen, speichert WordPress den Transient möglicherweise nicht*. Dies liegt an einer Zeichenbegrenzung in der Options-Tabelle der WordPress-Datenbank. Es kann sehr, sehr einfach sein, diese Grenze zu überschreiten, sobald Sie mit dem Präfixieren beginnen, eine Versionsnummer hinzufügen und einige Argumente hinzufügen. WordPress wird diese Grenze bald auf 255 Zeichen erhöhen, aber bis dahin besteht der Weg, dieses Problem zu umgehen, darin, Ihren Transient-Namen über die PHP-Funktion md5() zu komprimieren.
Leser Jibran B schreibt: „Transient-Namen (option_name) in der wp_options-Tabelle können jetzt 172 Zeichen statt 40 Zeichen lang sein.“
md5() kann praktisch jede Zeichenkette nehmen und auf 32 Zeichen komprimieren – eine neue Zeichenkette, die garantiert eindeutig für die eingegebene Zeichenkette ist. Das Ergebnis ist im Grunde unleserlich (es ist ein Hash), aber es gibt keinen Grund, warum Sie die Namen der Transient-Schlüssel lesen müssten, abgesehen vom Präfix-Teil.
Da wir nur 40 Zeichen zur Verfügung haben und md5() 32 davon verbraucht, bleiben uns nur noch 8 für unser Präfix übrig. Aus Gründen der Lesbarkeit verneige ich mich vor dem dritten schwierigen Problem der Informatik, den Off-by-one-Fehlern (siehe oben) und gebe mir zur Sicherheit nur 7 Zeichen.
<?php
function css_t_subscribers( $limit = '50' ) {
// The namespace for our plugin.
$namespace = css_t_namespace(); // Let's say this gives us the slug name, 'css_tricks';
// Cut it down to a max of 7 chars.
$namespace = substr($namespace, 0, 7 );
// The base url for getting subscribers.
$url = 'https://api.example.com/subscribers';
// Sanitize the limit variable.
$limit = absint( $limit );
// Add the limit variable to the url.
$url = add_query_arg( array( 'limit', $limit ), $url );
// Build a transient name that is guarenteed to carry all the uniqueness we might want, and also be less than 40 chars.
$transient_name = $namespace . md5( $url );
}
Wer hätte gedacht, dass wir uns so lange mit dem Nischenthema der Benennung von Transients beschäftigen könnten. Es ist erstaunlich, wie tief man hier eintauchen kann, und das alles, weil der Name auf interessante Weise geändert werden kann, um den Cache zu brechen. Aber genug von Namen.
Tricks zum Speichern von Daten in einem Transient
Weiter vorne in diesem Artikel habe ich erklärt, dass Transients drei Komponenten haben: einen Namen, Inhalt und eine Lebensdauer. Es ist an der Zeit, den zweiten Teil zu betrachten, nämlich den Inhalt, den Sie im Transient cachen.
Es muss keine Zeichenkette sein
Der WordPress-Kern teilt uns mit, dass wir unseren Transient-Inhalt nicht serialisieren müssen, bevor wir ihn speichern. Mit anderen Worten, wir sind nicht darauf beschränkt, einfache Werte wie Zeichenketten oder Zahlen zu speichern. Vielmehr können wir ganze Arrays oder Objekte speichern, wie z. B. eine HTTP-Antwort, die sich aus wp_remote_request() ergibt.
Das gesagt, nur weil Sie die gesamte Antwort speichern können, heißt das nicht unbedingt, dass Sie es tun sollten. Es könnte Ihrem Plugin helfen, wenn Sie die Antwort etwas parsen und nur den Body oder sogar eine Teilmenge des Bodys speichern. Alternativ haben Sie vielleicht einen guten Grund, die gesamte Antwort zu speichern, vielleicht weil Sie auf den HTTP-Statuscode an anderer Stelle in Ihrem Plugin reagieren möchten. Das bleibt Ihnen überlassen.
Nicht alle Daten sind speicherenswert
Apropos HTTP-Statuscodes, eines der ersten Dinge, die ich bei der API-Integration tue, ist, die Dokumentation zu lesen und eine Liste von HTTP-Statuscodes zu erstellen. Bei vielen APIs bedeutet ein Statuscode im Bereich 40x oder 50x, dass ich einen Fehler in meinem Plugin-Code gemacht habe, der eine Anfrage nicht erfüllen konnte. Wahrscheinlich gibt es keinen Grund, dies in einem Transient zu speichern, daher vergleiche ich den Antwortcode mit meiner Liste, bevor ich speichere.
<?php
// Get a list of subscribers from a remote API.
function css_t_subscribers() {
// Transient stuff...
// Call the remote service.
$response = wp_remote_get( $url );
// Check our response to see if it's worth storing.
if ( ! css_t_check_response( $response ) ) {
return FALSE;
}
}
// Given an HTTP response, check it to see if it is worth storing.
function css_t_check_response( $response ) {
// Is the response an array?
if( ! is_array( $response ) ) { return FALSE; }
// Is the response a wp error?
if( is_wp_error( $response ) ) { return FALSE; }
// Is the response weird?
if( ! isset( $response['response'] ) ) { return FALSE; }
// Is there a status code?
if( ! isset( $response['response']['code'] ) ) { return FALSE; }
// Is the status code bad?
if( in_array( $response['response']['code'], css_t_bad_status_codes() ) ) { return FALSE; }
// We made it! Return the status code, just for posterity's sake.
return $response['response']['code'];
}
// A list of HTTP statuses that suggest that we have data that is not worth storing.
function css_t_bad_status_codes() {
return array( 404, 500 );
}
?>
Nur das Ergebnis von GET-Anfragen speichern
Ich spreche hier von RESTful APIs. In einer RESTful API können Sie eine Anfrage mit verschiedenen Request-Typen stellen. Hier sind einige der gängigsten
- GET – Zum Abrufen von Daten verwendet.
- POST – Zum Hinzufügen einer Datenzeile verwendet.
- PUT – Zum Bearbeiten einer gesamten Datenzeile verwendet.
- PATCH – Zum Bearbeiten eines Teils einer Datenzeile verwendet.
- DELETE – Zum Löschen einer gesamten Datenzeile verwendet.
Ich spreche immer wieder von der Familie der Funktionen wp_remote_request(), und raten Sie mal? Sie ermöglichen es Ihnen, den Typ der Anfrage anzugeben, die Sie stellen. Es gibt nur einen Anfragetyp, dessen Antwort in einem Transient gespeichert werden sollte, und das ist eine GET-Anfrage. Tatsächlich, wenn Sie eine andere Art von Anfrage stellen, dann versuchen Sie wahrscheinlich, Daten auf dem Remote-Server zu *ändern*, und das bedeutet, dass einige Ihrer Transients jetzt veraltet sein könnten. Dies wäre ein Anlass, alle Transients zu löschen, die zu Ihrem Plugin gehören. Ich werde kurz darauf eingehen, wie wir das machen könnten.
Im Beispiel unserer E-Mail-API-Integration sendet mein Plugin jedes Mal, wenn sich jemand für meine E-Mail-Liste anmeldet, eine POST-Anfrage an die Remote-API, um ihn zu meiner Mailingliste hinzuzufügen. Ich habe wahrscheinlich eine Funktion in meinem Plugin, die sich dem Aufruf dieser API widmet. Diese Funktion erkennt, welchen Anfragetyp ich stelle, und wenn es keine GET-Anfrage ist, löscht sie alle meine Plugin-Transients.
Diese Haltung geht davon aus, dass Datenintegrität wichtiger ist als Leistung, und ehrlich gesagt ist das nicht immer der Fall. Vielleicht haben Sie eine Ansicht, die Hunderte von Datenzeilen anbietet und die Daten sich sehr häufig ändern. In einem solchen Fall wäre es nicht performant, Ihre Transients bei jeder POST-Anfrage Ihres Plugins zu löschen.
Tricks bei der Festlegung einer Lebensdauer für Ihren Transient
Wir sind beim dritten und letzten Teil eines Transients angelangt: Der Lebensdauer. Diese kann auf verschiedene Weise ausgedrückt werden
set_transient( $name, $content, 3600 )– Speichern der Daten für 3600 Sekunden, was einer Stunde entspricht.set_transient( $name, $content, 60 * 60 )– Speichern der Daten für 60 Minuten, was einer Stunde entspricht, nur lesbarer.set_transient( $name, $content, HOUR_IN_SECONDS )– Speichern der Daten für eine Stunde, sehr gut lesbar. Diese werden mit WordPress geliefert.
Der „Mayfly“-Transient für das Debugging
Eine Libelle ist ein Insekt mit einer unglaublich kurzen Lebensdauer. Betrachten Sie den folgenden Transient
set_transient( $name, $content, 1 )
Das ist ein Transient, der nur eine Sekunde hält! Dieser Transient wird fast garantiert nie aus der Datenbank aufgerufen. Er müsste generiert und dann in weniger als einer Sekunde erneut angefordert werden. Dies führt jedoch zu einer hilfreichen Möglichkeit, eine Art Debug-Modus in Ihrem Plugin bereitzustellen. Wenn Sie Ihren Code debuggen, ist einer der häufigsten Schritte, Ihre Variablen zu echon, um zu sehen, ob sie das widerspiegeln, was Sie erwarten. Dies kann bei Transients äußerst frustrierend sein. Sie müssten in Ihre API-Aufrufe gehen und die Transient-Logik auskommentieren, um sicherzustellen, dass Sie frische Ergebnisse für das Debugging erhalten, und sich dann daran erinnern, sie wieder einzukommentieren, bevor Sie sie bereitstellen. Stattdessen mache ich das
<?php
// If the user is a super admin and debug mode is on, only store transients for a second.
function css_t_transient_lifespan() {
if( is_super_admin() && WP_DEBUG ) {
return 1;
} else {
return DAY_IN_SECONDS;
}
}
// Get subscribers, using a dynamic value for the transient time.
function css_t_subscribers() {
// ...
$lifespan = css_t_transient_lifespan();
set_transient( $name, $content, $lifespan );
// ...
}
?>
Das gesagt, wenn Sie Transients mit einer relativ langen Lebensdauer haben, wie z. B. DAY_IN_SECONDS, erhalten Sie bis morgen immer noch diese alten Werte. Nicht gut. Dafür brauchen Sie eine Möglichkeit, alle Ihre Plugin-Transients einfach zu leeren.
Der Leerungsvorgang
Wir müssen alle Transients auswählen, die zu unserem Plugin gehören, und dann die Funktion delete_transient() verwenden, um jeden einzelnen zu löschen. Theoretisch könnten wir sie über SQL löschen, aber es ist normalerweise am besten, Dinge auf Anwendungsebene zu erledigen, und diese Regel gilt hier definitiv. Ich werde gleich erklären, warum.
<?php
// Purge all the transients associated with our plugin.
function purge() {
global $wpdb;
$prefix = esc_sql( $this -> get_transient_prefix() );
$options = $wpdb -> options;
$t = esc_sql( "_transient_timeout_$prefix%" );
$sql = $wpdb -> prepare (
"
SELECT option_name
FROM $options
WHERE option_name LIKE '%s'
",
$t
);
$transients = $wpdb -> get_col( $sql );
// For each transient...
foreach( $transients as $transient ) {
// Strip away the WordPress prefix in order to arrive at the transient key.
$key = str_replace( '_transient_timeout_', '', $transient );
// Now that we have the key, use WordPress core to the delete the transient.
delete_transient( $key );
}
// But guess what? Sometimes transients are not in the DB, so we have to do this too:
wp_cache_flush();
}
?>
Sie könnten diese Funktion aufrufen, wenn ein Benutzer auf einen Button auf der Einstellungsseite Ihres Plugins klickt, wenn neue Beiträge veröffentlicht werden oder vielleicht jedes Mal, wenn ein Widget gespeichert wird. Das liegt an Ihnen!
Beachten Sie die letzte Zeile in diesem Snippet, wo ich wp_cache_flush aufrufe. Das liegt daran, dass unsere Transients möglicherweise gar nicht in der DB sind. Sie könnten tatsächlich im Objekt-Cache sein!
Wir müssen über Objekt-Caching sprechen
Haben Sie meinen vorsichtigen Ton an verschiedenen Stellen in diesem Artikel bemerkt, der darauf hindeutet, dass Transienten nicht immer in der Datenbank liegen? Das liegt am Objekt-Caching.
Kürzlich habe ich versucht, eine API-Integration für einen Kunden zu debuggen. Ich habe versucht, phpMyAdmin zu verwenden, um Transientenwerte in der Datenbank zu inspizieren, aber ich konnte keine finden. Das liegt daran, dass der Kunde Objekt-Caching verwendete: Das bedeutet, dass seine Transienten nicht in der Datenbank lebten!
Um Probleme mit dem Objekt-Caching zu vermeiden, müssen Sie Ihre Transienten einfach wie gewohnt per CRUD verwalten, indem Sie set_transient(), get_transient() und delete_transient() verwenden. Wenn Objekt-Caching verfügbar ist, wird es diese auf seine eigene Weise per CRUD verwalten.
Wenn ich „wie gewohnt“ sage, meine ich, im Gegensatz zur Verwendung einer SQL-Abfrage zur Verwaltung von Transienten. In meinem obigen Snippet wähle ich meine Transiente über eine SQL-Abfrage aus, was gegen die Regeln verstößt, daher muss ich eine Strafe zahlen. Ich entscheide mich, eine Strafe in Form von Leistungseinbußen und einer zusätzlichen Codezeile zu zahlen, indem ich wp_cache_flush() aufrufe, was den gesamten Objekt-Cache leert. Umfassend, einfach, aber brachial. Es gibt ein paar andere Möglichkeiten, wie ich diese Strafe stattdessen zahlen könnte.
Zum einen wäre es wahrscheinlich klüger, nur den Teil des Caches zu leeren, der mit meinem Plugin verbunden ist. Die Objekt-Cache-Klasse hat Methoden dafür. Dies ist jedoch ein Artikel über Transienten, daher werde ich nicht tief in das Objekt-Caching eintauchen.
Ein anderer Ansatz wäre, jeden meiner Transienten-Schlüssel in einem Array zu registrieren und dieses Array in der Datenbank zu speichern. Auf diese Weise könnte ich dieses Array durchlaufen und delete_transient() für jeden Wert aufrufen.
<?php
// Pass the transient key to this function whenever we save a transient.
function css_t_update_transient_keys( $new_transient_key ) {
// Get the current list of transients.
$transient_keys = get_option( 'css_t_transient_keys' );
// Append our new one.
$transient_keys[]= $new_transient_key;
// Save it to the DB.
update_option( 'css_t_transient_keys', $transient_keys );
}
// Call this function to dump our plugin transients.
function css_t_purge() {
// Get our list of transient keys from the DB.
$transient_keys = get_option( 'css_t_transient_keys' );
// For each key, delete that transient.
foreach( $transient_keys as $t ) {
delete_transient( $t );
}
// Reset our DB value.
update_option( 'css_t_transient_keys', array() );
}
?>
Es kommt mir etwas seltsam vor, beim Speichern einer Transiente einen zusätzlichen Datenbankaufruf zu tätigen, um die Option zu aktualisieren – das ist wie zwei Fliegen mit einer Klappe. Aber es ist nicht viel Code, erfordert kein SQL und funktioniert gut mit Objekt-Caching.
Wenn Sie mehr über Objekt-Caching erfahren möchten, empfehle ich Ihnen, sich mit dem WordPress-Core zu beschäftigen. Schauen Sie sich zum Beispiel den Quellcode für delete_transient() an. Sie können sehen, wie dort vor dem Rückgriff auf die normale WP Options API auf Objekt-Caching geprüft wird.
Nächste Schritte
Ich wollte diese Diskussion auf die Transients API konzentrieren, aber die Realität ist, dass sie am besten in Verbindung mit der HTTP API von WordPress verwendet wird, mit einem Hauch von Objekt-Caching-Bewusstsein. Wenn Sie ein Plugin erstellen, das Remote-Aufrufe tätigt, sollten Sie die WordPress HTTP API verwenden. Kapseln Sie all diese Remote-Aufrufe in einer PHP-Klasse, und diese Klasse kann problemlos die WordPress Transients API vor und nach dem Aufruf des Remote-Dienstes verwenden. Indem Sie die Verwendung von Transienten für Ihre Remote-Aufrufe beherrschen, bringen Sie das gesamte Netz von APIs in Ihren Griff, mit minimalen Performance-Bedenken.
Ich habe viele Artikel über Transienten gelesen und sogar einige eigene geschrieben. Dies ist mit Abstand der prägnanteste Artikel, den ich je gelesen habe! Vielen Dank, dass Sie so tiefgehend waren und alle üblichen Fallstricke in einem schönen Artikel mit großartigen Beispielcode-Snippets aufgenommen haben. Ich werde diesen mit meinem Team teilen!