Twig in WordPress-Plugins nutzen

Update 2022-06-13:

Seien Sie gewarnt! Es stellt sich heraus, dass die Verwendung von Twig oder anderen Abhängigkeiten mit Composer in WordPress tatsächlich eine schlechte Idee ist! Das Problem ist, dass andere Plugins oder Themes möglicherweise auch dieselben Komponenten verwenden, aber in einer anderen Version – und dann können alle möglichen Konflikte auftreten! Ich empfehle daher bis auf weiteres NICHT, diesem Artikel zu folgen!


Der grundlegende Aufbau von WordPress-Plugins ist eher einfach gehalten:

Im Verzeichnis des Plugins wird als minimale Voraussetzung die Datei readme.txt mit einer Beschreibung im Header und eine PHP-Datei für die Plugin-Initialisierung benötigt. Es ist nicht zwingend erforderlich, eigene Klassen zu implementieren, da der Code von WordPress direkt ausgeführt wird – allerdings erleichtert eine Organisation in Klassen die Lesbarkeit und Wartbarkeit erheblich.

Objektorientierter Aufbau eines WordPress-Plugins

Aufgrund der Arbeitsweise von WordPress ist der übliche Ansatz für ein objektorientieres Plugin die Implentierung einer Hauptklasse, von der zur Laufzeit eine Instanz erzeugt wird. Im Konstruktor der Klasse werden alle erforderlichen Initialisierungen ausgeführt. Es ist dabei sinnvoll, einen eigenen Namspace zu definieren, um sicherzustellen, dass die Klasse keine Konflikte mit existierenden globalen Klassen verursacht.

Für die Nutzung von register_activation_hook() und register_deactivation_hook() ist es notwendig, den Namen der Datei anzugeben, über die das Plugin geladen wird. Es ist daher eine gute Idee, dies als Parameter an die Hauptklasse zu übergeben, damit diese Information dort auch zur Verfügung steht.

Ebenfalls sinnvoll ist es, die Versionsnummer als Konstante (MyPlugin::VERSION) bereitzustellen. Diese wird benötigt, wenn man mit wp_enqueue_script() und wp_enqueue_style() nutzt und sollte bei jedem Update des Plugin entsprechend angepasst werden.

Als Beispiel ein einfaches Plugin, was einen Shortcode bereitstellt.

In wp-content/plugins/my-plugin/readme.txt:

=== My Plugin ===

Contributors: myusername
Tags: images
Requires at least: 5.0
Tested up to: 6.0
Stable tag: 1.0
License: GPLv2
License URI: http://www.gnu.org/licenses/gpl-2.0.html

My Plugin for useful stuff.

== Description ==

This is the detailed plugin description.

In wp-content/plugins/my-plugin/my-plugin.php:

<?php
namespace MyPlugin;

defined('ABSPATH') or die();

class MyPlugin
{
    const VERSION = '1.0';

    protected string $pluginFile;

    public function __construct(string $pluginFile)
    {
        $this->pluginFile = $pluginFile;
        add_shortcode('myshortcode', array($this, 'shortCode'));
    }
    
    public function shortCode($atts, $content = null): string
    {
        $output = '';

        // ...

        return $output;
    }
}

$myPlugin = new MyPlugin(__FILE__);

Der Ablauf ist hier wie folgt:

  1. WordPress prüft, ob das Plugin bereits aktiviert ist und führt den Code in wp-content/plugins/my-plugin/my-plugin.php aus.
  2. Durch $myPlugin = new MyPlugin(); wird eine neue Instanz der Klasse MyPlugin erzeugt und der Konstruktor der Klasse ausgeführt, in dem der Shortcode hinzugefügt wird.
  3. Immer wenn der Shortcode [myshortcode] verwendet wird, wird die Methode MyPlugin::shortCode() ausgeführt.

Durch die Anweisung defined('ABSPATH') or die(); am Anfang wird sichergestellt, dass der Code nur im Rahmen von WordPress ausgeführt wird – was daran erkennbar ist, dass ABSPATH definiert ist.

Integration von Twig

Der vorgesehen Weg zur Nutzung von Twig ist die Installation mit Composer. Die Installation von Composer selbst ist in der Dokumentation beschrieben, siehe Download Composer.

Für die Installation von Twig wechselt man in einer Konsole das Verzeichnis des Plugins und führt dort folgenden Befehl aus, um Twig 3.0 zu installieren:

composer require "twig/twig:^3.0"

Damit wird Twig selbst und die dafür erforderlichen Pakete symfony/polyfilly-mbstring und symfony/polyfill-ctype von https://repo.packagist.org heruntergeladen. Als Ergebnis erhält man ein zusätzliches Verzeichnis vendor für die Pakete und die beiden Dateien composer.json und composer.lock.

Zusätzlich legt man manuell das Verzeichnis templates an, in dem man später die Templates für Twig ablegt. Daraus ergibt sich dann folgende Struktur:

wp-content/
    plugins/
        my-plugin/
            templates/
            vendor/
               composer/
               symfony/
               twig/
               autoload.php
            composer.json
            composer.lock
            my-plugin.php
            readme.txt

Einbinden von Twig über den Autoloader von Composer

Die notwendigen Klassen von Twig werden über den Autoloader geladen, sobald man sie mit use anfordert. Damit das funktioniert, muss der Autoloader, den Composer im Verzeichnis vendor angelegt hat, geladen werden.

Im Konstruktor der Plugin-Klasse wird eine Instanz von Twig erzeugt, mit der dann die Ausgabe von Templates vorgenommen wird.

Die Datei my-plugin.php wird dafür wie folgt erweitert:

<?php
namespace MyPlugin;

use Twig\Loader\FilesystemLoader;
use Twig\Environment;

defined('ABSPATH') or die();

require(__DIR__ . '/vendor/autoload.php');

class MyPlugin
{ 
    const VERSION = '1.0';
    const SLUG = 'my-plugin;

    protected string $pluginFile;
    protected Environment $twig;

    public function __construct(string $pluginFile)
    {
        $this->pluginFile = $pluginFile;
        $this->twig = new Environment(new FilesystemLoader(__DIR__.'/templates'));
        add_shortcode('myshortcode', array($this, 'shortCode')); } 
    }
    
    public function shortCode($atts, $content = null): string
    {
        $output = '';

        // ...

        return $output;
    } 
}

$myPlugin = new MyPlugin(__FILE__);

Verwenden von Twig-Templates

Der Aufbau von Twig-Templates ist in der Dokumentation von Twig gut beschrieben: Twig for Template Designers

Als Beispiel soll der Shortcode ein Bild anhand der angegeben ID wie folgt ausgeben:

[myshortcode id="7"]

Die Ausgabe des Shortcode wäre mit einem Twig-Template templates/shortcode.html.twig wie folgt möglich:

<figure>
    <img src="{{ imageUrl }}" alt="{{ imageAlt }}" />
    {% if imageCaption %}
    <figcaption>{{ imageCaption }}</figcaption>
    {% endif %}
</figure>

Das kann dann zur Laufzeit im Shortcode-Handler genutzt werden:

public function shortCode($atts, $content = null): string
{
    if (!isset($atts['id'])) {
        return '';
    }
    $id = $atts['id'];

    return $this->twig->render('shortcode.html.twig', [
        'imageUrl' => wp_get_attachment_image_url($id, 'full'),
        'imageAlt' => get_post_meta($id, '_wp_attachment_image_alt', TRUE);
        'imageCaption' => wp_get_attachment_caption($id)
    ]);
}

Mit $this->twig->render('shortcode.html.twig', ... wird Twig dazu veranlasst, das Template in der Datei templates/shortcode.html.twig zu verarbeiten. Die darin benötigten Variablen werden als array übergeben und stehen dann innerhalb des Template entsprechend zur Verfügung.

Ausblick

Nur für einen einfachen Shortcode mag die Verwendung von Twig übertrieben erscheinen. Es gibt aber Situationen, wo deutlich mehr HTML erzeugt werden muss, als nur ein paar Zeilen – etwa für administrative Seiten im Backend. Hier ist Twig zur Trennung von Code und UI sehr hilfreich. Templates kann man auch in kleinere Einheiten aufteilen, was die Fehlersuche vereinfacht, wenn man einer Änderung das Ergebnis nicht mehr so ist, wie erwartet.

Caching

Wenn Twig-Templates im Frontend verwendet werden, kann ein Cache sehr dabei helfen, die Leistung zu steigern. Twig compiliert jedes Template und unterstützt die Speicherung des Ergebnisses in einem Cache, so dass das Template beim nächsten Mal nicht erneut compiliert werden muss. Allerdings erfordert dies, dass ein Ordner dafür erzeugt wird, der auch beim Deaktivieren des Plugins wieder entfernt werden sollte. Dieses Thema wird in einem künftigen Artikel behandelt.

Extensions

Ebenfalls möglich ist die Einbindung eigener Twig-Extensions, siehe dazu Extending Twig. Das ist beispielsweise notwendig, wenn man die funktionen __() oder _n() von WordPress nutzen will, um Texte mit Übersetzungen in einem Template auszugeben. Dieses Thema wird in einem künftigen Artikel behandelt.

Öffentlichen Kommentar hinterlassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Dies ist kein Kontaktformular! Wenn Du mir eine persönliche Nachricht schreiben möchtest, benutze die E-Mail-Adresse in meinem Impressum.

Du kannst die folgenden HTML-Tags im Kommentar verwenden:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>