WordPress Navigationsmenü bearbeiten – Menüfelder hinzufügen

Ich möchte dir ein Package vorstellen, mit dem du mehr Felder zum WordPress-Menü Bearbeitungsfenster hinzufügen kannst.

WordPress Navigationsmenü bearbeiten – wie geht das, fragst du dich? Ich möchte dir eines unserer Packages vorstellen. Damit kannst du mehr Menüfelder in WordPress hinzufügen. Folgend eine kurze Einführung.

Das Problem: WordPress bietet keinen Filter an, um Standardfelder zu bearbeiten

Eigentlich stellt WordPress eine gute UI zur Verfügung, um Navigationsmenüs zu bearbeiten. Allerdings ist es ziemlich eigenwillig, was die verfügbaren Einstellungen für jedes Menüitem angeht. Diese sind:

  • “Navigation Label”
  • “Title Attribute”
  • “Open link in a new tab”
  • “CSS Classes”
  • “Link Relationship (XFN)”
  • “Description”

Das Problem ist also, dass WordPress keinen Filter anbietet, um Standardfelder in WordPress zu bearbeiten. Darüber hinaus gibt es keinen Action Hook, mit dem HTML für benutzerdefinierte Formularfelder ausgegeben werden können, wie es in vielen anderen Bereichen des WordPress Backend der Fall ist.

Nun, es gibt einen Weg, um einen Filter Hook anzupassen. Es ist der  "wp_edit_nav_menu_walker" Filter Hook, der es ermöglicht, den Class Name eines Custom Walkers zurückzugeben. Also musst du jedes Mal, wenn du ein Feld brauchst, einen Custom Walker schreiben. Das ist zwar ziemlich nervig, aber keine große Sache. Allerdings wird es schwieriger, wenn dieser Filter von mehr als einem Plugin gehooked wird.

Weil "wp_edit_nav_menu_walker" einen Walker Class Name voraussetzt, ist es nur möglich, den Class Name komplett zu überschreiben. Wenn also zwei oder mehr Plugins diesen gleichen Filter nutzen, bekommt nur eines von ihnen seine Walker Class in Gebrauch. Die anderen werden nichts tun.

Für unsere Kundenprojekte brauchten wir weitere Felder. Diese waren beispielsweise “data” Attribute oder “rel” Attribute (“noopener”, “nofollow”…). Also brauchten wir eine Lösung für das Problem. Darum haben wir dieses Package erstellt. Es existiert, weil wir einen Weg brauchten, um mehr Felder hinzuzufügen, die auch funktionieren konnten, wenn sie von mehreren Plugins verwendet werden.

Die Lösung: Ein Package, das Plugins via Composer anfragen können

Weil mehr als ein Plugin das Nutzungsziel “Mehr Felder in WordPress” nutzen werden, ist selbst kein Plugin. Stattdessen ist es ein Package, das Plugin über Composer anfragen können.


Um das Package zu installieren, benötigst du Composer und außerdem PHP 7 oder höher. Der Name des Packages ist inpsyde/more-menu-fields.


Wenn das Package über Composer gefordert und Composer Autoload geladen worden ist, musst du ein Bootstrapping des Packages durchführen.

Das kannst du in einem Plugin machen, indem du einfach eine Funktion aufrufst:

Inpsyde\MoreMenuFields\bootstrap();

Es ist nicht notwendig, den Call in einen Hook zu packen. Selbst wenn er mehr als einmal aufgerufen wird (von verschiedenen Plugins), wird nichts Schlimmes passieren.

Die Interfaces der Felder

Um mehr Felder hinzuzufügen, musst du eine PHP Klasse für jede von ihnen erstellen. Die Klasse muss das Interface Inpsyde\MoreMenuFields\EditField implementieren, was so aussieht:

 EditField {

public function name(): string;

public function field_markup(): string;
}

Die erste Methode, name(), muss den Feldnamen wiedergeben. Das kann irgendein String sein, muss aber einzigartig sein.

Die zweite und letzte Methode, field_markup(), muss das HTML Markup des Felds wiedergeben, da es auf der UI erscheinen wird.

Im HTML Markup ist es sehr wahrscheinlich notwendig den Input Name zu nutzen, seine ID und seinen derzeit gespeicherten Wert, falls vorhanden. Diese Informationen kannst du über ein Objekt des Typs Inpsyde\MoreMenuFields\EditFieldValue erhalten. Mehr dazu bald.

Sehr häufig (wenn nicht sogar immer) muss allerdings der Wert, den Nutzer im generierten Eingabefeld eingeben, gereinigt werden, bevor er gespeichert wird. Darum liefert das Package ein anderes Interface Inpsyde\MoreMenuFields\SanitizedEditField , was so aussieht:

interface SanitizedEditField extends EditField {

public function sanitize_callback(): callable;
}

Das Interface erweitert EditField  und du kannst seine einzige Methode, sanitize_callback() nutzen, um einen Callback zurückzugeben, der die Nutzereingabe reinigt. Es ist empfohlen dieses Interface zu implementieren, um Felder zu erstellen und nur EditField für Formulareingabefelder zu nutzen, die eigentlich keinen Input bekommen, wie zum Beispiel Buttons.

Du brauchst ein Beispiel? Dann schau dir GitHub an, wo wir ein field class example hinzugefügt haben.

Ein Feld hinzufügen

Nur die Field Class oben wird nichts machen, wenn das Package nichts darüber weiß. Darum müssen wir das Package auf die Class aufmerksam machen. Um dies zu tun, müssen wir eine Instanz davom zum Array hinzufügen, das von einem Filter-Hook übergeben wurde, der in der Konstanten Inpsyde\MoreMenuFields\FILTER_FIELDS gespeichert ist.

Dieser Filter gibt den Array der gerade hinzugefügten Filter an Hooking Rückrufe weiter und als zweites Argument eine Instanz von EditFieldValueFactory: Ein Objekt, das genutzt werden kann, um Instanzen von EditFieldValue zu erhalten, damit sie in Field Classes genutzt werden können.

Lasst uns ein Beispiel anschauen:


use Inpsyde\MoreMenuFields;
use My\Plugin\NofollowField;

add_filter(
    MoreMenuFields\FILTER_FIELDS,
    function (
        array $items,
        MoreMenuFields\EditFieldValueFactory $factory
    ) {
        $edit_field_value = $factory->create( 'nofollow' );
        $fields[] = new NofollowField( $edit_field_value );

        return $fields;
    },
    10,
    2
);

Beim Hooking von Inpsyde\MoreMenuFields\FILTER_FIELDS wird die übergebene  EditMenuFieldValueFactory genutzt, um eine Instanz von EditFieldValue zu erhalten, die in das Feldobjekt eingefügt wird. (Nicht mehr als das, was ich oben gezeigt habe.).

Um die EditFieldValue Instanz zu erhalten, wird die create() Methode in der Factory aufgerufen. Dabei wird ihr genau der Name des Feldes übergeben, der genau der gleiche Name sein muss wie der, der von der field object name() Methode zurückgegeben wird.

Das war’s. Der Filter rechts oben zusammen mit der Klasse im vorangegangenen Abschnitt ist wirklich alles was du brauchst, um das Feld zu erstellen und auch zu speichern.

Den Vorteil dieses Vorgangs kannst du sehr schnell sehen, wenn sehr viele Felder hinzugefügt werden. Außerdem kann der Inpsyde\MoreMenuFields\FILTER_FIELDS Filter bei vielen Plugins genutzt werden, die nichts voneinander wissen – und alles wird einfach gut funktionieren.

Weitere Informationen

Allerdings soll das hier nur eine kurze Einleitung in unser Package sein. Eigentlich haben wir noch viel mehr Informationen. Möchtest du zum Beispiel wissen, wie du den Wert nutzt, der von den hinzugefügten Feldern gespeichert wurde? Hole dir alle Infos auf: https://github.com/inpsyde/more-menu-fields/blob/master/README.md