WordPress Plugin schreiben mit Composer und Autoload
10.Aug.2021 WordPress Tutorial

WordPress Plugin schreiben mit Composer und Autoload

In diesem Tutorial möchte ich euch einmal zeigen, wie man WordPress Plugins mit Composer und einem PSR-4 Autoloader schreiben kann. Damit wir Composer nutzen können, benötigst du ein paar Sachen auf deinem Rechner und damit fangen wir jetzt direkt an…

Composer installieren

Damit wir Composer nutzen können, brauchen wir erst einmal eine installierte Version auf unserem Rechner. Composer hat allerdings eine Abhängigkeit, die wir uns zuvor besorgen müssen und die heißt PHP. Auf folgender Seite: PHP For Windows: Binaries and sources Releases kannst du dir PHP in einer ZIP Datei für Windows herunterladen. Entpacke diese Zip auf deinem Rechner an einem sinnvollen Ort, mit dem Hintergedanken, dass sich mit der Zeit verschiedene Versionen ansammeln können.

Anschließend laden wir uns auf folgender Website  Introduction – Composer (getcomposer.org)  das Composer Setup herunter und starten die Installation. Im Laufe der Installation werden wir ein paar Sachen gefragt, z.B. nach der command-line PHP, klicke hier auf Browse und wähle die, im eben entpackten Ordner befindliche, php.exe Datei.

Achte bitte auch darauf, dass im nächsten Schritt PHP zu deinem Path hinzugefügt wird.

Wenn die Installation durchgelaufen ist, schließen wir erst einmal alle Terminals, die wir noch offen haben und öffnen anschließend ein neues Terminal.
Mit folgendem Befehl testen wir, ob Composer uns nun zur Verfügung steht:

composer -V
Composer version 2.0.14 2021-05-21 17:03:37

Composer sollte nun mit der installierten Version antworten, wie im Beispiel zu sehen ist.

Composer Init für ein WordPress Plugin

Nachdem wir Composer installiert haben, sind wir auch schon bereit unser erstes Plugin mit Composer zu schreiben. Hierfür legen wir, wie gewohnt, einen neuen Ordner für das Plugin an.
Anschließend navigieren wir in einem Terminal in unseren Ordner und initialisieren mit folgendem Befehl ein neues Composer Projekt:

composer init
Welcome to the Composer config generator  

This command will guide you through creating your composer.json config.

Composer begrüßt uns anschließend und stellt uns ein paar Fragen zu unserem Projekt. Für dieses Tutorial habe ich die Fragen wie folgt beantwortet:

Wie soll das neue Package heißen?

Package name (<vendor>/<name>) [tobia/my-plugin]: tobier/myplugin

Eine Projektbeschreibung

Description []: Simple WordPress Plugin with Composer and Autoload

Angaben zum Author

Author [Tobias Keller <tobias@tobier.de>, n to skip]: Tobier <mail@tobier.de>

Folgende Fragen habe ich für dieses Tutorial mit einer enter Eingabe übersprungen:

Mindeststabilität der Dependencies die installiert werden dürfen (dev, alpha, beta, RC).
Package Type und die Lizenz unter der das Plugin später stehen soll:

Minimum Stability []:
Package Type (e.g. library, project, metapackage, composer-plugin) []:
License []:

Anschließend fragt uns Composer, ob wir Dependencies installieren möchten.
Dependencies können Pakete sein, die wir für einen speziellen Fall in unser Plugin integrieren möchten, wie z.B. eine Paket für eine Integration einer Newsletter API oder ähnliches.
Eine Auflistung der zur Verfügung stehenden Pakete findet man hier Packagist.
Bei den Dependencies unterscheidet man in der Regel zwischen zwei verschiedenen Stufen, den Dev-Dependencies, welche nur bei dem Entwickler auf dem Rechner installiert werden sollen und den normalen Dependencies, die auch später in unserem Plugin enthalten sein sollen. Für dieses Tutorial werden wir nur Dev-Dependencies verwenden, Composer fragt diese Pakete in zwei Fragen ab.

Wollen wir Dependencies installieren? Nein

Define your dependencies.

Would you like to define your dependencies (require) interactively [yes]? no

Wollen wir Dev-Dependencies intallieren? Ja!

Would you like to define your dev dependencies (require-dev) interactively [yes]?
Search for a package: WordPress Coding Standards

Wir suchen also nach „WordPress Coding Standards“ im Paket Archiv und Composer schlägt uns 15 Pakete vor. Wir wählen mit 0 das erste Pakete aus und bestätigen mit Enter das wir die aktuellste Version installieren möchten. Wer mehr über das WordPress Coding Standards Paket wissen möchte, kann auf Github vorbeischauen. WordPress/WordPress-Coding-Standards: PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions (github.com)

Found 15 packages matching WordPress Coding Standards

   [0] wp-coding-standards/wpcs
   .......

Enter package # to add, or the complete package name if it is not listed: 0
Enter the version constraint to require (or leave blank to use the latest version):
Using version ^2.3 for wp-coding-standards/wpcs

Anschließend zeigt Composer die aktuelle Konfiguration in Form von einem JSON und fragt uns, ob wir die Konfiguration bestätigen möchten, was wir natürlich tun. Die nächste Frage lautet, ob wir die angegebenen Dependencies installieren möchten, was wir auch bestätigen.

{
    "name": "tobier/myplugin",
    "description": "Simple WordPress Plugin with Composer and Autoload",
    "require-dev": {
        "wp-coding-standards/wpcs": "^2.3"
    },
    "authors": [
        {
            "name": "Tobier",
            "email": "mail@tobier.de"
        }
    ],
    "require": {}
}

Do you confirm generation [yes]? yes
Would you like to install dependencies now [yes]? yes

Composer legt nun zwei Konfigurations-Dateien an „composer.json“ und „composer.lock“. Die eben installierten Dependencies befinden sich nun im Ordner „Vendor“ in unserem Hauptverzeichnis.

WordPress Plugin Grundstruktur

Für unser Plugin müssen wir nun in unserem Ordner noch ein paar Dateien und Ordner in unserem Plugin Hauptordner erstellen.
Legen wir nun also eine „main.php“ Datei im Hauptordner an und fügen einen WordPress Plugin Standard Header ein, was wie folgt aussehen könnte:

<?php
/**
 * Plugin Name:       Tobier Plugin with Composer
 * Plugin URI:        https://tobier.de/wordpress-plugin-schreiben-mit-composer-und-autoload
 * Description:       Simple WordPress Plugin with Composer and Autoload
 * Version:           0.1
 * Requires at least: 5.7
 * Author:            Tobier.de
 * Author URI:        https://tobier.de
 */

if ( ! defined( 'ABSPATH' ) ) {
    die( '' );
}

Wer keine Ahnung hat, was dieser Header bedeutet und warum wir ihn brauchen, sollte sich erst einmal dieses Tutorial anschauen: https://tobier.de/wordpress-plugin-erstellen-so-einfach-geht-es/

In unserem Hauptordner legen wir nun noch einen neuen Ordner mit dem Namen „src“ an, wo wir später unsere PHP Klassen liegen haben werden. Wer möchte kann hier schon einmal ein PHP File mit dem Namen „Class_ModifingHeader.php“ erstellen.

Unsere Dateistruktur sollte nun wie folgt aussehen:

PSR-4 Autoloader integrieren

Wer bisher ohne Autoloader WordPress Plugins geschrieben hat und seinen Code in mehrere Dateien strukturiert hat, würde vermutlich jetzt anfangen in der Haupt PHP-Datei unseres Plugins die Datei zu laden z.B mit einem „require“ oder einem „require_once“.

Dies soll nun unser Autoloader für uns machen und die entsprechenden Datei für uns bereitstellen. Unserem Plugin müssen wir hierfür in der „composer.json“ erst einmal sagen, dass wir gerne einen Autloader nutzen möchten. Hierfür erstellen wir in unserem JSON-Objekt einen neuen Eintrag, der wie folgt aussieht:

"autoload": {
    "psr-4": {
        "MySimpleComposerPlugin\\" : "src/"
    }
}

Wir erstellen in unserem JSON Objekt also ein weiteres Objekt mit dem Namen „autoload“. In diesem ein weiteres Objekt mit der Bezeichnung „psr-4“, in dem wir nun angeben, welchen Namespace wir verwenden wollen ( in unserem Fall „MySimpleComposerPlugin“) und sagen ihm, in welchem Ordner er nach neuen Elementen suchen soll (in unserem Fall „src/“).

Unsere PHP Klasse für den Autoloader vorbereiten

Wer am Anfang des Tutorials die Klasse „Class_ModifingHeader“ im „src“ Ordner noch nicht angelegt hat, sollte dieses jetzt erledigen. Wir werden für das Tutorial jetzt eine sehr einfache Klasse mit wenig, oder auch keiner Logik erstellen, da es hier nur darum geht, wie wir Composer und Autoload mit WordPress verwenden können. Hier der Code der Klasse:

<?php

namespace MySimpleComposerPlugin;

if ( ! defined( 'ABSPATH' ) ) {
    die( '' );
}

class Class_ModifingHeader{
    public function __construct(){
        add_action('wp_head', [$this, 'addHelloToHeader']);
    }

    public function addHelloToHeader(){
        echo 'Hello little Header';
    }

    public function getCreatorName() {
        return "tobier.de";
    }
}

Jeder der bereits mit PHP Klassen gearbeitet hat, bemerkt hier wahrscheinlich, dass nichts besonders ungewöhnlich ist. Wer jedoch nicht häufig mit PHP Klassen und OOP arbeitet und sich gerade in das Thema einarbeitet, sollte speziell auf Zeile 3 achten. Hier wird der Namespace angegeben, unter dem sich die Klasse befinden soll. Ansonsten ist dies eine gewöhnliche Klasse, die im Konstruktor eine kleinen Text in den „wp_head“ Hooked und eine weitere Methode zur Verfügung stellt, um einen String zu bekommen.

Autoloader laden

Nachdem wir den Autoloader in unserer composer.json Datei bekanntgemacht haben, werden wir ihn jetzt in unser WordPress Plugin integrieren. Wer sich eventuell schon die Dateien angeguckt hat, die Composer im Vendor Ordner erstellt hat, ist bereits über die autoload.php Datei gestolpert. Diese Datei lädt eine weitere Autoload Datei welche für die Magie sorgt. Also requiren wir diese Datei in unserem Plugin und geben an, welche Klasse wir hier gerne benutzen möchten.

require "vendor/autoload.php";

use MySimpleComposerPlugin\Class_ModifingHeader;

$header = new Class_ModifingHeader();
$creator = $header->getCreatorName();

In Zeile 1 requiren wir, wie bereits beschrieben, unseren autoloader. Mit dem Befehl „use“ geben wir an, welche Klasse wir unter welchem Namespace nutzen möchten. Anschließend initialisieren wir unsere Klasse und können Sie wie gewohnt nutzen.

Autoloader generieren

Als letzten Schritt fehlt eigentlich nur noch das Generieren des Autloaders, welches über einen einfachen Befehl mit dem Terminal zu erledigen ist.

composer dump-autoload -o

Generiert einen optimierten Autoload, der von uns angelegten Klasse und der Klassen unserer verwendeten Dependencies.
Wer sich einmal die Größe unseres Plugins anschaut, derzeit 5MB, merkt man, dass es allerdings ein bisschen groß ist und wir würden unsere Dev-Dependencies mit in unsere WordPress Installation übertragen.
Da diese nur dafür bestimmt sind, um beim Entwickeln verschiedene Hilfsanwendungen benutzen zu können, brauchen wir sie nicht in einer Live-Umgebung.

Dementsprechend führen wir folgende Befehle in unserem Terminal aus, um die Dev-Dependencies zu entfernen und den Autoloader neu zu generieren:

composer install --no-dev
composer dump-autoload -o --no-dev

Unsere Plugingröße ist nun auf 35KB gesunken und wir liefern keine unnötigen Dateien mehr aus. Wer möchte kann jetzt das Plugin einmal unter WordPress installieren und aktivieren, es erscheint im wp_head nun der Text „Hello little Header“

WordPress Coding Standards

Wer sich fragt, warum wir als Dev-Dependency die WordPress Coding Standards installiert haben, kommt jetzt auf seine Kosten.
Mit den Coding Standards können wir unseren geschriebenen Code überprüfen lassen und bis zu einem gewissen Grad auch automatisch den Standards anpassen.
Hierfür installieren wir erst einmal wieder die Dev-Dependecies mit

composer install

Anschließend müssen wir unserem Code Sniffer noch die WordPress Standards bekannt machen, was mit folgendem Befehl zu realisieren ist:

vendor/bin/phpcs --config-set installed_paths vendor/wp-coding-standards/wpcs

Ist das erledigt, führen wir den Code Sniffer auf unsere Klasse aus und bekommen als Rückmeldung, was nicht den WordPress Coding Standards entspricht:

vendor/bin/phpcs --standard=WordPress src/Class_ModifingHeader.php

FILE: ...\htdocs\wp-content\plugins\myPlugin\src\Class_ModifingHeader.php
----------------------------------------------------------------------
FOUND 29 ERRORS AFFECTING 12 LINES
----------------------------------------------------------------------
  1 | ERROR | [ ] Filenames should be all lowercase with hyphens as
    |       |     word separators. Expected class-modifingheader.php,
    |       |     but found Class_ModifingHeader.php.
  1 | ERROR | [ ] Class file names should be based on the class name
    |       |     with "class-" prepended. Expected
    |       |     class-class-modifingheader.php, but found
    |       |     Class_ModifingHeader.php.
  1 | ERROR | [ ] Missing file doc comment
  1 | ERROR | [x] End of line character is invalid; expected "\n" but
    |       |     found "\r\n"
  5 | ERROR | [ ] Missing doc comment for class Class_ModifingHeader
  5 | ERROR | [x] Expected 1 space before opening brace; found 0
  6 | ERROR | [x] Tabs must be used to indent lines; spaces are not
    |       |     allowed
  6 | ERROR | [ ] Missing doc comment for function __construct()
  6 | ERROR | [x] Expected 1 space before opening brace; found 0
  7 | ERROR | [x] Tabs must be used to indent lines; spaces are not
    |       |     allowed
  7 | ERROR | [x] Expected 1 spaces after opening parenthesis; 0
    |       |     found
  7 | ERROR | [x] Missing space after array opener.
  7 | ERROR | [x] Short array syntax is not allowed
  7 | ERROR | [x] Missing space before array closer.
  7 | ERROR | [x] Expected 1 spaces before closing parenthesis; 0
    |       |     found
  8 | ERROR | [x] Tabs must be used to indent lines; spaces are not
    |       |     allowed
 10 | ERROR | [x] Tabs must be used to indent lines; spaces are not
    |       |     allowed
 10 | ERROR | [ ] Method name "addHelloToHeader" in class
    |       |     Class_ModifingHeader is not in snake case format,
    |       |     try "add_hello_to_header"
 10 | ERROR | [ ] Missing doc comment for function addHelloToHeader()
 10 | ERROR | [x] Expected 1 space before opening brace; found 0
 11 | ERROR | [x] Tabs must be used to indent lines; spaces are not
    |       |     allowed
 12 | ERROR | [x] Tabs must be used to indent lines; spaces are not
    |       |     allowed
 14 | ERROR | [x] Tabs must be used to indent lines; spaces are not
    |       |     allowed
 14 | ERROR | [ ] Method name "getCreatorName" in class
    |       |     Class_ModifingHeader is not in snake case format,
    |       |     try "get_creator_name"
 14 | ERROR | [ ] Missing doc comment for function getCreatorName()
 15 | ERROR | [x] Tabs must be used to indent lines; spaces are not
    |       |     allowed
 15 | ERROR | [x] String "tobier.de" does not require double quotes;
    |       |     use single quotes instead
 16 | ERROR | [x] Tabs must be used to indent lines; spaces are not
    |       |     allowed
 17 | ERROR | [x] File must end with a newline character
----------------------------------------------------------------------
PHPCBF CAN FIX THE 20 MARKED SNIFF VIOLATIONS AUTOMATICALLY
----------------------------------------------------------------------

Time: 182ms; Memory: 10MB

Recht viele Fehlermeldungen für so wenige Zeilen Code. Aber lasst uns kurz versuchen ein paar Fehler automatisch zu beheben.
Die automatische Behebung führen wir mit einem Befehl aus, der dem letzten sehr ähnelt:

vendor/bin/phpcbf --standard=WordPress src/Class_ModifingHeader.php

Als Antwort bekommen wir das 20 Fehler automatisch behoben werden konnten:

PHPCBF RESULT SUMMARY
----------------------------------------------------------------------
FILE                                                  FIXED  REMAINING
----------------------------------------------------------------------
...ent\plugins\myPlugin\src\Class_ModifingHeader.php  20     9
----------------------------------------------------------------------
A TOTAL OF 20 ERRORS WERE FIXED IN 1 FILE
----------------------------------------------------------------------

Time: 307ms; Memory: 10MB

Es bleiben also 9 „Fehler“ übrig, die du beheben kannst um WordPress Coding Standard konform zu arbeiten.
Ich wünsche dir viel Spaß dabei und falls du dieses Beispiel als Download haben möchtest, findest du es hier auf meinem GitHub Profil.

Tobias Keller Web Entwickler
Tobias Keller Web Entwickler

Mit Leib und Seele Web Entwickler, immer auf der Suche nach der nächsten Herrausforderung, offen für Neues, Autodidakt.

Kommentare

Geschlossen wegen DSGVO, Artikel 13 Gedöns