Month: May 2015

WordPress und Abwärtskompatibilität

Wenn man Entwickler nach den Gründen fragt, weshalb WordPress um so viel erfolgreicher ist als andere Content Management Systeme wie Drupal, Joomla und so weiter, so fällt unweigerlich der Begriff der Abwärtskompatibilität. Seit den Anfängen von WordPress haben die Entwickler darauf geachtet, dass die Funktionalität von einer Version zur nächsten nicht zusammenbricht.

Ein Beispiel dafür sind veraltete Funktionen: Funktionen, welche in einer Version nicht mehr benötigt werden, werden nicht einfach aus WordPress entfernt sondern über mehrere Versionen als veraltet markiert und weiter mitgeführt, bis man sie schließlich entfernt. Entwickler können sich auf dieser Seite lange im voraus informieren, um diese Funktionen in den eigenen Plugins rechtzeitig zu ersetzen. Und auch mit WP_DEBUG auf true werden sie darüber informiert.

Ein weiteres Beispiel ist die Datenbank. So findet die Tabelle wp_links im WordPress Core zwar keine Anwendung mehr, wird jedoch weiterhin mitgeführt. Es mag zunächst simpel klingen: WordPress benötigt die Tabelle in der aktuellen Version nicht mehr, also wird sie rausgeschmissen. Da jedoch niemand weiß, was einzelne Installationen in dieser Tabelle womöglich für Informationen gespeichert haben und wie diese genutzt werden, würde ein solches Vorgehen drastische Konsequenzen haben. Würde man die Tabelle einfach rausschmeißen, würden Administratoren so quasi Inhalte verlieren, welche sie mühsam aufgebaut haben. Statt also aus Gründen einer konsistenten Struktur diese Tabelle zu entfernen führt WordPress sie weiter mit.

Damit zusammenhängend: Hat sich schon einmal jemand gefragt, warum die Post ID in der Datenbanktabelle wp_term_relationship object_id heißt und nicht konsistent wie in allen anderen Tabellen auch post_id? Auch Spalten aus der wp_links können hier verknüpft sein, weshalb man sich für object_id entschied, da es sich nicht nur um Post IDs handelt. Doch, obwohl es sich mittlerweile eigentlich nur noch um Post IDs handelt wird die Spalte nach wie vor object_id genannt. Warum? Wie viele Plugins gibt es, die – auch wenn sie nur die Terms eines Posts oder ähnliches abfragen – einen direkten SQL-Zugriff unternehmen und in ihrer Syntax object_id verwenden? Alle diese Plugins würden zusammenbrechen. WordPress hat eine Geschichte und man kann sie in diesen Inkonsistenzen lesen.

Auch innerhalb überarbeiteter Funktion finden sich Beispiele, wie WordPress diese Philosophie umsetzt. Betrachten wir beispielsweise den zweiten Parameter von load_plugin_textdomain(), welcher immer mit false angegeben wird. Bis zur Version 2.7 wurde hier der relative Pfad angegeben, in welchem Verzeichnis sich die Übersetzungsdateien befinden. Da man heute nicht mehr den relativen Pfad ausgehend von ABSPATH, sondern ausgehend von WP_PLUGIN_DIR bestimmt, ist dieser Parameter veraltet und der dritte Parameter übergibt den relativen Pfad. Dennoch wird der Parameter weiter mitgeführt und muss von Entwicklern standardmäßig mit false übergeben werden. Der Grund dafür ist einfach: Ältere Plugins verwenden diesen Parameter vielleicht noch und würde man ihn entfernen würden diese Plugins nicht mehr funktionieren.

Aus Anwendersicht mag sich das Ganze etwas anders darstellen. Mit jedem Update fluten die Foren mit Fragen wie “Habe gerade auf WordPress XY aktualisiert und komme nicht mehr in den Admin/sehe keine Bilder mehr/die Seite ist nicht mehr erreichbar”. Alle diese Fragen zeigen zwei Dinge:

  1. Wie wichtig Abwärtskompatibilität ist und
  2. wie schwierig es tatsächlich ist, diese in einer Umgebung wie WordPress zu realisieren.

Unter Entwicklern ist Abwärtskompatibilität hingegen ein zweischneidiges Schwert, denn es bläst den Code – für manche unverhältnismäßig – auf. Bedenkt man jedoch die Debatte um Sicherheitslücken und die Notwendigkeit, das System immer auf dem aktuellsten Stand zu halten kommen die meisten zu dem Schluss: an Abwärtskompatibilität führt kein Weg vorbei. Alles andere würde gerade für kleine Blog- und Shopbetreiber zu einem unverhältnismäßig höherem Aufwand führen oder aber – bedenkt man, dass ca. 20 Prozent der Internetseiten auf WordPress laufen – zu einem unsichereren Internet.

Aber: Ist Abwärtskompatibilität nur ein Thema für die Core-Entwickler oder betrifft es auch uns, die Theme- und Pluginentwickler? Natürlich betrifft das auch uns. Auch das Aktualisieren von Plugins muss ein sicherer Vorgang sein, bei dem nach Möglichkeit nichts kaputt geht.* In seiner Rede auf der Loopconf 2015 spricht Pippin Williamson, Autor von Easy Digital Downloads, deshalb ausführlich über Abwärtskompatibilität und was sie für uns Entwickler bedeutet. Er zeigt auch an Beispielen, wie schwierig es manchmal ist, diese zu gewährleisten und warum wir dennoch unser Bestes geben sollten. Ein sehr guter Vortrag, der jedem WordPress Entwickler ans Herz gelegt sei:

Dieses Video ansehen auf YouTube.

*) Ich muss mich hier allerdings noch an der eigenen Nase packen und dies für eines meiner Plugins tatsächlich auch umsetzen. Doch das mach ich jetzt nicht hier in diesem Post. Er dient mir auch als Mahnung 🙂

BuddyPress Desktop Notification

Mein neustes Plugin wurde gerade auf wordpress.org veröffentlicht: “BuddyPress Desktop Notification“. Wenn Du eine BuddyPress Community betreibst, kannst Du dieses Plugin nutzen, um neue Nachrichten, Aktivitäten oder Freundschaftsanfragen von Nutzern anzeigen zu lassen.

BuddyPress Desktop Notification
Eine Benachrichtigung mit BuddyPress Desktop Notification

Wie das funktioniert? Nachdem der Nutzer sich eingeloggt hat fragt ihn der Browser, ob er Desktop Notifications zulassen möchte. Diese funktionieren mit den meisten modernen Browsern (eine aktuelle Übersicht gibt es hier). Während normale Benachrichtigungsplugins einfach ein kleines Popup oder etwas ähnliches aufleuchten lassen, werden Desktop Notifikationen sogar angezeigt, während der Browser minimiert ist:

Desktop notification works also with minimized browsers
Desktop Notification funktionieren auch, wenn der Browser minimiert ist

Es ist ein ziemlich kleines Plugin, kann jedoch relativ viel Traffic verursachen, da jeder eingeloggte Benutzer, welcher Notifikationen zulässt, alle fünf Sekunden eine Ajax Anfrage startet, ob es Neuigkeiten gibt. Ich habe mich dazu entschieden, das Plugin über Filter konfigurierbar zu machen, da ich – um ehrlich zu sein – kein besonders großer Fan überfrachteter Admin Menüs bin. Wenn das Plugin also zu viel Traffic verursacht, kann man das Request Intervall mit Hilfe von PHP vergrößern:

Weitere Informationen zu BuddyPress Desktop Notification finden sich auf der Webseite.

Vier Wege, die Adminbar in WordPress auszublenden

Die Standardeinstellung in WordPress zeigt für eingeloggte Benutzer die Adminbar oberhalb der Webseite an. Doch nicht immer will man diese anzeigen. Manchmal zerstört sie das Layout einer Seite, oder aber man möchte bestimmte Benutzergruppen die Adminbar nicht anzeigen.

Es gibt verschiedene Wege, die Adminbar auszuschalten. Dazu gehört natürlich als erstes die Möglichkeit, den entsprechenden Haken für einen Benutzer im Admin herauszunehmen.

Die Adminbar kann im Admin für bestimmte User abgeschaltet werden.
Die Adminbar kann im Admin für bestimmte User abgeschaltet werden.

Wenn es sich nur um ein, zwei Benutzer handelt, bei denen man dies machen möchte, so ist dies sicherlich der schnellste Weg. Unangenehmer wird es schon, wenn es sich um einige dutzend User handelt oder wenn man bei Neuanmeldungen diese Prozedur jedes Mal händisch durchführen muss.

Interessant ist deshalb, wo diese Information eigentlich gespeichert wird. Dabei handelt es sich um eine Metaangabe von Benutzern, welche in der wp_usermeta-Tabelle der Datenbank abgelegt wird. Der entsprechende Schlüssel, unter welchem diese Einstellung gespeichert wird lautet 'show_admin_bar_front'. Mit dem Wert 'true' wird die Leiste angezeigt, der Wert 'false' zeigt die Adminleiste hingegen nicht an. So könnte man beispielsweise während des Registrierungsprozesses den Wert auf 'false' setzen:

Doch vielleicht möchte man die Toolbar auch nur auf bestimmten Sektionen der Seite verbergen. Verantwortlich für die Darstellung der Adminleiste sind die Funktionen _wp_admin_bar_init() und wp_admin_bar_render() in der Datei wp-includes/admin-bar.php. Bevor diese allerdings die Anzeige veranlassen, prüfen sie zunächst mit Hilfe von is_admin_bar_showing(), ob die Bar angezeigt werden soll. Auch diese Funktion findet sich in der admin-bar.php. is_admin_bar_showing() gibt lediglich einen Boolean zurück, ob die Leiste angezeigt werden soll. Mit Hilfe des Filters 'show_admin_bar' kann man dabei in die Ausgabe der Bar eingreifen. So könnte man WordPress veranlassen, die Ausgabe auf Blogbeiträgen zu verhindern:

Natürlich bleibt auch noch die Möglichkeit, die Anzeige einfach mit CSS zu unterbinden. Die Adminbar verfügt über die ID '#adminbar', welche man einfach ausblenden kann:

#adminbar{ display: none; }

Doch damit ist das ursprüngliche Layout noch nicht komplett wieder hergestellt. Denn mit Hilfe von margin schafft WordPress Platz für die Admin Bar, indem das gesamte HTML-Element 32 Pixel nach unten verschoben wird. Da dies alles in der 'wp_head'-Aktion geschieht müssen die eigenen Definitionen später geladen werden. Eine Option wäre deshalb, sich in die 'wp_footer'-Aktion einzuklinken und auch das HTML-Element wieder nach oben zu schieben. Zu beachten ist dabei, dass WordPress hier mit !important arbeitet, was wir dann schließlich auch machen müssen:

Man sieht also, es gibt viele Wege, die Adminbar abzuschalten. Je nachdem, welche Anforderungen an die Anzeige bestehen, bietet sich der eine oder aber der andere Weg an.

Wähle das Headerbild abhängig von der Seite

Mit dem WordPress Customizer hielt ein sehr schönes Feature Einzug in WordPress: Das Headerbild. Wenn ein Theme Headerbilder mit add_theme_support() unterstützt kann der Administrator hier selbst ein solches Bild auswählen. Jetzt hatte ich gerade eine interessante Frage in einem Forum gelesen:

Kann mir bitte jemand sagen, ob und wie es möglich ist im Theme Twenty Eleven (2.1) ein Headerbild für jede Seite zu erstellen?

Ich fand die Frage ganz interessant, weil es dafür sicherlich eine hübsche Filterfunktion geben würde, die man hier einsetzen kann. Also habe ich ein wenig gestöbert. Mit get_header_image(), lokalisiert in der wp-includes/theme.php wird das Kopfbild ausgegeben. Diese Funktion greift dazu natürlich auf die get_theme_mod() zurück, welche sich in der gleichen Datei befindet. Der Name, der dabei erwartet wird ist “header_image”.

Die get_theme_mod() wiederum filtert ihre Ausgabe über den Filter “theme_mod_{name}”. Für das Bild im Header also über den Filter “theme_mod_header_image”. Und damit ist die Sache dann eigentlich auch schon abgeschlossen. Wir schreiben uns eine kleine Funktion, welche das Headerimage filtert. Diese Funktion prüft mit is_singular() zunächst, ob man sich auch auf einer (Beitrags-)Seite befindet. Wenn dem so ist wird geprüft, ob die aktuelle Seite über das benutzerdefinierte Feld “current-background” verfügt. Ist dort eine URL zu einem Bild enthalten, so wird diese URL ausgegeben. In allen anderen Fällen wird das Standardbild, welches über den Customizer festgelegt wurde, ausgegeben:

Zusätzliche Links auf der Plugin Übersichtsseite unterbringen Teil 2

Vor einigen Tagen hatte ich schon einen Artikel verfasst, wie man zusätzliche Links für das eigene Plugin mit Hilfe von plugin_action_links auf der Pluginübersichtsseite unterbringt. Nun bin ich gestern wieder über das Plugin “Cleaner Plugin Installer” gestolpert und habe gesehen, dass David für sein Plugin auch weitere Links unterhalb der Plugin Beschreibung unterbringt.

Cleaner Plugin Installer hat zusaetzliche Links unter der Beschreibung
Unter der Beschreibung von David Deckers Plugin finden sich weitere Links.

Normalerweise finden sich in dieser Zeile ja nur die Versionsnummer, ein Link zur Autorenseite sowie ein Link zu weiteren Details für das Plugin. Wie man sieht hat der Pluginautor hier jedoch noch Links zur FAQ, zum Support und noch weitere Links untergebracht.

Wie hat er das gemacht? Die untere Zeile wird über den Filter plugin_row_meta gefiltert. Die Zeile besteht aus verschiedenen Elementen, welche der Filter als Array an die Funktion übergibt. Im Gegensatz zu dem plugin_action_links, welcher auf jedes Plugin speziell eingestellt werden muss, handelt es sich hier um einen allgemeinen Filter. Das heißt: Wir müssen prüfen, ob die derzeitige Ausführung des Filters für unser Plugin erfolgt oder aber für andere, da wir unsere zusätzlichen Links nur für unser Plugin anzeigen möchten. Neben dem Array aus den Elementen wird als zweiter Parameter dabei der Name der Plugin-Datei übergeben. Dies können wir mit Hilfe von plugin_basename( __FILE__ ) überprüfen.

Der Code, um auf diese Reihe zuzugreifen und ein weiteres Element hinzuzufügen könnte also wie folgt aussehen: