Hallo @Ash G:
Ich bin nicht 100% gefolgt, wo Sie speziell Probleme hatten, daher bin ich mir nicht sicher, ob ich Ihre Probleme wirklich Punkt für Punkt beantworten kann, aber ich kann erklären, wie dies von Grund auf zu tun ist . Und es sei denn, was Sie tun, ist ein bisschen mehr involviert, als Sie erwähnt haben, dass es ein bisschen mehr Arbeit ist, als Sie erwartet haben, aber es ist immer noch vollständig machbar. Und selbst wenn ich viele Bereiche abdeckte, von denen Sie bereits wissen, dass es eine gute Chance gibt, dass andere mit weniger Wissen oder Erfahrung dies über Google finden und auch davon unterstützt werden.
Bootstrap WordPress mit /wp-load.php
Das erste, was wir in Ihrer my_theme_css.php
Datei tun müssen, ist das Booten der Kernbibliotheksfunktionen von WordPress. Die folgende Codezeile wird geladen /wp-load.php
. Es verwendet , $_SERVER['DOCUMENT_ROOT']
um die Root - Webseite zu finden , so dass Sie Sorge haben nicht darüber , wo Sie speichern diese Datei auf Ihrem Server; Vorausgesetzt, es DOCUMENT_ROOT
ist richtig eingestellt, wie es immer für WordPress sein sollte, dann wird dies WordPress booten:
<?php
include_once("{$_SERVER['DOCUMENT_ROOT']}/wp-load.php");
Das ist also der einfache Teil. Als nächstes kommt der schwierige Teil ...
PHP-Skripte müssen die gesamte Caching-Logik verarbeiten
Ich wette, Sie sind hier gestolpert, weil ich es wirklich getan habe, als ich versucht habe, herauszufinden, wie ich Ihre Frage beantworten kann. Wir sind so an die Caching-Details gewöhnt, die vom Apache-Webserver verarbeitet werden, dass wir vergessen oder gar nicht erkennen , dass wir beim Laden von CSS oder JS mit PHP das ganze schwere Heben selbst erledigen müssen .
Sicher, der Ablauf-Header ist möglicherweise alles, was wir brauchen, wenn wir einen Proxy in der Mitte haben, aber wenn die Anfrage an den Webserver gelangt und das PHP-Skript wohl oder übel Inhalte und den Statuscode "Ok" zurückgibt, sind Sie im Wesentlichen gut habe kein Caching.
Rückgabe von "200 Ok" oder "304 Not Modified"
Insbesondere unsere PHP - Datei , dass CSS Bedürfnisse kehrt korrekt auf die reagieren Anfrage vom Browser gesendete Header. Unser PHP-Skript muss den richtigen Statuscode basierend auf dem Inhalt dieser Header zurückgeben. Wenn der Inhalt bereitgestellt werden muss, weil es sich um eine erstmalige Anforderung handelt oder weil der Inhalt abgelaufen ist, sollte das PHP-Skript den gesamten CSS-Inhalt generieren und mit "200 Ok" zurückkehren .
Auf der anderen Seite , wenn wir auf den Cache-bezogenen bestimmen basierend Anfrage - Header , dass der Client - Browser bereits die neueste CSS hat , wir sollten nicht jede CSS zurückzukehren und stattdessen zurückkehren mit einem „304 Not Modified“ . Die zu Codezeilen dafür sind jeweils (natürlich würden Sie niemals beide Zeilen nacheinander verwenden, ich zeige dies hier nur der Einfachheit halber) :
<?php
header('HTTP/1.1 200 Ok');
header('HTTP/1.1 304 Not Modified');
Vier Geschmacksrichtungen des HTTP-Caching
Als nächstes müssen wir uns die verschiedenen Möglichkeiten ansehen, wie HTTP mit dem Caching umgehen kann. Das erste ist, was Sie erwähnen; Expires
::
- Läuft ab : Dieser
Expires
Header erwartet ein Datum imFormat( PHP- gmdate()
Funktion )'D, d M Y H:i:s'
mit einem' GMT'
angehängten ( GMT steht für Greenwich Mean Time ). Theoretisch werden der Browser und die nachgeschalteten Proxys zwischengespeichert, bis die angegebene Zeit abgelaufen ist, nach der er gestartet wird die Seite erneut anfordern. Dies ist wahrscheinlich der bekannteste Caching-Header, aber offensichtlich nicht der bevorzugte. Cache-Control ist die bessere . Interessanterweise konnte ich bei meinen Testslocalhost
mit Safari 5.0 unter Mac OS XI den Browser nie dazu bringen, denExpires
Headerzu respektieren. es immerhat die Datei erneut angefordert (wenn jemand dies erklären kann, wäre ich dankbar). Hier ist das Beispiel, das Sie von oben gegeben haben:
header("Expires: Thu, 31 Dec 2020 20:00:00 GMT");
- Cache-Kontrolle : Der
Cache-Control
Header ist einfacher zu bearbeiten als derExpires
Header, da Sie nur die Anzahl der Sekunden in Sekunden angeben müssen, damitmax-age
Sie kein genaues Datumsformat in Zeichenfolgenform erstellen müssen, das leicht falsch zu verstehen ist . Darüber hinausCache-Control
können verschiedene andere Optionen verwendet werden, z. B. die Möglichkeit, den Clientanzuweisen,den Cache mithilfe diesermustrevalidate
Optionimmer erneut zu validieren,undpublic
wenn Sie das Caching für normalerweise nicht zwischenspeicherbare Anforderungen (dh Anforderungen überHTTPS
)erzwingenund sogar nicht zwischenspeichernmöchten,wenn Sie dies benötigen (Das heißt, Sie möchten möglicherweise ein 1x1-Pixel-Anzeigen-Tracking erzwingen. GIF darf nicht zwischengespeichert werden.) Als obExpires
ich dies auch beim Testennicht zum Laufen bringen könnte( Hilfe?) Das folgende Beispiel wird für einen Zeitraum von 24 Stunden (60 Sekunden x 60 Minuten x 24 Stunden) zwischengespeichert:
header("Cache-Control: max-age=".60*60*24.", public, must-revalidate");
- Last-Modified / If-Modified-Since : Dann gibt es das
Last-Modified
Antwort-Header- und das If-Modified-Since
Request-Header-Paar. Diese verwenden ebenfalls dasselbe GMT-Datumsformat wie derExpires
Header, führen jedoch einen Handshake zwischen Client und Server durch. Das PHP-Skript muss einenLast-Modified
Headersenden(den Sie übrigens nur aktualisieren sollten, wenn Ihr Benutzer sein benutzerdefiniertes CSS zuletzt aktualisiert hat). Danach sendet der Browser weiterhin denselben Wert wie einenIf-Modified-Since
Header zurück und es liegt in der Verantwortung des PHP-Skripts Vergleichen Sie den gespeicherten Wert mit dem vom Browser gesendeten. Hier muss das PHP-Skript die Entscheidung treffen, ob a200 Ok
oder abereitgestellt werden soll304 Not Modified
. Hier ist ein Beispiel für das Bereitstellen desLast-Modified
Headers unter Verwendung der aktuellen Zeit (was nicht derFall ist)was wir tun wollen; siehe das spätere Beispiel für das, was wir tatsächlich brauchen):
header("Last-Modified: " . gmdate('D, d M Y H:i:s', time()).'GMT');
Und so würden Sie die Last-Modified
vom Browser über den If-Modified-Since
Header zurückgegebenen Informationen lesen :
$last_modified_to_compare = $_SERVER['HTTP_IF_MODIFIED_SINCE'];
- ETag / If-None-Match : Und schließlich gibt es den
ETag
Antwortheader und dasIf-None-Match
Anforderungsheaderpaar. DasETag
ist eigentlich nur ein Token, das unser PHP auf einen eindeutigen Wert setzt (normalerweise basierend auf dem aktuellen Datum) und an den Browser sendet und der Browser gibt es zurück. Wenn sich der aktuelle Wert von dem unterscheidet, den der Browser zurückgibt, sollte Ihr PHP-Skript den Inhalt neu200 Ok
generieren,den ein Serversonst nicht generiert und a bereitstellt304 Not Modified
. Hier ist ein Beispiel für die Einstellung einer unterETag
Verwendung der aktuellen Zeit:
header("ETag: " . md5(gmdate('D, d M Y H:i:s', time()).'GMT'));
Und so würden Sie die ETag
vom Browser über den If-None-Match
Header zurückgegebenen Informationen lesen :
$etag_to_match = $_SERVER['HTTP_IF_NONE_MATCH'];
Nachdem wir alles behandelt haben, schauen wir uns den eigentlichen Code an, den wir brauchen:
Bereitstellen der CSS-Datei über init
undwp_enqueue_style()
Sie haben das nicht gezeigt, aber ich dachte, ich würde es zum Nutzen anderer zeigen. Hier ist der Funktionsaufruf, der WordPress anweist, es my_theme_css.php
für sein CSS zu verwenden. Dies kann in der functions.php
Themendatei oder auf Wunsch auch in einem Plugin gespeichert werden:
<?php
add_action('init','add_php_powered_css');
function add_php_powered_css() {
if (!is_admin()) {
$version = get_theme_mod('my_custom_css_version',"1.00");
$ss_dir = get_stylesheet_directory_uri();
wp_enqueue_style('php-powered-css',
"{$ss_dir}/my_theme_css.php",array(),$version);
}
}
Es gibt mehrere Punkte zu beachten:
- Verwendung von
is_admin()
, um das Laden des CSS im Administrator zu vermeiden (es sei denn, Sie möchten das ...),
- Verwendung von
get_theme_mod()
, um das CSS mit einer Standardversion von zu laden 1.00
(mehr dazu gleich),
- Verwendung von
get_stylesheet_directory_uri()
, um das richtige Verzeichnis für das aktuelle Thema abzurufen, auch wenn das aktuelle Thema ein untergeordnetes Thema ist.
- Verwendung von,
wp_enqueue_style()
um das CSS in die Warteschlange zu stellen, damit WordPress es zum richtigen Zeitpunkt laden kann, wobei 'php-powered-css'
ein beliebiger Name später ( falls erforderlich ) als Abhängigkeit verwendet werden kann. Leer array()
bedeutet, dass dieses CSS keine Abhängigkeiten aufweist ( obwohl dies in der realen Welt häufig der Fall ist eine oder mehrere ) und
- Verwendung von
$version
; Wahrscheinlich die wichtigste, wir empfehlen wp_enqueue_style()
, ?ver=1.00
der /my_theme_css.php
URL einen Parameter hinzuzufügen , damit der Browser ihn bei einer Änderung der Version als eine völlig andere URL ansieht (viel mehr dazu in Kürze).
Einstellung $version
und Last-Modified
wann Benutzer CSS aktualisiert
Also hier ist der Trick. Jedes Mal, wenn der Benutzer sein CSS aktualisiert, möchten Sie den Inhalt bereitstellen und nicht warten, bis 2020
der Browser-Cache aller Benutzer eine Zeitüberschreitung aufweist, oder? Hier ist eine Funktion, die in Kombination mit meinem anderen Code dies erreicht. Verwenden Sie jedes Mal, wenn Sie vom Benutzer aktualisiertes CSS speichern, diese Funktion oder Funktionalität, die den folgenden Funktionen ähnelt:
<?php
function set_my_custom_css($custom_css) {
$new_version = round(get_theme_mod('my_custom_css_version','1.00',2))+0.01;
set_theme_mod('my_custom_css_version',$new_version);
set_theme_mod('my_custom_css_last_modified',gmdate('D, d M Y H:i:s',time()).' GMT');
set_theme_mod('my_custom_css',$custom_css);
}
Die set_my_custom_css()
Funktion erhöht die aktuelle Version automatisch um 0,01 (was nur ein beliebiger von mir ausgewählter Inkrementwert war) und setzt das Datum der letzten Änderung auf " Jetzt" und speichert schließlich das neue benutzerdefinierte CSS. Das Aufrufen dieser Funktion ist möglicherweise so einfach (wo new_custom_css
sie wahrscheinlich über einen Benutzer zugewiesen wird, der übermittelt wird, $_POST
anstatt durch Hardcodierung, wie Sie hier sehen) :
<?php
$new_custom_css = 'body {background-color:orange;}';
set_my_custom_css($new_custom_css);
Das bringt uns zum letzten, wenn auch bedeutenden Schritt:
Generieren des CSS aus dem PHP-Skript
Endlich sehen wir das Fleisch, die eigentliche my_theme_css.php
Akte. Auf einem hohen Niveau testet es sowohl die If-Modifed-Since
gegenüber dem gespeicherten Last-Modified
Wert und die If-None-Match
gegen die , ETag
die von der gespeicherten abgeleitet wurde Last-Modified
Wert und wenn weder geändert setzt nur den Header 304 Not Modifed
und Zweige bis zum Ende.
Wenn sich jedoch einer von beiden geändert hat, wird der Expires
, Cache-Control
. Last-Modified
und Etag
Überschriften sowie ein 200 Ok
und, das angibt, dass der Inhaltstyp ist text/css
. Wir brauchen wahrscheinlich nicht alle, aber angesichts der Tatsache, wie schwierig das Caching mit verschiedenen Browsern und Proxys sein kann, schadet es meiner Meinung nach nicht, alle Basen abzudecken. (Und jeder mit mehr Erfahrung mit HTTP-Caching und WordPress meldet sich bitte, wenn ich irgendwelche Nuancen falsch verstanden habe.)
Der folgende Code enthält einige weitere Details, aber ich denke, Sie können sie wahrscheinlich selbst herausarbeiten:
<?php
$s = $_SERVER;
include_once("{$s['DOCUMENT_ROOT']}/wp-load.php");
$max_age = 60*60*24; // 24 hours
$now = gmdate('D, d M Y H:i:s', time()).'GMT';
$last_modified = get_theme_mod('my_custom_css_last_modified',$now);
$etag = md5($last_modified);
if (strtotime($s['HTTP_IF_MODIFIED_SINCE']) >= strtotime($last_modified) || $s['HTTP_IF_NONE_MATCH']==$etag) {
header('HTTP/1.1 304 Not Modified');
} else {
header('HTTP/1.1 200 Ok');
header("Expires: " . gmdate('D, d M Y H:i:s', time()+$max_age.'GMT'));
header("Cache-Control: max-age={$mag_age}, public, must-revalidate");
header("Last-Modified: {$last_modified}");
header("ETag: {$etag}");
header('Content-type: text/css');
echo_default_css();
echo_custom_css();
}
exit;
function echo_custom_css() {
$custom_css = get_theme_mod('my_custom_css');
if (!empty($custom_css))
echo "\n{$custom_css}";
}
function echo_default_css() {
$default_css =<<<CSS
body {background-color:yellow;}
CSS;
echo $default_css;
}
Also mit diesen drei Hauptcodebits; 1.) die add_php_powered_css()
vom init
Hook aufgerufene Funktion , 2.) die set_my_custom_css()
von welchem Code auch immer aufgerufene Funktion ermöglicht es dem Benutzer, sein benutzerdefiniertes CSS zu aktualisieren, und schließlich 3.) das my_theme_css.php
sollten Sie so ziemlich geleckt haben.
Weiterführende Literatur
Abgesehen von den bereits verlinkten Artikeln stieß ich auf einige andere Artikel, die ich für sehr nützlich hielt, und dachte mir, ich sollte sie hier verlinken:
Epilog:
Aber ich würde das Thema nicht verlassen, ohne abschließende Kommentare abzugeben.
Läuft ab in 2020
? Wahrscheinlich zu extrem.
Erstens glaube ich nicht, dass Sie Expires
das Jahr 2020 festlegen möchten . Browser oder Proxys, die dies respektieren, Expires
werden auch nach vielen CSS-Änderungen nicht erneut angefordert. Es ist besser, etwas Vernünftiges wie 24 Stunden festzulegen (wie ich es in meinem Code getan habe), aber selbst das wird die Benutzer für den Tag frustrieren, an dem Sie Änderungen am fest codierten CSS vornehmen, aber die bereitgestellte Versionsnummer vergessen. Moderation in allen Dingen?
Dies könnte sowieso alles übertrieben sein!
Als ich verschiedene Artikel las, um Ihre Frage zu beantworten, stieß ich im Mr. Cache Tutorial selbst, Mark Nottingham, auf Folgendes :
Der beste Weg, um ein Skript cachefreundlich zu machen (und eine bessere Leistung zu erzielen), besteht darin, seinen Inhalt bei jeder Änderung in eine einfache Datei zu kopieren. Der Webserver kann es dann wie jede andere Webseite behandeln und Validatoren generieren und verwenden, was Ihnen das Leben erleichtert. Denken Sie daran, nur Dateien zu schreiben, die sich geändert haben, damit die zuletzt geänderten Zeiten erhalten bleiben.
Während all dieser Code, den ich geschrieben habe, cool war und Spaß gemacht hat (ja, das habe ich tatsächlich zugegeben), ist es vielleicht besser, jedes Mal eine statische CSS-Datei zu generieren, wenn der Benutzer stattdessen sein benutzerdefiniertes CSS aktualisiert , und Apache das ganze schwere Heben zu überlassen wie es geboren wurde, um zu tun? Ich sage ja nur...
Hoffe das hilft!