Der Artikel ist zwar aus dem November 2011, aber ich habe ihn erst heute entdeckt: Green IT als Klimaretter? Wie man den Stromverbrauch in Rechenzentren und am Heimcomputer nachhaltig senken kann. Ein kurzer Bericht über die Green-IT Tagung auf dem 6. Nordhäuser Energieforum, auf der ich unser Green Computing Portal vorstellen durfte.
WordPress-Plugin Optimierung
Vor Weihnachten habe ich ein schönes neues Spielzeug für WordPress entdeckt: P3 – Plugin Performance Profiler. Profiler – mein Lieblingsspielzeug. Denn ohne einen vernünftigen Profiler kann man auch nicht vernünftig optimieren. Ok, der P3 ist kein super ausgefeiltes Werkzeug, aber es zeigt für alle installierten Plugins an, wie viel Zeit für deren Ausführung benötigt wurde. Und mit der Information lässt sich schon so einiges anfangen. Vor allem zeigt es nämlich welche Plugins viel zu viel unnötige Rechenzeit beanspruchen, ohne dabei wirklich etwas zu tun.
Ein schönes Beispiel dafür: Admin Management Xtended. Das Plugin erweitert einiges im Backend, arbeitet aber auch dann, wenn das Backend gar nicht angezeigt wird. Eine simple Abfrage auf is_admin hat das “Problem” erledigt (und es scheint auch noch zu funktionieren, aber wirklich getestet habe ich es noch nicht). Ein schönes Beispiel für ein schlecht geschriebenes Plugin (zumindest hinsichtlich der Performance – ansonsten ist es gut). Zu viele Plugins initialisieren immer alles und machen bei jedem Aufruf Berechnungen, Datenbankabfragen usw. – egal ob wirklich nötig oder nicht.
Ein anderes Beispiel ist der WordPress Download Monitor: Das Plugin lädt beim Initialisieren diverse Dinge aus der Datenbank vor – um den späteren Ablauf zu optimieren. An sich nicht unbedingt verkehrt, aber die Datenbankabfragen werden immer gemacht, egal ob sie wirklich benötigt werden, oder nicht. Und das kostet Zeit. Viel Zeit in diesem Fall.
Ein “Problem” das viele Plugins haben: Sie speichern jede Menge Einstellungen einzeln in der Datenbank. Empfehlenswerter (und schneller) ist es, alle Einstellungen eines Plugins als Array in einem Datenbankeintrag zu speichern (sicherlich gibt es Ausnahmen für diese Regel). Das Laden vieler Einstellungen aus der Datenbank kann sich deutlich auf die Performance auswirken (und ich habe Plugins gesehen mit zig einzeln gespeicherten Optionen gesehen, die alle diese Einstellungen beim Initialisieren in globale Variablen laden um im Folgenden nicht mehr mit get_options zu arbeiten – mal wieder ganz egal ob das Plugin wirklich ausgeführt wird, oder nicht).
Was mir aufgefallen ist, beim Versuch diverse Plugins zu optimieren, es gibt kaum vernünftige Anleitungen, wann ein Plugin genau was machen sollte. Wann sollen welche Hooks registriert werden? Wie ist der genaue Ablauf der Ausführung? Welche Empfehlungen gibt es? Gibt es Performance-Tipps? Alles was ich bisher heruasgefunden habe, musst ich mir mühsam von verschiedenen Stellen zusammensuchen. Darum arbeite ich gerade an einem Artikel darüber – um es selbst zu lernen und das gelernte irgendwo festzuhalten und ggf. so auch weiterzugeben.
Aber wie gesagt – ich arbeite noch daran. Bis dahin spielt mit dem Plugin Performance Profiler herum. Der funktioniert übrigens erst ab WordPress 3.3.
WordPress: Dynamic Links Plugin
Ich habe mir mal die “Mühe” gemacht, aus dem im letzten Post beschriebenen Code zum Verwenden von “dynamischen Links” für Bilder in WordPress-Posts ein Plugin zu machen. Die erste Version in bereits online. Wenn ich die Zeit finde, dann kommen noch Funktionen zum automatischen Ersetzen aller Links in bestehenden Posts und zum zurücksetzen der Platzhalter in den Posts dazu. Mal schauen, wann ich Zeit dazu finde.
WordPress: Statische (Bild-)URLs in Posts dynamisch anpassen
Fügt man in WordPress ein Bild in einen Post ein, dann wird dieses dort mit seiner absoluten URL eingefügt, also zum Beispiel http://www.domainname.com/wp-content/uploads/restlicher/pfad/zum/bild.jpg. Ob ganz allgemein solche absoluten URLs sinnig sind, oder “relative” Pfade (ohne http und Domain) besser sind, wird scheinbar viel diskutiert.
Dafür spricht bei WordPress unter anderem, dass die reine Verwendung relativer Pfade Probleme bei Feeds bereitet: Denn dann würde die relative angabe auf die Domain angewendet, von der aus der Feeds aufgerufen wurde – und das läuft mit Sicherheit ins Leere.
Dagegen spricht, dass Domainumzüge mit Inhalt so aufwändiger sind. Denn man muss dann in der Datenbank alle Links auf die neue Domain anpassen. Das ist besonders ärgerlich, wenn man zum Beispiel eine Seite in einer lokalen Testinstallation inklusive Inhalte vorbereitet (was ich gerade mache, weshalb ich auch auf dieses Thema gekommen bin). Oder wenn man nachträglich in den Einstellungen den Basispfad zu den Dateien ändert (um z.B. Bilder über eine Subdomain bereitszustellen – das habe ich beim GCP gemacht, um kürzere Bild-URLs zu haben, für optimierte, parallele Downloads der Bilder und damit bei den Anfragen keine Cookies mitgesendet werden).
Also: Nur relative URLs sind nicht gut, aber nur statische sind auch irgendwie unschön.
Mein momentaner Lösungsansatz: In der Datenbank in Posts den Basispfad für Downloads durch einen Platzhalter ersetzen, der dann beim Anzeigen wieder ersetzt wird. Beim Speichern einen Posts wird der Upload-Basispfad einfach durch {uploads} ersetzt. Beim Auslesen wird dann der Platzhalter wieder durch den Basispfad ersetzt. Vorteil: Die Datenbank wird kleiner, Domain-Wechsel und Änderungen am Basispfad werden dynamisch übernommen. Und da es für das Lesen der Posts aus der Datenbank verschiedene Filter gibt, ließe sich das ganze so auch noch anpassen, dass z.B. auf der Seite selbst relative Pfade verwendet werden, in Feeds aber absolute.
Hier die Quick-And-Dirty Lösung:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | function content_substitute_uploadbase ($content) { $uploads = wp_upload_dir(); $content = str_replace('href=\"'.$uploads['baseurl'], 'href=\"{uploads}', $content); $content = str_replace('src=\"'.$uploads['baseurl'], 'src=\"{uploads}', $content); return $content; } function content_set_uploadbase ($content) { $uploads = wp_upload_dir(); $content = str_replace('{uploads}', $uploads['baseurl'], $content); return $content; } add_filter('content_save_pre','content_substitute_uploadbase',99); add_filter('the_content','content_set_uploadbase',99); add_filter('the_content_rss','content_set_uploadbase',99); add_filter('the_content_feed','content_set_uploadbase',99); add_filter('the_editor_content','content_set_uploadbase',99); |
Worpdress: Slimbox2 statt Lightbox/Colorbox
Ich kann es ja nie sein lassen und muss immer wieder an der Technik des GCP herumbasteln. Zuletzt hatte ich Probleme mit WP-Minify. Genauer gesagt kamen die Probleme vom Lightbox Plus Plugin, dessen Script (Colorbox) nicht mit WP-Minify zusammen funktionieren wollte, was sich in teils seltsamen Verhalten äußerte: Unter anderem gab es Probleme, wenn die Pretty URL Option in WP-Minify aktiviert war. Warum auch immer. Einzige lösung, war das Lightbox-Skript von Wp-Minify auszuschließen. Eine Lösung, die mir nicht gefiel, auch wenn es lediglich eine zusätzliche Anfrage verursacht hat.
Also habe ich mich nach Alternativen umgesehen und bin dabei auf Slimbox2 gestoßen. Slimbox2 verwendet, genau wie Colorbox, jQuery. Allerdings ist es mit gerade mal 4KB (laut Webseite) deutlich kleiner. Eine kurze Suche hat dann auch gleich diverse WordPress-Plugins für Slimbox2 geliefert von denen ich mich für Slimbox2 with Slideshow entschieden habe. Installiert, getestet, funktioniert.
Ein wenig musste ich dann doch noch anpassen, damit die alte Funktionalität hergestellt wurde: Das Slimbox2-Plugin verwendet als Bildunterschriften die Titel der Links, das alte Lightbox-Plugin hingegen hat die Titel der img-Tags verwendet. Außerdem hat das Plugin jQuery umgebogen auf die Version 1.5.1 auf den Google-Servern. Die entsprechenden Zeilen auskommentiert, ein paar Anpassungen im Skript und alles funktioniert wie es soll und auch mit WP-Minify und Slimbox2 gibt es keine Probleme.
Statt meine Änderungen hier zu posten werde ich sie mal ins Plugin als Optionen einbauen und diese dem Autor zukommen lassen. Slimbox2 with Slideshow scheint noch recht neu zu sein und wurde erst kürzlich aktualisiert. Noch ein Pluspunkt für das Plugin.
Was auch noch auf meiner ToDo-Liste steht: Die Texte des Plugins übersetzbar machen (“Bild x von y” statt “Image x of y“) und die üblichen Next/Prev bilder durch CSS-Text zu ersetzen. Und mal schauen ob ich das Einbinden der Scripte auf Seiten beschränken kann, auf denen es auch wirklich verwendet wird. Noch ein wenig optimieren eben…
Das GCP auf dem 6. Norhäuser Energieforum
Ja, dieser Beitrag kommt zu spät, mindestens drei Tage zu spät: Vor drei Tagen fand in Nordhausen das 6. Nordhäuser Energieforum statt, mit dem Thema “Green IT – Innovationen für die Zukunft”. Warum trotzdem ein Beitrag zu einer längst gelaufenen Green-IT-Veranstaltung? Weil ich hier schon viel zu lange keinen neuen Beitrag verfasst habe und weil ich im Rahmen der Veranstaltung in einem Vortrag unser Green Computing Portal vorstellen durfte. An dieser Stelle nochmal vielen Dank an die Veranstalter für die Einladung, es war ein interessanter und spannender Tag. Mir hat’s gefallen und es war die Reise wert.
Leider lag mein Fotoapparat den ganzen Tag über im Kofferraum, also habe ich nicht mal ein paar Bilder dazu.
Bei der Heinrich-Böll-Stiftung Thüringen e.V gibt es hier ein paar weitere Informationen zum 6. Energieforum: http://greennewdeal.boellblog.org/2011/green-it-innovationen-fur-die-zukunft/
Und auf der Webseite der Fachhochschule Nordhausen gibt es den Flyer der Veranstaltung: http://www.fh-nordhausen.de/fileadmin/daten/presse/pdf/flyer_energieforum_6_10-10-11_web.pdf
WordPress-Tuning – Text-Domains nur bei Bedarf laden
Was mir wirklich Spaß macht beim Programmieren ist Optimieren – für mehr Geschwindigkeit oder weniger Speicherverbrauch. Und das macht selbstverständlich auch nicht vor WordPress halt. Deshalb habe ich mit die Tage xDebug installiert und ein wenig mit dessen Profiler WordPress genauer angeschaut.
Das erste Ergebnis, das sofort ins Auge stach: Über 25% der Ausführungszeit (beim Darstellen der Startseite vom GCP) wurde von load_textdomain verbraucht. Ein übersetztes WordPress ist also deutlich langsamer, als ein nicht übersetztes. Also habe ich mir das ganze mal genauer angesehen.
Bei jedem Durchlauf werden alle Übersetzungen geladen und allein die Standard-Übersetzungstabelle umfasst über 3000 Texte (z.B. für Deutsch in der Datei de_DE.po). Und es werden alle Übersetzungstexte jedes mal komplett geladen und geparst, egal, ob sie benötigt werden, oder nicht. Blöd dabei, dass die meisten Texte nur im Backend benötigt werden. Und installierte, mehrsprachige Plugins verschlimmern das ganze nur weiter.
Als einen ersten Schritt konnte ich einbauen, dass Text-Domains nur bei Bedarf geladen werden, also erst beim Ersten versuch einen Text aus dieser zu übersetzen. Das ganze lässt sich relativ einfach sogar als Plugin realisieren, indem man sich in den Filter override_load_textdomain einklinkt.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | class MO_onDemand extends MO { var $loaded = false; var $mofile = NULL; var $domain = NULL; function loadOnDemand () { global $l10n; if (!$this->loaded) { $mo=new MO(); if ( !$mo->import_from_file( $this->mofile ) ) return false; $l10n[$this->domain]=$mo; $this->loaded=true; return $mo; } else { return $l10n[$this->domain]; } } function translate_entry(&$entry) { $mo=$this->loadOnDemand(); return $mo->translate_entry(&$entry); } function translate($singular, $context=null) { $mo=$this->loadOnDemand(); return $mo->translate($singular, $context); } function select_plural_form($count) { $mo=$this->loadOnDemand(); return $mo->select_plural_form($count); } function get_plural_forms_count() { $mo=$this->loadOnDemand(); return $mo->get_plural_forms_count(); } function translate_plural($singular, $plural, $count, $context = null) { $mo=loadOnDemand(); return $mo->translate_plural($singular, $plural, $count, $context); } } function load_textdomain_override( $retval, $domain, $mofile ) { global $l10n; do_action( 'load_textdomain', $domain, $mofile ); $mofile = apply_filters( 'load_textdomain_mofile', $mofile, $domain ); if ( ! is_readable( $mofile ) ) return false; $mo = new MO_onDemand(); $mo->mofile=$mofile; $mo->domain=$domain; if ( isset( $l10n[$domain] ) ) $mo->merge_with( $l10n[$domain] ); $l10n[$domain] = &$mo; return true; } add_filter('override_load_textdomain', 'load_textdomain_override',10,3); |
Ein wichtiger Punkt fehlt hier noch: Die Funktion merge_with der Basisklasse Translations müsste auf jeden Fall noch überschrieben werden, so dass ggf. mehrere Dateien gemerkt werden. Die neue Klasse muss eigentlich auch nicht von MO abgeleitet werden, da sie beim ersten Zugriff auf eine Übersetzung sich selbst im globalen l10n-Array durch eine Instanz von MO ersetzt (was aus Geschwindigkeitsgründen so ist).
Allein dieses “Plugin” hat die Ausführungszeit für das Anzeigen der Startseite vom GCP (lokale Installation mit aktivem Debugger) von 9,5 auf 7,8 Sekunden beschleunigt. Nur weil die Text-Domains der Plugins nicht geladen werden (da sie auf der Startseite nicht verwendet werden). Der größte Brocken, die Default-Text-Domain ist aber noch da und braucht noch immer fast 2,5 Sekunden zum Laden.
Unprintable Blog WordPress-Plugin
Mein erstes WordPress Plugin ist fertig: Unprintable Blog. Das Plugin verhindert das Drucken der Seiten des Blogs über die Druckfunktion des Browsers (statt der angezeigten Seite wird ein Hinweis gedruckt, die Seite bitte nicht zu drucken). Als Alternative dazu können die Beiträge als automatisch generierte PDFs heruntergeladen werden, die ebenfalls nicht druckbar sind.
Die Idee dazu hatte ich, als ich vom WWF-Format gelesen hatte: Ein nicht druckbares Dokumenten-Format, dass kompatibel mit PDF ist. Also eigentlich nichts anderes, als ein geschütztes PDF, ohne öffentliches Passwort, so dass es von jedem geöffnet werden kann, bei dem das Drucken nicht erlaubt ist. Und dann mit der Dateiendung wwf gespeichert, statt mit pdf.
“Das kann ich auch” – und nach einigem Suchen konnte ich es auch: Das Plugin wp-mpdf von Florian Krauthan um eine Zeile ergänzt und schon hat es nicht druckbare PDFs erzeugt. Auch das Drucken der Webseite über den Browser lässt sich leicht “verhindern”, und zwar per CSS für das Medium print. Ein wenig Feintuning, Updates der von wp-mpdf verwendeten PHP-Bibliotheken (mPDF und GeSHi), diverser “Kleinkram” und eine komplette Überarbeitung des Admin-Interfaces inklusive Lokalisierung, und fertig war Unprintable Blog.
Ein wenig aufwändiger als es klingt war es schon, aber ich habe dabei viel neues über WordPress gelernt. Wirklich selbst gemacht ist es also nicht, aber es steckt schon einiges an Arbeit drin. Und das erste Update für das Plugin (auf Green Computing Portal ist es übrigens schon aktiv – hier muss ich es noch hochladen) ist auch schon in Arbeit.
WordPress-Plugins mit Hilfe versehen
Usability kommt bei vielen WordPress-Plugins leider zu kurz, dabei bietet WordPress diverse Funktionen die dabei helfen. Unter anderem kann man sein eigenes Plugin mit einer Kontext-Hilfe versehen. Damit ist der kleine Reiter “Hilfe” gemeint, der im Backend auf jeder Seite rechts oben zu sehen ist. Relativ einfach lässt sich hier ein eigener Hilfetext einbauen. Die Funktion dafür ist aber nicht wirklich gut dokumentiert, zumindest musste ich länger suchen, bis ich eine mir genehme Lösung gefunden hatte.
Für das Anpassen des Hilfetextes bietet WordPress die Action contextual_help. Die einfachste Variante einen eigenen Text einzubinden dürfte die folgende sein:
1 2 3 4 5 6 7 8 9 10 11 | function my_contextual_help($text) { $screen = $_GET['page'];if ($screen == 'my_plugin') { $text = '<h5>Hilfe zum Plugin</h5>'; $text .= '<p>Jede Menge Hilfetext und ganz viel Beschreibung, aber auch nicht zu viel, eben so viel, dass es reicht.</p>'; $text .= <p>'Vielleicht auch noch ein <a href="#">Link irgendwo hin</a>.</p>'; } return $text; } add_action('contextual_help', 'my_contextual_help'); |
Zunächst wird überprüft, ob es sich bei der aufgerufenen Seite um die Seite des eigenen Plugins handelt. Nur dann wird der Hilfetext in $text geschrieben und zurückgegeben. Ansonsten wird $text unverändert (übergeben wir der Standard-Hilfetext von WordPress – Links zum Support-Forum und zu WordPress.org) gelassen und zurückgegeben. (continue reading…)
Delphi XMLDoc Viewer
Wie vor einiger Zeit bereits angekündigt (XML Documentation mit Delphi) habe ich meinen eigenen kleinen Viewer für Delphis XML-Dokumentation gebastelt (oder vielmehr bin ich noch dabei, aber den aktuellen Stand kann man schon als benutzbar bezeichnen). Hier ist er also, der Delphi XMLDoc Viewer in der Version 0.1.

