WordPress Cache Busting – oder wieso erscheinen meine Design-Änderungen nicht?

Als Betreiber einer WordPress Website oder eines Blogs werden Sie die Situation vielleicht kennen: Sie haben einige wunderschöne Design-Anpassungen im Adminbereich vorgenommen und sobald Sie eine Vorschau der Änderungen anzeigen möchten, sind diese nicht mehr vorhanden – egal was Sie versuchen. In diesem Fall wird eine Technik namens „Cache Busting“ benötigt.

Einer der vielen möglichen Gründe für dieses Verhalten ist der Caching-Mechanismus des Browsers. Prinzipiell macht es Sinn, dass der Browser nicht immer alle Stylesheets und JavaScript-Dateien bei jedem Aufruf der Seite herunterladen muss, da in der Regel die Frequenz, mit der sich diese Dateien ändern, sehr gering ist. Deswegen weisen sehr viele Websites den Browser an, statische Dateien wie CSS und JavaScript zum Beispiel für 1 Jahr im Cache zu halten. Damit wird eine Menge Bandbreite auf Browser-Seite und zahlreiche Requests server-seitig gespart und die Website kann deutlich schneller angezeigt werden.
Eine sehr gute Erklärung über verschiedene Cache-Techniken von Browsern findet sich hier.

Der Nachteil dieses Verhaltens ist, dass der Browser wissen muss, wenn sich der Inhalt der (CSS- und JavaScript-)Dateien geändert hat. Ansonsten würde er diese Dateien einfach nicht erneut herunterladen und die Version aus seinem internen Cache verwenden. Das ist genau der Fall, wenn der Anwender die durchgeführten Design-Änderungen nicht sieht, solange er nicht seinen Browser-Cache leert (was niemand macht).

Ein einfacher Weg, dieses Problem zu lösen, ist, den Dateinamen oder -pfad der CSS- und JavaScript-Dateien jedes Mal zu ändern, wenn sich deren Inhalt ändert (Hinweis: es gibt natürlich noch andere Wege über E-Tags oder Last-Modified Header, aber das hier ist der einfachste). Dieser Prozess, den Cache zu invalidieren, ist als „Cache Busting“ bekannt.
Im Standard hängt WordPress an jede CSS- und JavaScript-Datei die installierte WordPress-Version an und zwar so:
http://demo.wordpress.recolize.com/wp-includes/js/comment-reply.min.js?ver=5.2.3
(Nebenbei bemerkt ist dieser Weg nicht sehr clever, da so die installierte WordPress Version von außen sichtbar ist und ggfs. Sicherheitslücken aufzeigt).

Die WordPress Version wird angefügt, damit bei jedem Upgrade – das möglicherweise auch eine neue Theme-Version mit Design-Änderungen enthält – der Browser die statischen Dateien neu herunterlädt.
Die meisten WordPress-Themes verwenden statische Stylesheets, die automatisch generiert werden, sobald Änderungen am Design im Backend vorgenommen werden. Das Problem ist, dass der Browser des Anwenders dies nicht mitbekommt, solange sich die WordPress-Version nicht ändert.

Die Lösung für dieses Problem ist ziemlich einfach: wir modifizieren den „ver“-Parameter, so dass er einen sogenannten Hash des Änderungsdatums der Datei enthält. Auf diese Weise wird jedes Mal, wenn die Datei neu generiert wird, das Änderungsdatum aktualisiert und damit ändert sich der Hash. Dies bedeutet, dass der Browser einen neuen Dateinamen erkennt und die geänderte Datei vom Server anfragt. Unser Dateiname sieht jetzt wie folgt aus: http://demo.wordpress.recolize.com/wp-includes/js/comment-reply.min.js?ver=1534832128

Unten finden Sie ein Code Snippet, das z.B. in die WordPress WordPress functions.php Datei integriert werden kann:

<?php
/**
 * WordPress Cache Busting made simple.
 *
 * @author Recolize GmbH <service@recolize.com>
 * @license http://opensource.org/licenses/GPL-3.0 GNU General Public License Version 3 (GPLv3)
 *
 * This script is based on
 * @see https://medium.com/@futuremediagr/easy-versioning-for-css-and-js-files-in-wordpress-e7dad756586c
 * @see https://gist.github.com/ocean90/1966227
 */

function set_custom_ver_css_js($src)
{
    // Don't touch admin scripts.
    if (is_admin()) {
        return $src;
    }

    $_src = $src;
    if (strpos($_src, '//') === 0) {
        $_src = 'http:' . $_src;
    }

    $_src = parse_url($_src);

    // Give up if malformed URL.
    if (false === $_src) {
        return $src;
    }

    // Check if it's a local URL.
    $wordPressUrl = parse_url(home_url());
    if (isset($_src['host']) && $_src['host'] !== $wordPressUrl['host']) {
        return $src;
    }

    $filePath = ABSPATH . $_src['path'];
    if (file_exists($filePath) && strpos($src, 'ver=') !== false) {
        $src = add_query_arg('ver', filemtime($filePath), $src);
    }

    return $src;
}

function css_js_versioning()
{
    add_filter('style_loader_src', 'set_custom_ver_css_js', 9999);
    add_filter('script_loader_src', 'set_custom_ver_css_js', 9999);
}

add_action('init', 'css_js_versioning');
WordPress Cache Busting – oder wieso erscheinen meine Design-Änderungen nicht?