WP Plugins Part 1: Aufbau der Main Datei

WP Plugins Part 1: Aufbau der Main Datei
Dieser Artikel ist der erste in der Reihe zum Aufbau einer eigenen Boilerplate. Mit dieser kann man dann eigene Plugins erstellen, die alle möglichen Funktionen enthalten.

Inhaltsverzeichnis

Einleitung

Sei Willkommen am Beginn der Reihe für den Aufbau einer Boilerplate für WordPress Plugins. Eine Boilerplate ist allgemein eine grundlegende Struktur von Code, die man immer wieder benutzen kann. Und genau so etwas ist überaus praktisch, wenn man verschiedenste Plugins entwickeln möchte.

Dabei werden wir uns jeden Schritt, den man gehen muss genauer anschauen. Am Ende dieser Reihe habt ihr dann ein Plugin welches sich in WordPress installieren & aktivieren lässt. Das aber noch keinerlei nutzbringende Funktion mit sich führt. Da all diese nutzbringenden Funktionen wieder eine Spezialisierung darstellen.

Nach diesen kurzen einleitenden Worten starten wir direkt in unser Thema. Was macht so ein Plugin eigentlich aus?

Die Plugin-Datei

Die Plugin-Datei wie ich sie gerne immer nenne, ist die Datei die von WordPress bei einem Plugin zu allererst angesprochen wird. Und in der die gesamte Funktionalität zusammenläuft.

Diese Datei ist immer eine .php – Datei. Wenn du dich fragst wo der Unterschied zu einer .html – Datei tritt bevor du an diesem Punkt weitermachst nochmal einen Schritt zurück. Denn bevor du mit der Entwicklung deines eigenen Plugins beginnst, solltest du einige wichtige Grundlagen verinnerlicht haben.

Gut, wir sind soweit. Beginnen wir mit der Erstellung unseres Plugins. Da es eine Boilerplate werden soll. Nenne ich es hier boilerplate-master. Also erstellen wir nun in unserem Projektordner folgendes.

  • Einen Ordner mit dem Namen boilerplate-master
  • Eine PHP-Datei in dem grade erstellten Ordner mit dem Namen boilerplate-master.php

Kommen wir jetzt zum ersten Teil dieser PHP-Datei. Denn der ist von WordPress mehr oder weniger vorgegeben. Hier werden wichtige Daten für WordPress abgelegt, die geparst werden. Damit erhält das CMS wichtige Informationen wie Version, Name, Beschreibung & Autor des Plugins.

Kommentar-Kopf der Datei

/*
Plugin Name: Plugin Boilerplate
Plugin URI: https://heinsen-it.de/
Description: Vorlage für unsere Plugins
Author: Heinsen-IT
Version: 0.0.0.0
Letztes Update: 2025-02-01 20:00:00
Author URI: https://heinsen-it.de/
MINIMAL WP: 6.4.0
MINIMAL PHP: 8.2.0
Tested WP: 6.7.1
*/

Gehen wir es der Reihe nach einmal durch. Der Plugin Name ist frei wählbar, sollte aber in aller Regel mit dem Namen deines gewählten Dateinamens und Plugins übereinstimmen. Hier gibt es aber keine Vorgaben wegen Leerzeichen oder ähnlichem.

Bei der Plugin URI kann eine Webseite eingetragen werden, im besten Fall eure eigene, auf der ihr euer Plugin bewerbt.

In der Description solltet ihr eine sehr kurze und prägnante Formulierung für euer Plugin finden und diese dort hinterlegen. Was macht dein Plugin aus?

Der Author ist glaube ich selbst erklärend. Wenn ihr ein Plugin selber schreibt, seid ihr der Autor und tragt dort euren Namen oder euer Pseudonym oder ähnliches ein.

Wichtiger ist nun schon die Version. Bei der Version handelt es sich um eine fortlaufende Nummer. Die jeweils durch einen Punkt getrennt ist. Ich habe hier eine vierstellige Versionsnummer. Mit 3 Stellen z.B. 0.0.0 würde es auch gehen, genauso mit 2 Stellen. Jede höhere Version ist ein Upgrade eures Plugins und hilft dabei WordPress erkennen zu lassen, dass ein verbessertes Paket vorliegt.

Wofür der Datumsstempel bei Letztes Update gedacht ist, könnt ihr euch an dieser Stelle vermutlich denken. Das ist die Information von wann die letzten Änderungen am Plugin stammen. Damit erhalten mögliche User eures Plugins eine Abschätzung wie aktuell das Programm noch ist.

Die Author URI lasse ich mit weiteren Erklärungen mal weg, da sie nicht zwingend relevant ist. Bei MINIMAL WP wird eine Versionsnumer von WordPress angegeben. Die minimal benötigt wird, um das Plugin laufen zu lassen. Hierbei handelt es sich um eine Empfehlung deinerseits, was du noch für vertretbar hälst. Und was du vielleicht selbst noch getestet hast.

So nun sind wir schon fast durch. Es fehlt noch MINIMAL PHP. Und auch hier steht wieder eine Versionsnummer. Aber diese Versionsnummer ist die deiner PHP-Version. Auch hier solltest du schauen, welche Version du als Mindeststandard vorraussetzen möchtest.

Der letzte Punkt dieser Liste ist TESTED WP. Diese Versionsnummer zeigt an ob dein Plugin mit aktuellen Version von WordPress bereits kompatibel ist. Es kommt ja immer wieder vor, dass WordPress ein neues Update bekommt. Und da man als Entwickler nicht immer sofort die Zeit hat gleich auf alle möglichen Änderungen zu reagieren und jedes mögliche Problem zu testen, hast du hier die Chance dem User mitzuteilen.

„Hey Moment, lass das mit dem Update nochmal sein. Das ist mit deiner WordPress Version noch gar nicht getestet.“

Um Fehler auf Seiten der Benutzer zu vermeiden.

Die ersten Zeilen Code

Jetzt geht es langsam los. Wir haben unser Plugin beschrieben und die Formalitäten abgearbeitet. Nun kommen wir den ersten Zeilen Quellcode unseres Plugins näher.

Ich mache es wieder wie im vorherigen Schritt. Ich zeige euch den nächsten Teil des Codes. Und dann gehen wir das ganze in einer Erläuterung durch. Für die jenigen, denen die Codezeilen schon klar sind, können dann direkt zum nächsten Punkt weiterscrollen.

if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly.
}
$basename = 'boilerplate-master';

define( 'BOILERPLATE_VERSION', '0.0.0.0' );
define( 'BOILERPLATE_MIN_PHP',   '8.2.0' );
define( 'BOILERPLATE_MIN_WP',    '6.4.0' );
define( 'BOILERPLATE_TESTED_WP',    '6.7.1' );
define( 'BOILERPLATE_DIRPATH', plugin_dir_path( __FILE__ ) );
define( 'BOILERPLATE_BASEURL',plugin_dir_url(dirname(__FILE__)).$basename.'/');


if(file_exists(BOILERPLATE_DIRPATH.'config.php')) {
    require_once BOILERPLATE_DIRPATH.'config.php';
}
if(file_exists(BOILERPLATE_DIRPATH.'autoload.php')) {
    require_once BOILERPLATE_DIRPATH.'autoload.php';
}

Dieser Codeabschnitt landet direkt unter unserem obrigen Abschnitt mit dem Kommentarblock.

Die ersten 3 Zeilen dieses Code-Abschnitts sind so etwas wie eine Sicherungsfunktion in WordPress. Damit soll verhindert werden, dass einzelne PHP-Dateien direkt angesteuert werden. Da WordPress – Plugins in einem mehr oder weniger leicht anzusteuerndem Ordner liegen, der auch jedem bekannt ist, wäre es so ein leichtes einzelne Dateien direkt aufzurufen. Dadurch könnten dann unberechtigte Bestimmte Funktionen triggern, die gar nicht aufgerufen werden sollen. 

Bei der Entwicklung von WordPress-Plugins sollte die Sicherheit des eigenen Codes immer hoch im Kurs stehen. Mögliche Sicherheitslücken können sonst eine Gefahr für viele Webseiten und alle Nutzer deines Plugins werden. Diesen Punkt werden wir zu einem späteren Zeitpunkt aber noch einmal vertiefen.

Die Zeilen 6-9 dürften dir ziemlich bekannt vorkommen. Denn es sind die selben Versionen, die wir schon in dem Kommentarblock oben einmal definiert haben. Im oberen Block haben wir es für WordPress und deren Parsing gemacht. Diese Definitionen die wir mit define gesetzt haben, sind für unseren Code. Damit wir innerhalb unseres Plugins damit arbeiten können.

Die Zeile 10 definiert mit einer WordPress Funktion den absoluten Basispfad deines Plugins. Damit kannst du von diesem definierten Punkt ausgehend andere PHP-Dateien aus anderen Ordnern besser ansteuern und einbinden.

In Zeile 11 definieren wir dann die Basisurl unseres Plugins. Diesen definierten Wert können wir später überall einsetzen wo es uns darum geht mit Javascript oder CSS-Dateien zu arbeiten. Denn diese können eher schlecht über interne Basispfade eingebunden werden. Sondern über einen öffentlichen Link. Darauf kommen wir aber später in der Serie noch genauer zu sprechen.

Einen ersten Vorgeschmack wofür die Definitionen gut sind, wird aber in den Zeilen 14-19 bereits gegeben. Hier binden wir 2 Dateien in unsere Hauptdatei ein, die wir in den folgenden Parts erstellen werden.  Wichtig ist dabei die Abfrage file_exists, denn damit wird überprüft ob diese Dateien wirklich dort vorliegen von wo wir sie Laden möchten. So verhindern wir einen Fehler, falls die Datei doch noch nicht da sein sollte. So wie es jetzt in unserem Fall ja ist. Wir benutzen hier die weiter oben definierte Konstante BOILERPLATE_DIRPATH welcher den Pfad zu unserem Plugin darstellt. An diesen Wert müssen wir dann nur noch einen entsprechenden Unterpfad (falls nötig) und den Dateinamen anhängen und schon haben wir eine qualifizierte Datei, die wir einbinden können.

Wir binden in diesen Zeilen einmal eine Datei für das Autoloading und eine Datei für Konfiguration ein. Beide Dateien sollten Standard in einem Plugin sein um gewisse Dinge festzulegen. Und beim Autoloading, um sich die Arbeit sehr zu erleichtern.

Optional: Der Update-Checker

Auch wenn dies kein zwingender Part für eine Plugin Boilerplate ist, möchte ich diesen Abschnitt hier mit einbringen. Dabei geht es mir um den Update-Checker. Dieser funktioniert sehr gut und lässt euch Updates von einem eigenen Updateserver abholen. Das heißt, ihr müsst euer Plugin dann nicht bei WordPress direkt verwalten und könnt es euren Kunden vom eigenen Server aus anbieten.

Mir gefällt diese Lösung sehr gut, sie wird regelmäßig geupdated, ist einfach zu implementieren und bietet hohen Komfort. Natürlich könnte man mit entsprechendem zeitlichen Aufwand so eine Lösung auch selbst in die Boilerplate implementieren. Aber warum stetig das Rad neu erfinden, wenn es schon vorhanden ist?

Wichtig ist nur, dieser Abschnitt ist optional. Wenn du keinen eigenen Updateserver betreiben möchtest, kannst du diesen Abschnitt auslassen. HINWEIS: In näherer Zukunft wird es hier auch einen detailierten Aufbau eines Updateservers geben, der mit dem Update-Checker kompatibel sein wird.

if(file_exists(BOILERPLATE_DIRPATH.'lib/plugin-update-checker/plugin-update-checker.php')) {
    require BOILERPLATE_DIRPATH . 'lib/plugin-update-checker/plugin-update-checker.php';
}


  use YahnisElsts\PluginUpdateChecker\v5p4\PucFactory;

$plugin_updateurl = "https://meineupdates.heinsen-it.de/updates/" . $basename . "/";
if(class_exists('PucFactory')) {
// Update Service
    $MyUpdateChecker = PucFactory::buildUpdateChecker(
        $plugin_updateurl,
        __FILE__, //Full path to the main plugin file.
        $basename //Plugin slug. Usually it's the same as the name of the directory.
    );
}

Wir benutzen hier in unserem Beispiel die Version 5.4 des Update-Checkers. Zum Zeitpunkt der Veröffentlichung dieses Artikels ist schon die Version 5.5 erschienen, die allerdings vom Autor noch nicht in einer Live-Version getestet wurde. Daher wird zunächst die bewährte Version genutzt. Wir haben hier noch entsprechende Sicherungen eingebaut, damit es keinen Fehler gibt, wenn der Update-Checker noch nicht eingebaut ist.

Aktivierungs & Deaktivierungs Hook

function BOILERPLATE_deactivate() {
// Alles was ausgeführt werden soll, sobald das Plugin deaktiviert wird.
}
register_deactivation_hook( __FILE__, 'BOILERPLATE_deactivate' );

function BOILERPLATE_activate() {
// Alles was ausgeführt werden soll, sobald das Plugin aktiviert wird.
}
register_activation_hook( __FILE__, 'BOILERPLATE_activate' );

function BOILERPLATE_uninstall() {
// Alles was ausgeführt werden soll, sobald das Plugin deinstalliert wird. 
}
register_uninstall_hook( __FILE__, 'BOILERPLATE_uninstall' );

Für unser Plugin können wir schonmal leere Dummy-Funktionen einrichten, die ausgeführt werden, sobald das Plugin aktiviert oder deaktiviert wird.

Diese Funktionen können dazu genutzt werden, um Dinge einzurichten, die für die Funktionalität des eigentlichen Plugins später unerlässlich sind. Ein gutes Beispiel hierfür wären Konfigurationen, die in die Datenbank geschrieben werden müssen.  Oder aber eine eigene Tabelle, die angelegt werden soll.

Beim Deaktivieren dann genau der umgekehrte Weg. Hierbei gibt es zwei verschiedene Abstufungen. Einmal bei Deaktivierung und einmal beim Deinstallieren. Die Funktion sollte die Dinge wieder aufräumen damit nach dem entfernen des Plugins die Datenbank sauber hinterlassen wird.

Es macht natürlich keinen Sinn, die Datenbank des Plugins schon zu bereinigen, wenn das Plugin deaktiviert wurde.

Starten des Plugins

// Starten der Plugin Funktionen
if (class_exists('main')) {
$plugin = new main();
$plugin->init();
}

Zum Schluss müssen wir noch den Part hinzufügen, der das Plugin aktiviert. Da wir diese Funktionen zum jetzigen Zeitpunkt dieser Serie noch nicht haben, werden wir diesen Teil zu einem späteren Zeitpunkt nochmal ergänzen.

Daher ist dieser Abschnitt und der Codeschnipsel erstmal nur ein Dummy. Auch wenn er nur minimalistisch ist. In unserem Beispiel haben wir den Abschnitt mit einer Abfrage umschlossen, ob die Klasse die wir aufrufen wollen vorhanden ist, weil wir diese Klasse natürlich noch gar nicht haben.

Zusammenfassung

Wir haben nun ein minimales sehr kleines Plugin. Das Plugin besteht aus einer Datei. Und es lässt sich aktivieren und deaktivieren. Unten sind zwei Bilder eingefügt, die unser Plugin im jetzigen Zustand aktiviert und deaktiviert auf dieser Seite zeigen.

Das ist aber noch nicht alles was wir mit der Boilerplate erreichen wollen. Wir wollen eine deutlich umfangreichere Grundlage für Plugins schaffen. Daher wird es in den kommenden Wochen weitere Teile dieser Reihe geben, in denen wir diese Grundlagen weiter ausbauen.

Zum Abschluss nun nochmal alle Codebestandteile zusammengefügt, die nun in der Hauptplugin – Datei vorhanden sein sollten:

<?php
/*
Plugin Name: Plugin Boilerplate
Plugin URI: https://heinsen-it.de/
Description: Vorlage für unsere Plugins
Author: Heinsen-IT
Version: 0.0.0.0
Letztes Update: 2025-02-01 20:00:00
Author URI: https://heinsen-it.de/
MINIMAL WP: 6.4.0
MINIMAL PHP: 8.2.0
Tested WP: 6.7.1
*/

if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly.
}
$basename = 'boilerplate-master';

define( 'BOILERPLATE_VERSION', '0.0.0.0' );
define( 'BOILERPLATE_MIN_PHP',   '8.2.0' );
define( 'BOILERPLATE_MIN_WP',    '6.4.0' );
define( 'BOILERPLATE_TESTED_WP',    '6.7.1' );
define( 'BOILERPLATE_DIRPATH', plugin_dir_path( __FILE__ ) );
define( 'BOILERPLATE_BASEURL',plugin_dir_url(dirname(__FILE__)).$basename.'/');


if(file_exists(BOILERPLATE_DIRPATH.'config.php')) {
    require_once BOILERPLATE_DIRPATH.'config.php';
}
if(file_exists(BOILERPLATE_DIRPATH.'autoload.php')) {
    require_once BOILERPLATE_DIRPATH.'autoload.php';
}



/** OPTIONAL */
if(file_exists(BOILERPLATE_DIRPATH.'lib/plugin-update-checker/plugin-update-checker.php')) {
    require BOILERPLATE_DIRPATH . 'lib/plugin-update-checker/plugin-update-checker.php';
}


  use YahnisElsts\PluginUpdateChecker\v5p4\PucFactory;

    $plugin_updateurl = "https://meineupdates.heinsen-it.de/updates/" . $basename . "/";
if(class_exists('PucFactory')) {
// Update Service
    $MyUpdateChecker = PucFactory::buildUpdateChecker(
        $plugin_updateurl,
        __FILE__, //Full path to the main plugin file.
        $basename //Plugin slug. Usually it's the same as the name of the directory.
    );
}


/** OPTIONAL */



function BOILERPLATE_deactivate() {
// Alles was ausgeführt werden soll, sobald das Plugin deaktiviert wird.
}
register_deactivation_hook( __FILE__, 'BOILERPLATE_deactivate' );

function BOILERPLATE_activate() {
// Alles was ausgeführt werden soll, sobald das Plugin aktiviert wird.
}
register_activation_hook( __FILE__, 'BOILERPLATE_activate' );

function BOILERPLATE_uninstall() {
// Alles was ausgeführt werden soll, sobald das Plugin deinstalliert wird.
}
register_uninstall_hook( __FILE__, 'BOILERPLATE_uninstall' );


// Starten der Plugin Funktionen
if (class_exists('main')) {
    $plugin = new main();
    $plugin->init();
}

Quellen & Links

Und nun nochmal die wichtigsten Quellen zum Abschluss:

Es gibt im Internet auch noch weitere spannende Quellen. An dieser Stelle soll es das aber erstmal gewesen sein. Weiter geht es im zweiten Part mit dem Thema Autoloading und der weiteren Struktur des Plugins.

Jeder Beitrag unterliegt einem ständigen Verbesserungsprozess. Es wird versucht die enthaltenden Informationen stets auf dem neusten Stand zu erhalten. Über Hinweise zur Verbesserung bin ich dankbar.

Sollten Informationen fehlen oder veraltet sein, übernimmt der Autor dennoch keine Haftung dafür. Vielen Dank.

HIT Plugin Boilerplate
WP Plugins Part 2: Autoload und Struktur

Im zweiten Part stellen wir die Weichen für unser Plugin. Wir treffen einige Entscheidung zur grundlegenden Struktur. Und auf dieser Basis legen wir uns dann einen Autoloader an, der die Arbeit einfacher macht.

Erfahre mehr