Ungenutzte JS und CSS Files aus WordPress entfernen

80% Deiner CSS und JS Dateien könnten auch gelöscht werden!

Krasse These? Nun gerade wenn man WordPress benutzt eigentlich eher der Standard als das krasse Extrembeispiel. Die Frage ist ja: Woher kommt das denn bitte?

Es gibt für alles ein Plug-In

In der WordPress-Welt wird sehr viel über Plug-Ins abgedeckt. Selbst für die Geschwindigkeits-Optimierung und JSS Reduzierung wird ein Plug-In installiert, dass sich selbst mit noch mehr JavaScript und CSS im Source Code festsetzt. Der Klassiker zum Beispiel wäre das Revolution Slider Plugin, das fein säuberlich auf jeder einzelnen Seite seine Dateien lädt obwohl nur auf der Startseite ein Slider eingebaut wurde.

Welche Scripte lädt meine Seite eigentlich?

Um ungewolltes JavaScript zu entfernen, sollte man wissen welche Dateien eigentlich geladen werden.

Eine Möglichkeit wäre nun den Source Code der Seite zu öffnen und eine Liste zu erstellen. Und das macht man dann für jede einzelne Seite, damit man feststellen kann wo welche Dateien geladen werden. Doch das ist umständlich, zeitaufwendig und nervig. Es geht auch viel leichter!

Ausgabe der benutzten JS Handles pro Seite

Einfach mal alles auflisten was mit wp_enqueue_script geladen wurde

Der erste Schritt besteht darin, sich ein eigenes Plug-In anzulegen. Alternativ könnt Ihr natürlich auch das Beispiel Plugin nutzen, dass ich euch hier zur Verfügung stelle.

Erstellt also eine Datei mit dem Namen wp_remove_unused.php (oder etwas Vergleichbares, in der Namensgebung bin ich relativ kreativlos) und tragt den Plug-In Header ein.

<?php
/*
 * Plugin Name: SameMission räumt auf
 * Plugin URI: https://benjamin-mylius.de/ungenutze-js-css-dateien-entfernen/
 * Version: 1.0
 * Description: Gibt im Frontend für Administratoren eine Handle-List aller JS und CSS Dateien aus. Handles die nicht geladen werden sollen können hier definiert werden.
 * Author: Benjamin Mylius
 * Author URI: https://www.samemission.de/
*/

Was das Plug-In als erstes können muss: Auflisten was überhaupt auf der Seite geladen wird.

Es gibt zwei globale Variablen in WordPress um Scripte und Styles zu speichern:

  • $wp_scripts
  • $wp_styles

Lässt man sich nun also einen var_dump für beide Globalen ausgeben würde man sehen, welche Scripte und Styles von allen Plug-Ins und von WordPress registriert worden sind. Uns interessieren aber nur die, die geladen wurden.

// Liste alle Assets auf, die geladen werden. Nur für Administratoren sichtbar!
add_action('wp_print_footer_scripts', 'sm_list_stuff', 900000);

function sm_list_stuff(){
    if ( !current_user_can('delete_users') ){
        return;
    }
 
    echo '<h2>Liste aller Scripte, die auf dieser Seite geladen wurden.</h2>';
    echo '<p>Die Ausgabe kann von Seite zu Seite verschieden sein, je nachdem welche Scripte geladen worden sind.</p>';
 
    // Zeige alle geladenen Scripte (JS)
    global $wp_scripts;
    sm_print_assets($wp_scripts);
 
    echo '<h2>Liste aller CSS Dateien, die auf dieser Seite geladen wurden.</h2>';
    echo '<p>Die Ausgabe kann von Seite zu Seite verschieden sein, je nachdem welche Scripte geladen worden sind.</p>';
    // Zeige alle geladenen Styles (CSS)
    global $wp_styles;
    sm_print_assets($wp_styles);
}

Also hängen wir uns an den wp_print_footer_scripts Hook mit einer sehr hohen Priorität um sicher zu gehen, dass auch alle Scripte geladen wurden, bevor sie aufgelistet werden.

Ausserdem soll nicht jeder User auf unserer Seite diese Liste sehen können, deswegen stellen wir sicher, dass die Ausgabe nur für Administratoren gilt.

Jetzt folgen noch Zwei weitere Funktionen: sm_print_assets und sm_asset_template:

function sm_print_assets($wp_asset){
    $nb_of_asset = 0;
    foreach( $wp_asset->queue as $asset ) :
        $nb_of_asset ++;
        $asset_obj = $wp_asset->registered[$asset];
        sm_asset_template($asset_obj, $nb_of_asset);
    endforeach;
}
 
function sm_asset_template($asset_obj, $nb_of_asset){
    if( is_object( $asset_obj ) ){
        echo '<div class="wra_asset" style="padding: 2rem; font-size: 0.8rem; border-bottom: 1px solid #ccc;">';
 
        echo '<div class="wra_asset_nb"><span style="width: 150px; display: inline-block">Nummer:</span>';
        echo $nb_of_asset . '</div>';
 
 
        echo '<div class="wra_asset_handle"><span style="width: 150px; display: inline-block">Handle:</span>';
        echo $asset_obj->handle . '</div>';
 
        echo '<div class="wra_asset_src"><span style="width: 150px; display: inline-block">Quelle:</span>';
        echo $asset_obj->src . '</div>';
 
        echo '<div class="wra_asset_deps"><span style="width: 150px; display: inline-block">Abhängigkeiten:</span>';
        foreach( $asset_obj->deps as $deps){
            echo $deps . ' / ';
        }
        echo '</div>';
 
        echo '<div class="wra_asset_ver"><span style="width: 150px; display: inline-block">Version:</span>';
        echo $asset_obj->ver . '</div>';
 
        echo '</div>';
 
    }

Was wir damit auflisten werden:

  • Die Nummer der JavaScript oder CSS Datei: um einen Überblick zu behalten.
  • Der Handle: Das ist nämlich der eindeutige Identifizierer der von der wp_enqueue_scripts genutzt wird
  • Die Quelle: Der Speicherort der Datei
  • Die Version: Die aktuelle Version der Datei

Für unsere Zwecke brauchen wir nur den Handle, aber mit additionalen Informationen sieht das ganze runder aus und man bekommt eine Idee davon warum und wo diese Dateien geladen werden.

Ungenutzes CSS und JS in WordPress entfernen

Zum entfernen von den Dateien stellt WordPress insgesamt 4 Funktionen zur Verfügung:

Mit WordPress conditional Tags und custom post types kann man das entfernen der Scripte und Styles noch gezielter steuern.

function sm_filter_scripts(){
    #wp_deregister_script($handle);
    #wp_dequeue_script($handle);

    if( !is_page( 'contact' ) ){
        // Contact-Form-7 soll nur auf Contact-Form-7 Seiten geladen werden.
        wp_deregister_script('contact-form-7');
        wp_dequeue_script('contact-form-7');
    }

}

Als Beispiel hier dient das Contact-Form-7 Handle, da ein Kontaktformular nur auf der Contact Page existiert soll auch nur auf dieser Seite das JavaScript geladen werden.

Eine Liste der verschiedenen conditional tags, die Seitens WordPress genutzt werden können, gibt es hier

Das fertige Plug-In

Wie versprochen, wer nicht die Muse hat sich bis hier hin durchzuarbeiten, kann das Plugin auch ganz einfach herunterladen. Eine Anleitung, wie das Plugin-gehandhabt wird folgt in kürze

Sicherheitslücken finden und schliessen

Gerade jetzt zur Zeit, wo Gutenberg veröffentlich wurde und noch nicht so läuft, wie man sich das vorstellt, sträuben sich viele User auf die aktuelle Version zu updaten. Warum Updates eine gute Sache sind und wie sie zur Sicherheit der WordPress Installation beitragen will ich hier kurz beleuchten.

Wenn Ihr meiner Anleitung Kali Linux in VirtualBox installieren gefolgt seid, habt ihr bereits eine Kali Installation. Solltet ihr diese noch nicht haben, macht es Sinn dies vorher einmal durch zu gehen.

Sicherheitslücken mit WPScan finden

WPScan öffnen
Hier findet Ihr WPScan

Unter “Anwendungen -> Webapplikationen -> wpscan” findet man das Tool, dass wir für den ersten Schritt benötigen. Zunächst wollen wir erst einmal schauen, ob unsere WordPress Installation wirklich Sicherheitslücken aufweist.

Der Befehlsaufbau lautet dabei wie folgt:

wpscan --url [URL einfügen]

Dieser Befehl ist der simpelste, den man mit wpscan ausführen kann. Würde uns interessieren welche Benutzer auf dem System angemeldet sind, könnte man noch den enumerate Befehl anhängen, dazu komme ich aber gleich nochmal.

wpscan start
wpscan beginnt zu arbeiten

Wpscan durchsucht die aktuelle URL nun nach allen Möglichen Parametern. Unter anderem: Versionen der WordPress Installation und Versionen der installierten Plug-ins.

Wenn alles in Ordnung mit dem geprüften Part ist wird dies mit einem grünen Plus versehen. Sollte das Programm eine Schwachstelle gefunden haben, wird diese mit einem roten Ausrufezeichen markiert.

Sicherheitslücken in WordPress gefunden!

Auf der aktuell geprüften Seite wurden insgesamt 17 Sicherheitslücken gefunden. Wer jetzt denkt, dass diese extra für diesen Beitrag offen gelassen worden sind liegt weit daneben. Diese Findings sind mehr die Tagesordnung in aktuell laufenden Systemen als die Ausnahme.

Folgende Sicherheitslücken wurden identifiziert:

Sicherheitslücke: Contact Form 7

Sicherheitslücken in Contact Form 7
register_post_type() Privilege Escalation found

Die erste Sicherheitslücke wird uns direkt von Contact Form 7 angeboten. Ausserdem werden auch die Erklärungen zu dieser Sicherheitslücke angezeigt, so dass sich der interessierte User mehr darüber informieren kann. Ausserdem sieht man auch, wie man das Problem beheben kann.

Fixed in: 5.0.4

wpscan – Kali Linux

Ein Update des Plug-ins wäre also dringend anzuraten.

Sicherheitslücke: LayerSlider

Sicherheitslücken im LayerSlider Plugin
Der LayerSlider beschert uns gleich 3 Sicherheitslücken

Die verwendete LayerSlider Version öffnet die Tore für Angriffe gleich so weit, dass man sich nicht mal mehr besonders anstrengen müsste um dem System schaden zuzuführen. Und auch hier können die Lücken geschlossen werden, indem man mindestens auf Version 6.2.1. updated.

Sicherheitslücke: Wordfence

Sicherheitslücken in Wordfence 1
Wordfence kommt gleich mit 12 Lücken daher

Wordfence, ein WordPress Plugin, dass für Sicherheit sorgt. Öffnet auch gleich Tür und Tor der WordPress Installation, aber das Plugin kann nichts dafür, dass der Admin es nicht geupdated hat.

Sicherheitslücken in Wordfence 2
XSS und Banned IP Bypasses – Ein Spaß für jeden Angreifer

Spätestens jetzt, sollte man kalte Füße oder Gänsehaut bekommen. Und sich bereits ein Backup der Installation ziehen, damit man sich ans updaten der Plug-ins machen kann. Aber da geht ja sicher noch mehr oder? -Na klar, einen haben wir noch.

Sicherheitslücke Wordfence 3
Und weiter gehts, XSS und Bypasses ohne Ende

Wer sich fragt was XSS bedeutet. Sollte sich ausgiebig über Cross Site Scripting informieren. Aber vielleicht gibt es dazu später noch einen Beitrag.

Sicherheitslücke: Yoast SEO

Sicherheitslücke: Yoast
Auch eine alte Verison von Yoast ist betroffen

Diese Sicherheitslücke von Yoast ist “nicht so schwerwiegend” und betrifft nur Systeme in denen die Rolle SEO-Manager vergeben wurde. Aber warum sollte man etwas riskieren, wenn man so eine lücke mit einem simplen Mausklick beheben könnte?

Fazit:

Der Scan der Seite hat Sage und Schreibe 3 Minuten gedauert und 17 mögliche Angriffsstellen offenbart. Alle 17 lassen sich durch das Update der Plugins beheben. Leider ist es oftmals so, dass gerade wenn man mehrere Seiten unter der Fuchtel hat. Gar nicht im Fokus hat auf welchem System welche Versionen installiert sind.

Double Check am Ende

Da ich ein Freund der Absicherung bin prüfe ich die Sicherheitslücken erneut mit einem anderen Programm. In meinem Fall mit wpseku. Die benötigten Dateien bekommt ihr hier.

Run WPSeku.py

WPSeku Help Console
Lieber auf Nummer sicher gehen bei der Sicherheit

Gestartet wird der Scan mittels:

python3 wpseku.py --url www.URL.com

Sicherheitslücke: Revslider

WPSecu Scan 1
17 waren ja noch nicht genug, hier kommt Nummer 18

Na zum Glück haben wir nochmal nachgeschaut, denn der RevSlider ist auch betroffen, bei wpseku.py wird auch noch der passende Exploit aus dem Metasploit Framework angeboten. Aber hier geht es nicht um das testen des Exploits.

Sicherheitslücke: js_composer

WPSeku Scan 2
Und der js_composer liefert uns Sicherheitslücke 19

Die letzte Sicherheitslücke liefert uns der js_composer mit einer XSS Verletzlichkeit.

Darum sollte man seine Plugins up-to-date haben

Wie der nächste Schritt für diese Seite aussehen muss, sollte jetzt jedem klar sein. Denn genau jetzt muss man damit beginnen die Plugins Stück für Stück zu updaten und dann eine erneute Prüfung durchzuführen.

wpscan und wpseku sind frei zugängliche Programme, die sich jeder installieren kann. Und es ist immer besser für die WordPress Seite, wenn man den Script Kiddies und Pseudo Hackern, die mal gehört haben, dass man leicht in ein WordPress einbrechen kann, nicht den Weg frei macht.

Vier MySQL Querys die Dir das Leben leichter machen

Kennste oder?

Du entwickelst eine Website auf deiner Testumgebung oder Local mit Xampp, Lampp oder einem *ampp deiner Wahl. Der Kunde (insofern vorhanden) ist durchaus zufrieden bei der Präsentation und “das Teil soll jetzt online gehen”

Du fängst an deine Daten und die Datenbank zu kopieren, verknüpfst Deine Domain mit dem Webspace und dann:

Fehler beim Aufbau einer Datenbankverbindung
“Nanu? Dabei hab ich doch alles richtig kopiert?”

Natürlich! Du hast vergessen die wp-config.php anzupassen. Also gehst du nochmal über den FTP Server, öffnest die Datei und trägst deine Verbindungsdaten in der Datei ein.

Nach dem Abspeichern freust Du Dich schon auf eine schöne Tasse Kaffe.
Aber Pustekuchen: Deine Seite springt auf die URL der Testumgebung zurück.

Anpassungen der URLs in der Datenbank vergessen?

Spätestens jetzt sollten Dir Wörter wie “Better Search Replace” oder “Duplicator” in den Sinn kommen. Und wenn dem nicht so ist, dann wäre das spätestens jetzt der Fall. Was aber tun diese beiden Plugins?

Better Search Replace

Mit Hilfe dieses Plugins ist es möglich nach bestimmten Strings in der Datenbank zu suchen um diese durch andere auszutauschen. Wie mein alter Oberleutnant immer sagte :”Alles heißt so wie das was es tut”

Bildauschnitt Better Search Replace

Das Problem bei der Geschichte:
Du kommst gar nicht in dein Backend um das Plugin zu installieren. Denn wenn du das versuchst kommst du wieder auf deine Testumgebung. Mehr Glück bringt da eventuell das nächste Plugin

Duplicator

Duplicator WordPress Theme

Duplicator ist eine All in One Lösung für den Umzug oder eben dem Duplizieren von WordPress Seiten. Dabei wird ein Abbild deiner aktuellen Version gemacht. Du bekommst zwei Dateien, die du auf deinem FTP Server wieder hochlädst um dann mit dem Wizard die Installation auf dem neuen Server abzuschliessen.

Dabei ändert Duplicator deine URLs nach deinen Vorgaben direkt bei der Installation. Klingt erstmal sehr gut.

Das Problem bei der Geschichte:
Du hast die Daten bereits aufgespielt. Natürlich kannst du jetzt die Datenbank löschen, die Files vom Server löschen. Duplicator auf deinem Testsystem installieren, das Archiv generieren lassen, das Archiv dann hochladen und den Wizard zum installieren durchführen. Und jetzt kommt das große

ABER:

Je nach Verbindungsgeschwindigkeit dauert das Löschen, runter- und wieder hochladen je nach Seitengröße so lange, dass man da überhaupt keine Lust mehr zu hat. Ausserdem möchte man sich vielleicht auch kein externes Plugin installieren für einen Vorgang, den man mit Sage und Schreibe vier SQL Querys selbst erledigen kann.

Hier kommen die Querys

Query 1: Home Base

UPDATE wp_options SET option_value = replace(option_value, 'http://www.oldurl', 'http://www.newurl') WHERE option_name = 'home' OR option_name = 'siteurl';

Mit diesem Query passt du den Basepfad deiner WordPress Installation an, und sorgst dafür, dass das Backend erreichbar wird. Solltest Du Dich, aus welchen Gründen auch immer dazu entscheiden die anderen Schritte nicht durchzuführen.

Query 2: GUID

UPDATE wp_posts SET guid = replace(guid, 'http://www.oldurl','http://www.newurl');

Das Zweite Query passt die URLs bei den Global Unique Identifiern an.

Query 3: Post Content

UPDATE wp_posts SET post_content = replace(post_content, 'http://www.oldurl', 'http://www.newurl');

Nummer Drei ist dafür Verantwortlich, dass deine Beiträge wieder auf der richtigen URL auflaufen.

Query 4: Post Meta

UPDATE wp_postmeta SET meta_value = replace(meta_value,'http://www.oldurl','http://www.newurl');

Das Schlusslicht in der Liste sorgt dafür das auch erweiterte Optionen berücksichtig werden.

Was du also zu tun hast

Wenn du deine Datenbank auf deinem neuen Server aufgespielst hast, gehst du über phpmyadmin in deine Datenbank und führst die Querys nacheinander aus. Dabei ersetzt du natürlich den Tabellen Präfix und die URLs mit deinen aktuellen. Und das wars!

Verschiedene Produktlayouts für WooCommerce?

Das Problem:

Es wurde ein Shop für einen Kunden geplant. Der Einsatz von WooCommerce wurde dafür vorgesehen. Allerdings benötigen wir für eine bestimmte Shop Kategorie ein abweichendes Produktlayout als für die anderen Kategorien.

Standardmäßig kann man aber kein anderes Layout für eine bestimmte Kategorie verwenden.

Aus diesem Grund wurde also eine Lösung benötigt, die für eine vorher definierte Kategorie ein anderes Layout verwendet, als das Default.

Eigene Templatefiles benutzen

Bevor definiert werden kann, welches Template geladen werden soll, muss dieses auch erst mal vorhanden sein. Das Bearbeiten von Corefiles ist nicht update sicher, deswegen kopiert man das Template das man umschreiben möchte in seinen eigenen Themepfad und behält dabei die Filestruktur bei.

Beispiel:

Aus:

/wp-content/plugins/woocommerce/templates/single-product.php

wird:

/wp-content/themes/yourtheme/woocommerce/single-product.php

Nachdem alle benötigten Dateien update sicher in das eigene Template Verzeichnis kopiert worden sind. Kann man die single-product.php auch ohne größere Schäden zu verursachen bearbeiten.

Auszug aus der single-product.php Datei

Modifizieren der single-product.php

Standardmäßig findet sich folgender Codeschnipsel in der single-product.php in Zeile 35, wenn die Datei nicht weiter bearbeitet wurde:

		<?php while ( have_posts() ) : the_post(); ?>
		     <?php wc_get_template_part( 'content', 'single-product' ); ?>
		<?php endwhile; // end of the loop. ?>

Hier befindet sich die Anweisung den Template Part “single-product” auszugeben, solange Posts vorhanden sind. Alles klar soweit. Hier ist also auch genau der Punkt, an dem ich ansetze, um eine andere Template Datei zu laden.

if ( has_term( 'quads', 'product_cat' ) ) {
    woocommerce_get_template_part( 'content', 'single-product-quads' );
} else {
    woocommerce_get_template_part( 'content', 'single-product' );
}

Prüfen der Funktionalität

Wenn man jetzt prüft ob das oben genannte Vorgehen funktioniert, sieht man folgendes:

Leere Shopseite, weil das Template noch nicht eingebunden ist

Das Template wurde geladen, aber es wird nichts angezeigt. Der Grund, der dahinter steckt, ist relativ simpel.
Die Zeile woocommerce_get_template_part( ‘content’, ‘single-product-quads’ ); definiert, dass die Datei content-single-product-quads.php geladen werden soll. Die ist aber schlichtweg einfach noch nicht vorhanden.

Deswegen wird diese Datei als Erstes im Woocommerce Verzeichnis des eigenen Templates erstellt. Ich habe dazu die content-single-product.php kopiert und umbenannt, da ich auf dieser Struktur aufbauen möchte. Lädt man die Datei dann auf den Server, sieht die vorläufige Anzeige so aus:

Standard Single Product Ausgabe

Da die Verknüpfung jetzt klappt, kann man die Datei nach allen Vorlieben umändern und abarbeiten die einem so einfallen.