Der automatische Cache

Ein recht effektives Caching-System ist seit Version 2.0x in Wordpress eingebaut.

Aktiviert wird es mit der entsprechenden Definition ENABLE_CACHE in der Datei “wp-config.php” - wobei man zusätzlich mittels CACHE_EXPIRATION_TIME (Angabe in Sekunden) bestimmen kann, wie lang die gecacheten Daten gültig sein sollen:

define('ENABLE_CACHE', true);
define('CACHE_EXPIRATION_TIME', 604800);

Der Wordpress-Cache braucht Schreibrechte im Ordner “wp-content”, um automatisch den Ordner “cache” erstellen zu können.

Wer aus Sicherheitsgründen nicht so freigiebig mit den Berechtigungen ist, kann den benötigten Ordner natürlich auch selbst erstellen und die Schreibrechte nur auf diesen beschränken.

Der Effekt ist deutlich: Die Anzahl der Datenbank-Abfragen reduziert sich bei aktivem Caching-System enorm. Insbesondere, wer unter einer 2.0x-Version vorwiegend mit “Pages” arbeitet, wird die verbesserte Performance bemerken.

Ein rätselhaftes Phänomen von Wordpress 2.0x ist nämlich, dass die Anzahl der Datenbank-Abfragen proportional zur ID der aufgerufenen Page steigt. Wenn man öfter mal etwas löscht oder normale “Blog-Funktionen” zusammen mit der Seitenverwaltung im Einsatz hat, erstaunt einen der Aufruf von echo $wpdb->num_queries; im Footer auch ohne “leistungshungrige PlugIns” teilweise mit Werten von weit über 100.

Übrigens ist das der Grund, warum ich mich lange Zeit davor gescheut habe, von 1.52 auf 2.0x upzugraden. Wordpress 2.1x sorgt bei massivem Einsatz von Pages hingegen nicht mehr für größere Überraschungen.

 

Erweiterter Einsatz des Wordpress-Cache

Was vermutlich allgemein nicht so bekannt ist: Das “hauseigene” Caching-System kann man auch für Funktionen und PlugIns einsetzen - Man ist also nicht auf die vorgegebenen Datensätze beschränkt. Die Vorgehensweise ist dabei ähnlich wie bei Einsatz des PlugIns POC Output Cache.

Prinzipiell kann so ziemlich alles gecachet werden, was man in irgendeiner Form in einer Variablen ablegen kann. Die Einsatzmöglichkeiten sind entsprechend flexibel - Im Folgenden beschreibe ich die grundsätzliche Anwendung.


Schritt 1) Kein “echo”, sondern “return”

Angenommen, wir haben ein “leistungshungriges” PlugIn im Einsatz, das auch direkt etwas in HTML ausgibt …

function LeistungsHungrigesPlugIn() {
	(...  Code ...)
	echo $Output
}

… muss zunächst dafür gesorgt werden, dass nicht gleich eine Ausgabe erzeugt wird, sondern die Werte für die weitere Verwendung zurückgegeben werden:

function LeistungsHungrigesPlugIn() {
	(...  Code ...)
	//echo $Output
	return $Output
}


Schritt 2) Theme bearbeiten

Danach muss das Theme bearbeitet werden, denn jetzt gibt das PlugIn ja nichts mehr aus - sondern es werden nur Werte zurückgegeben. Dort, wo früher …

<?php LeistungsHungrigesPlugIn(); ?>

… stand, “passiert” nichts. Aber das ist in Ordnung, denn wir wollen ja gar nicht, dass die PlugIns irgendetwas ausgeben - es sollen ja letztenendes die Werte aus einer gecacheten Datei geholt werden.


Schritt 3) “Werte” sammeln

Weil jeder Zugriff auf eine gecachete Datei mindestens einen Datenbank-Zugriff benötigt, ist es nicht sinnvoll, alle Ausgaben in einzelnen Keys zu speichern - In einigen Fällen verlangsamt man sein System dadurch sogar wieder.

Daher ist es empfehlenswert, gleich die Ausgaben von mehreren Funktionen oder PlugIns zusammen mit dem “umgebenden HTML” in einer gemeinsamen Variablen abzulegen. Das könnte beispielsweise so aussehen, dass man diesen Code …

<div class="AusgabeBox1">
<?php LeistungsHungrigesPlugIn1(); ?>
</div>

<div class="AusgabeBox2">
<?php LeistungsHungrigesPlugIn2(); ?>
</div>

<div class="AusgabeBox3">
<?php LeistungsHungrigesPlugIn3(); ?>
</div>

… gleich in eine neue Funktion umwandelt, auf deren Ergebnisse der Cache-Aufruf nachher zurückgreifen kann:


<?php
function get_AllesSammeln() {
	$Sammlung =
		"<div class=\"AusgabeBox1\">\n".
		LeistungsHungrigesPlugIn1()."\n".
		"</div>\n\n".
		"<div class=\"AusgabeBox2\">\n".
 		LeistungsHungrigesPlugIn2()."\n".
		"</div>\n\n".
		"<div class=\"AusgabeBox3\">\n".
 		LeistungsHungrigesPlugIn3()."\n".
		"</div>\n\n";
	return $Sammlung;
}
?>
	


Schritt 4) Einbau der Cache-Funktion

Um dafür zu sorgen, dass eine $Sammlung gespeichert wird, wenn’s noch kein “gespeichertes Gegenstück” gibt - und danach dann auf diesen abgespeicherten Wert zurückgegriffen wird - baut man als letzten Schritt die Cache-Logik um die Ausgabe herum:


<?php
function show_AllesSammeln() {
	$key = 'EinmaligerName';
	$Output = wp_cache_get($key, 'BeliebigerUnterOrdner');
	if (false === $Output) {
		$Output = get_AllesSammeln();
		wp_cache_set($key, $Output, 'BeliebigerUnterOrdner', 604800);
	}
	echo $Output;
?>
	

Es passiert also Folgendes:

  • Mit $key = … wird die Bezeichnung der Cache-Datei festgelegt

  • Mit wp_cache_get(); wird geprüft, ob sich bereits eine fertige Cache-Datei in “BeliebigerUnterOrdner” befindet

  • Die Variable $Output wird mit dem Ergebnis gefüllt

  • Gibt es kein Ergebnis, wurde noch nichts zwischengespeichert, so wird die Funktion get_AllesSammeln(); ausgeführt

  • Außerdem wird dann mit wp_cache_set(); eine neue Cache-Datei in “BeliebigerUnterOrdner” gespeichert - die 604.800 Sekunden lang gültig ist (also eine ganze Woche)

  • Zum Schluss wird der Wert von $Output angezeigt

Wichtig ist, dass jede Bezeichnung für $key nur einmal benutzt wird, sonst überschreiben sich die Cache-Dateien ungewollt gegenseitig.

Wenn beispielsweise eine der Funktionen LeistungsHungrigesPlugIn(); auf jeder statischen Seite etwas anderes ausgibt, müssen auch entsprechend viele Cache-Dateien angelegt werden.

Im folgenden Beispiel wird wieder der Rückgabewert der Funktion get_AllesSammeln(); gecachet, allerdings für jede aufgerufene Page ein eigener - Je nach ID der aktuellen Page werden dabei entsprechend benannte Keys benutzt …

<?php 

function show_AllesSammeln() {
	// Falls $posts ist nicht verfügbar sein sollte:
	// global $posts;
	$key = 'EinmaligerName';
	if (is_page()) {
		$key .= $posts[0]->ID;
	}
	$Output = wp_cache_get($key, 'BeliebigerUnterOrdner');
	if (false === $Output) {
		$Output = get_AllesSammeln();
		wp_cache_set($key, $Output, 'BeliebigerUnterOrdner', 604800);
	}
	echo $Output;
?>
	

Anregung: Wenn die Daten, die gecachet werden sollen, in der Ausgabe “weit verstreut” liegen (beispielsweise teils in der “header.php”, teils in der “sidebar.php” des verwendeten Themes) kann man die Daten auch in einem gemeinsamen Array ablegen, so dass nicht für jeden HTML-Schnippsel eine neue Cache-Datei verwaltet werden muss …

 

Wann ist Caching sinnvoll?

Der Aufwand, diverse PlugIns “Cache tauglich” zu machen, ist natürlich nicht unerheblich - denn die meisten PlugIns geben direkt HTML aus. Und nicht immer reicht es, ganz am Ende aus einem “echo” ein “return” zu machen, vielfach muss man auch schon vorher Einiges umstellen.

Aber wer z.B. das PlugIn “Page Category Organiser” im Einsatz hat, wird sich sicherlich schon mal über die vielen Datenbank-Abfragen gewundert haben, die erzeugt werden, wenn man viele Seiten nach “Kategorie” geordnet ausgeben möchte. Wenn man dazu noch die neuesten 20 Events aus dem “EventCalendar” anzeigen lässt, kann man seine Seite schon ziemlich ausbremsen.

Bei einem “meiner” Wordpress-Projekte habe ich durch konsequent eingesetztes Caching die Anzahl der Datenbank-Abfragen von über 200 je Seite auf durchgängig unter 20 reduzieren können - Und ich denke, spätestens dann wird Caching richtig interessant: In dem Fall (zugegebenermaßen ein Extremfall) hat das Caching einen Geschwindigkeits-Vorteil von etwa einer ganzen Sekunde je Seiten-Aufruf gebracht.