Um es gleich vorweg zu nehmen: So etwas wie „Child Plugins“ gibt es nicht đ Wieso also komme ich auf diesen komischen Titel? Den AnstoĂ zu meiner neuen kleinen Artikelreihe gab ein Tweet von Phillip Roth:
Den meisten WordPress Entwicklern ist das Prinzip von Child Themes ein Begriff und sie wissen auch, wie man damit eigene Themes erstellen kann, die bei einem Update des Parent Themes nicht verloren gehen.
GrĂŒnde fĂŒr Child Plugins
Wieso also möchten Phillip und viele andere auch so etwas wie Child Plugins haben? Der Grund ist hier wohl genau der gleiche wie bei Themes: Bei einem Update sollen Ănderungen nicht verloren gehen.
Genau wie beim Core und den Themes sollte man niemals den Code eines Plugins verÀndern. Was ist aber, wenn man die FunktionalitÀt eines Plugins dennoch verÀndern möchte? Hierzu gibt es leider keine allgemeine Lösung. Daher möchte ich in den nÀchsten Wochen zeigen, welche Möglichkeiten zur Anpassung uns viele Plugins bieten, wie man diese als Entwickler nutzen kann und was man selbst als Plugin-Autor vielleicht bedenken sollte, um die eigenen Plugins anpassbar zu machen. Und beginnen möchte ich mit der wohl einfachsten Möglichkeit: der Definition von Konstanten.
Definition von Konstanten
Zuerst einmal sollten wir klĂ€ren, was genau eine Konstante ist. Wie der Name schon vermuten lĂ€sst ist eine Konstant: „konstant“, „gleichbleibend“, „feststehend“, „unverĂ€nderlich“. Wenn eine Konstante also nicht verĂ€ndert werden kann, wie kann ich diese dann anpassen? Sehen wir uns hierzu einen typischen Codeschnippsel aus der wp-config.php
Datei an, den wohl jeder schon einmal gesehen hat:
/** Absolute path to the WordPress directory. */ if ( !defined('ABSPATH') ) define('ABSPATH', dirname(__FILE__) . '/');
Mit der Funktion defined()
wird zuerst geprĂŒft, ob die Konstante ABSPATH
bereits definiert wurde. Ist dies nicht der Fall, dann wird sie in der nĂ€chsten Zeile ĂŒber die Funktion define()
definiert und mit einem Wert belegt.
Konstanten nutzen
In beiden Funktion wird der Name der Konstante in AnfĂŒhrungsstriche gesetzt (einfache oder doppelte), es handelt sich also um einen String. Nutzt man diese Konstante allerdings im Code, dann muss sie ohne AnfĂŒhrungsstriche verwendet werden. Hier ein Beispiel aus dem Core, in dem die Konstante ABSPATH
verwendet wird:
include( ABSPATH . 'wp-admin/edit-form-advanced.php' ); include( ABSPATH . 'wp-admin/admin-footer.php' );
Diese Zeilen stammen aus der Datei wp-admin/post-new.php
, also dem PHP-Skript, das beim Erstellen eines neuen Beitrags verwendet wird. Die Konstante speichert dabei den Pfad bis zum Root-Verzeichnis der WordPress-Installation und vereinfacht die Pfadangaben zur Einbindung von weitern Dateien.
Konstanten in Plugins
Nachdem wir nun gesehen haben, wie Konstanten im WordPress Core verwendet werden, wollen wir uns ansehen, wie wir mit deren Hilfe auch die Funktionsweise von Plugins beeinflussen können. Hierzu mal ein sehr einfaches Beispiel anhand des beliebten Kontaktformular-Plugin Contact Form 7. Mit dieser einzelnen Zeile Code können wir beispielsweise den Versand des Formulars per AJAX-Request deaktivieren:
define( 'WPCF7_LOAD_JS', false );
Diese Codezeile könnten wir dann theoretisch entweder in die functions.php
Datei unseres Child Themes einfĂŒgen oder noch besser in ein Plugin einfĂŒgen und darĂŒber installieren.
Die Frage ist nun, wie man herausfinden kann, welche Konstanten ein Plugin anbietet und wie man diese verwenden kann. Hier muss man entweder im Quellcode des Plugins nachsehen oder aber darauf hoffen, dass diese gut dokumentiert sind. Im Fall von Contact Form 7 stehen diese Konstanten leider nicht auf den Seiten im Plugin-Repository und auch auf der offiziellen Dokumentation ist die Ăbersichtsseite ein wenig unter Docs -> Tips -> Controlling Behavior by Setting Constants versteckt.
Fallstricke bei Konstanten
Die Verwendung von Konstanten hat ein groĂes Problem: Diese sind „konstant“. Einmal definiert kann man ihren Wert, anders als bei normalen PHP-Variablen, nicht mehr verĂ€ndern. Meistens werden Konstanten von Plugin-Entwicklern eingesetzt, weil sie „global“ sind. Um sie in einer Funktion verwenden zu können muss man sie also nicht in die Funktion bringen.
Probleme bei der Ladereihenfolge
Im Fall von Contact Form 7 bestehen nun mehrere Probleme, die eine Verwendung erschweren. Zum einem werden die Variablen direkt definiert, sobald das Plugin geladen wird. Besser wĂ€re es gewesen, wenn dies innerhalb eines „Initialisierungs-Hooks“ passiert. Erstellt man also z.B. ein Plugin, dass durch die alphabetische Ladereihenfolge nach dem Contact Form 7 Plugin geladen wird, dann kann man die Konstante nicht mehr verĂ€ndern, da sie bereits definiert wurde. Aus dem gleichen Grund scheitert auch die Definition im Child Theme, da dieses erst nach dem Laden alles Plugins geladen wird.
Keine Möglichkeit zur VerÀnderung
Wie schon erwĂ€hnt ist es nicht möglich, den Wert einer Konstanten zu Ă€ndern, wenn sie einmal definiert ist. Hat man also z.B. eine Multisite-Installation und möchte z.B. die AJAX-FunktionalitĂ€t von Contact Form 7 nur fĂŒr bestimmte Seiten deaktivieren, dann kann man dies nicht einfach in der wp-config.php
definieren, denn es wÀre dann in der Unterseite nicht mehr möglich diesen Wert zu Àndern. Man muss hier als ein Plugin mit passendem Namen schreiben, in diesem Plugin die aktuelle Unterseite abfragen und dann entsprechend die Konstante definieren. Das ist also nicht gerade einfach umzusetzen.
Erschwert das Testen von Plugins
Wenn man sein Plugin zum Beispiel mit Unittest testen lĂ€sst, so ist es nicht so einfach, diese bei der Verwendung von Konstanten zu testen, denn diese sind ja nicht verĂ€nderbar und man kann daher nicht einfach testen, was bei einer anderen Definition der Konstanten passiert. Es gibt zwar einige AnsĂ€tze, wie man Konstanten „mocken“ kann, aber das verkompliziert doch die Tests erheblich.
Fazit
Eigentlich hatte ich ja vor, in jedem Artikel eine Anleitung fĂŒr Plugin-Autoren zu geben, wie sie die vorgestellte Technik in ihre Plugins einbauen können. Aber da man von der Verwendung von Konstanten (oder globalen Variablen im Allgemeinen) absehen sollte, werde ich das dieses Mal nicht tun đ
Wenn ihr aber die Funktionsweise eines Plugins verÀndern wollt und dieses eine passende Konstante anbietet, dann hilft euch dieser Artikel hoffentlich dabei zu verstehen, wie dies möglich ist, aber auch, welche Konsequenzen das mit sich bringen könnte (Stichwort: Multisite).
Im nĂ€chsten Artikel werde ich mich vermutlich um das groĂe Thema Hooks (Actions und Filters) kĂŒmmern.
Weitere Artikel zu Themenreihe
Dies ist der erste Teil der Themenreihe „Child Plugins“. Hier findest du die anderen BeitrĂ€ge:
Hallo Bernhard,
auch bei mir gibt es immer wieder Ănderungen bei einzelnen Plugins. Entweder weil ich W3C Fehler beheben will oder weil ich die eine oder andere Funktion anders haben will. Meine Ănderungen beziehen sich da also eher auf JS und CSS Dateien.
Ich verwende meine functions.php, um diese Ănderungen dann einzubinden:
Das ist zwar kein „Child Plugin“ aber hilft vielleicht dem Einen oder Anderen wenn solche Ănderungen bei CSS oder JS anstehen.
Gruss Harry
Das ist schon eine sehr spezielle Anpassung. Aber was du hier machst (wenn auch etwas sehr kompliziert), werde ich vermutlich im nĂ€chsten Artikel beschreiben. Denn die optimale Lösung fĂŒr so etwas ist ja die Verwendung von Hooks.
So speziell finde ich das gar nicht:)
Aber warum ist das kompliziert? Das wĂŒrde mich schon interessieren, wenn ich das einfacher machen kann:)
Vermutlich hat das Plugin eine Funktion, die die JS und CSS Dateien einbindet. Denn du diese ĂŒber ein
remove_action
deaktivierst, kannst du anschlieĂend deine eigenen Dateien einbinden.Ich verwende das so eigentlich bei jedem Plugin wo ich solche Ănderungen habe. Und das sind einige;)
Ist „remove_action“ denn da so viel vorteilhafter wie „wp_deregister_style/wp_dequeue_style bzw script“?
Viele Plugins binden die Styles und Script ja via „wp_enqueue_…“ ein.
Es ist auf jeden Fall sehr viel kĂŒrzer. Du könntest z.B. wie folg einfach das gesamte Standard JS/CSS rauswerfen:
Aber das Plugin ist wirklich etwas unsauber geschrieben, da ist deine Variante vielleicht ein wenig einfacher. Nur musst du nicht deregister und dequeue verwenden, letzteres reicht. Oder aber du ĂŒberschreibst einfach den Handle mit deinem eigenen. Beim CSS könntest du auch die Anpassungen im Child Theme CSS vornehmen, wenn es nicht zu viele sind. Und beim JS gibt es vielleicht Ansatzpunkte. Aber ich kenne natĂŒrlich deinen Problemfall mit dem Plugin nicht, um das beurteilen zu können.
Hi Bernhard,
ich möchte ja nicht immer das gesamte JS oder CSS rauswerfen, es sind oft nur einzelne Dateien. Na das ist aber nicht das einzige Plugin, dass so „unsauber“ geschrieben ist;)
Ah ok, wenn letzteres reicht oder das Ăberschreiben reicht, dann teste ich das nochmal. Bei irgendeinem Plugin klappte das nicht, daher hatte ich das dann fĂŒr alle, wo ich andere Dateien einbinden möchte, so ĂŒbernommen.
Doch es sind viele:) Ich mag einfach sauberen CSS-Code, ebenso HTML nach W3C, daher rĂŒhren meine Ănderungen. Eigentlich ist das natĂŒrlich relativ unwichtig aber ich wills halt so;) Und bei JS ist es dann die eine oder andere Funktion die ich hinzufĂŒge oder einfach AbĂ€ndern möchte. Also echte ProblemfĂ€lle sind das da nicht;)
Ich danke dir soweit fĂŒr die Anregungen!
Gruss Harry
Verstehe, es geht dir um sauberen Code. Dann ist wohl das Ăberschreiben einfacher.
Noch besser wĂ€re es natĂŒrlich, wenn du dem Plugin-Autor einfach eine verbesserte Variante zuschickst, dann musst du sie in Zukunft nicht mehr ĂŒberschreiben đ
Das mache ich auch:) Besonders wenn der PHP-Code zu solchen Fehler fĂŒhrt weil zb das alt-Tag fehlt oder was auch immer;)
Es dauert aber bis so etwas dann ĂŒbernommen wird;)
Bei Jetpack Statistik, hat es echt lange gedauert bis diese smiley-pixel-grafik endlich width und height bekommen hatte;) GTMetrix hatte da „gemeckert“.
Und da bin ich denen sicherlich schon auf die Nerven gefallen. Aber das war auch so ein eher unwichtiger „Fehler“ der wohl niemandem aufgefallen war. Aber letztlich wurde es doch gemacht;)
Wegen meines Pagespeed, lade ich via WP-Cron alle externen Scripte(auch analytics.js) auf meinen Server und binde diese dann ein(wegen der Cachingzeit). So konnte ich im Jetpackscript das selbst mit replace reinschreiben;) Aber es ist immer schon, wenn solche Sachen dann wegfallen.
Dann noch was Anderes: Beim erneuten Kommentieren hier, fĂ€llt mir auf, dass der Haken bei „Benachrichtige mich ĂŒber nachfolgende Kommentare via E-Mail.“ nicht gesetzt ist. Ist das ein „Bug“ oder soll das so sein? Und wenn es so sein soll, muss ich dann den Haken immer wieder setzen um eine Mail bei einem neuen Kommentar zu bekommen? Ich denke das könnte den einen oder anderen verwirren. WĂ€re ja auch blöd wenn man beim ersten Mal den Haken gesetzt hat und beim nĂ€chsten Mal nicht drauf achtet, falls er wieder gesetzt werden muss, und man dann keine Mails mehr darĂŒber bekommt;)
Achso, du hast ja auch Gravatare in deinen Kommentaren. Vielleicht ist da ja mein Plugin was fĂŒr dich(wo ich eben ĂŒber Pagespeed geschrieben habe fiel mir das auf), damit diese Bildchen nicht von einem anderen Server kommen mĂŒssen;)
https://wordpress.org/plugins/harrys-gravatar-cache/
Konstanten? Unfug. Hooks, nix anderes. End of story đ
.. besonders, wenn du so Sachen wie etwa Premium-Plugins fĂŒr Themes verzapft, bei denen letztere aber weiterhin frei und quelloffen verfĂŒgbar sein sollen.
cu, w0lf.
Hallo Wolf,
ich habe ja in meinem Beitrag ausfĂŒhrlich erklĂ€rt, was die Probleme mit Konstanten sind und daher auch keine Anleitung geliefert, wie man diese in eigenen Plugins einsetzt.
Dennoch gibt es eben viele Plugins und Themes, die diese einsetzen und ich wollte eben zeigen, wie man sie verwenden kann, um die Funktionsweise von Plugins zu beeinflussen.
Ich denke mein nĂ€chster Beitrag in der Reihe wird dir besser gefallen. Dreimal darfst du raten, worum es dann gehen wird đ
SpĂ€testens wenn man mit der Ladereihenfolge auf die Nase fliegt, sollte klar sein: Gehen tut viel, aber der Aufwand dafĂŒr lohnt sich nicht. Die logische Konsequenz daraus sollte sein: Entweder mit Filter und Action Hooks arbeiten, oder mit Globals. Wobei rein technisch ja ersteres auf letzterem fuĂt, nur halt wesentlich komfortabler zu benutzen ist đ
cu, w0lf.
Nachtrag: Und ja, den Hinweis auf den Nachfolgeartikel habe ich gesehen đ
Mit Hooks musst du letzlich auch arbeiten, wenn du ein Theme-Framework vernĂŒnftig fĂŒr Child Themes nutzbar machen willst. WĂŒrde daher auch bei „Child Plugins“ als generelle Bezeichnung bleiben đ
cu, w0lf.
Hallo,
Mein Ansinnnen: ich habe ein Theme, das Leeway heiĂt. Ich baue gerade eine Kochrezepte-Datenbank auf. Es passiert nun, dass ich eine riesen Lange von BeitrĂ€gen habe, die ich StĂŒck fĂŒr StĂŒck in das MenĂŒ einfĂŒgen muss. Von selbst macht er da nichts. Egal ob ich die Katgegorien vor oder nachher anlege. Das mit den Konstanten hat mich da auf die Idee gebracht. Gibt es da eine Möglichkeit, wordpress anzuregen, das selbstĂ€ndig zu machen. Jedesmal in das MenĂŒ zu gehen, den Beitrag aussuchen und in die Reihe der Kategorien einordnen ist öde.
Vielleicht nicht der richtige weg hier, aber ich habe in den Foren nichts gefunden und es schreibt auch keiner zurĂŒck. Danke
Sehr hilfreicher Artikel, vielen Dank! Ich habe mich auch schon oft gefragt, warum es nicht so etwas wie Child Plugins gibt ? Bei nahezu jedem dritten Kundenprojekt mĂŒssen wir Plugins anpassen und arbeiten hier auch bevorzugt mit Hooks. Das mit den Konstanten ist aber mal eine nette Idee, werde ich demnĂ€chst mal ausprobieren bei nicht allzu komplexen Anpassungen.